aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/cpptools
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2020-06-11 16:43:25 +0200
committerChristian Kandeler <christian.kandeler@qt.io>2020-06-18 12:02:00 +0000
commita0764603d09adef7c7d561c0cbc800ab9a194467 (patch)
tree3a63455b6f76d4f8200dae4d8c56c2529faf9bb5 /src/plugins/cpptools
parente34416a966f35d1c28900948fdb9a287d7b4264a (diff)
CppTools: Also look up definitions for variables
... not just functions. This includes global variables and static members. Fixes: QTCREATORBUG-18828 Change-Id: Iee9f83a4f955a859c6fc4038c61997b30afdaec8 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/plugins/cpptools')
-rw-r--r--src/plugins/cpptools/cppfollowsymbolundercursor.cpp34
-rw-r--r--src/plugins/cpptools/symbolfinder.cpp122
-rw-r--r--src/plugins/cpptools/symbolfinder.h3
3 files changed, 142 insertions, 17 deletions
diff --git a/src/plugins/cpptools/cppfollowsymbolundercursor.cpp b/src/plugins/cpptools/cppfollowsymbolundercursor.cpp
index ded069a96e..a21babf852 100644
--- a/src/plugins/cpptools/cppfollowsymbolundercursor.cpp
+++ b/src/plugins/cpptools/cppfollowsymbolundercursor.cpp
@@ -292,9 +292,9 @@ inline LookupItem skipForwardDeclarations(const QList<LookupItem> &resolvedSymbo
return result;
}
-Link attemptFuncDeclDef(const QTextCursor &cursor, Snapshot snapshot,
- const Document::Ptr &document,
- SymbolFinder *symbolFinder)
+Link attemptDeclDef(const QTextCursor &cursor, Snapshot snapshot,
+ const Document::Ptr &document,
+ SymbolFinder *symbolFinder)
{
Link result;
QTC_ASSERT(document, return result);
@@ -333,11 +333,6 @@ Link attemptFuncDeclDef(const QTextCursor &cursor, Snapshot snapshot,
}
if (!decl || !declParent)
return result;
- if (!decl->postfix_declarator_list || !decl->postfix_declarator_list->value)
- return result;
- FunctionDeclaratorAST *funcDecl = decl->postfix_declarator_list->value->asFunctionDeclarator();
- if (!funcDecl)
- return result;
Symbol *target = nullptr;
if (FunctionDefinitionAST *funDef = declParent->asFunctionDefinition()) {
@@ -346,8 +341,14 @@ Link attemptFuncDeclDef(const QTextCursor &cursor, Snapshot snapshot,
funDef->symbol);
if (!candidates.isEmpty()) // TODO: improve disambiguation
target = candidates.first();
- } else if (declParent->asSimpleDeclaration()) {
- target = symbolFinder->findMatchingDefinition(funcDecl->symbol, snapshot);
+ } else if (const SimpleDeclarationAST * const simpleDecl = declParent->asSimpleDeclaration()) {
+ FunctionDeclaratorAST *funcDecl = nullptr;
+ if (decl->postfix_declarator_list && decl->postfix_declarator_list->value)
+ funcDecl = decl->postfix_declarator_list->value->asFunctionDeclarator();
+ if (funcDecl)
+ target = symbolFinder->findMatchingDefinition(funcDecl->symbol, snapshot);
+ else
+ target = symbolFinder->findMatchingVarDefinition(simpleDecl->symbols->value, snapshot);
}
if (target) {
@@ -514,9 +515,9 @@ void FollowSymbolUnderCursor::findLink(
int pos = tc.position();
while (document->characterAt(pos).isSpace())
++pos;
- if (document->characterAt(pos) == QLatin1Char('(')) {
- link = attemptFuncDeclDef(cursor, snapshot, documentFromSemanticInfo,
- symbolFinder);
+ const QChar ch = document->characterAt(pos);
+ if (ch == '(' || ch == ';') {
+ link = attemptDeclDef(cursor, snapshot, documentFromSemanticInfo, symbolFinder);
if (link.hasValidLinkText())
return processLinkCallback(link);
}
@@ -585,16 +586,15 @@ void FollowSymbolUnderCursor::findLink(
if (positionInBlock >= tk.utf16charsBegin() && positionInBlock <= tk.utf16charsEnd()) {
cursorRegionReached = true;
if (tk.is(T_OPERATOR)) {
- link = attemptFuncDeclDef(cursor, theSnapshot,
- documentFromSemanticInfo, symbolFinder);
+ link = attemptDeclDef(cursor, theSnapshot,
+ documentFromSemanticInfo, symbolFinder);
if (link.hasValidLinkText())
return processLinkCallback(link);
} else if (tk.isPunctuationOrOperator() && i > 0 && tokens.at(i - 1).is(T_OPERATOR)) {
QTextCursor c = cursor;
c.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor,
positionInBlock - tokens.at(i - 1).utf16charsBegin());
- link = attemptFuncDeclDef(c, theSnapshot, documentFromSemanticInfo,
- symbolFinder);
+ link = attemptDeclDef(c, theSnapshot, documentFromSemanticInfo, symbolFinder);
if (link.hasValidLinkText())
return processLinkCallback(link);
}
diff --git a/src/plugins/cpptools/symbolfinder.cpp b/src/plugins/cpptools/symbolfinder.cpp
index 1e7cf37c58..34b81a8499 100644
--- a/src/plugins/cpptools/symbolfinder.cpp
+++ b/src/plugins/cpptools/symbolfinder.cpp
@@ -36,6 +36,7 @@
#include <utils/qtcassert.h>
#include <QDebug>
+#include <QPair>
#include <algorithm>
#include <utility>
@@ -84,6 +85,46 @@ public:
}
};
+class FindMatchingVarDefinition: public SymbolVisitor
+{
+ Symbol *_declaration = nullptr;
+ QList<Declaration *> _result;
+ const Identifier *_className = nullptr;
+
+public:
+ explicit FindMatchingVarDefinition(Symbol *declaration)
+ : _declaration(declaration)
+ {
+ if (declaration->isStatic() && declaration->enclosingScope()->asClass()
+ && declaration->enclosingClass()->asClass()->name()) {
+ _className = declaration->enclosingScope()->name()->identifier();
+ }
+ }
+
+ const QList<Declaration *> result() const { return _result; }
+
+ using SymbolVisitor::visit;
+
+ bool visit(Declaration *decl) override
+ {
+ if (!decl->type()->match(_declaration->type().type()))
+ return false;
+ if (!_declaration->identifier()->equalTo(decl->identifier()))
+ return false;
+ if (_className) {
+ const QualifiedNameId * const qualName = decl->name()->asQualifiedNameId();
+ if (!qualName)
+ return false;
+ if (!qualName->base() || !qualName->base()->identifier()->equalTo(_className))
+ return false;
+ }
+ _result.append(decl);
+ return false;
+ }
+
+ bool visit(Block *) override { return false; }
+};
+
} // end of anonymous namespace
static const int kMaxCacheSize = 10;
@@ -207,6 +248,87 @@ Function *SymbolFinder::findMatchingDefinition(Symbol *declaration,
return nullptr;
}
+Symbol *SymbolFinder::findMatchingVarDefinition(Symbol *declaration, const Snapshot &snapshot)
+{
+ if (!declaration)
+ return nullptr;
+ for (const Scope *s = declaration->enclosingScope(); s; s = s->enclosingScope()) {
+ if (s->asBlock())
+ return nullptr;
+ }
+
+ QString declFile = QString::fromUtf8(declaration->fileName(), declaration->fileNameLength());
+ const Document::Ptr thisDocument = snapshot.document(declFile);
+ if (!thisDocument) {
+ qWarning() << "undefined document:" << declaration->fileName();
+ return nullptr;
+ }
+
+ using SymbolWithPriority = QPair<Symbol *, bool>;
+ QList<SymbolWithPriority> candidates;
+ QList<SymbolWithPriority> fallbacks;
+ foreach (const QString &fileName, fileIterationOrder(declFile, snapshot)) {
+ Document::Ptr doc = snapshot.document(fileName);
+ if (!doc) {
+ clearCache(declFile, fileName);
+ continue;
+ }
+
+ const Identifier *id = declaration->identifier();
+ if (id && !doc->control()->findIdentifier(id->chars(), id->size()))
+ continue;
+
+ FindMatchingVarDefinition finder(declaration);
+ finder.accept(doc->globalNamespace());
+ if (finder.result().isEmpty())
+ continue;
+
+ LookupContext context(doc, snapshot);
+ ClassOrNamespace * const enclosingType = context.lookupType(declaration);
+ for (Symbol * const symbol : finder.result()) {
+ const QList<LookupItem> items = context.lookup(symbol->name(),
+ symbol->enclosingScope());
+ bool addFallback = true;
+ for (const LookupItem &item : items) {
+ if (item.declaration() == symbol)
+ addFallback = false;
+ candidates << qMakePair(item.declaration(),
+ context.lookupType(item.declaration()) == enclosingType);
+ }
+ // TODO: This is a workaround for static member definitions not being found by
+ // the lookup() function.
+ if (addFallback)
+ fallbacks << qMakePair(symbol, context.lookupType(symbol) == enclosingType);
+ }
+ }
+
+ candidates << fallbacks;
+ SymbolWithPriority best;
+ for (const auto &candidate : qAsConst(candidates)) {
+ if (candidate.first == declaration)
+ continue;
+ if (QLatin1String(candidate.first->fileName()) == declFile
+ && candidate.first->sourceLocation() == declaration->sourceLocation())
+ continue;
+ if (!candidate.first->asDeclaration())
+ continue;
+ if (declaration->isExtern() && candidate.first->isStatic())
+ continue;
+ if (!best.first) {
+ best = candidate;
+ continue;
+ }
+ if (!best.second && candidate.second) {
+ best = candidate;
+ continue;
+ }
+ if (best.first->isExtern() && !candidate.first->isExtern())
+ best = candidate;
+ }
+
+ return best.first;
+}
+
Class *SymbolFinder::findMatchingClassDeclaration(Symbol *declaration, const Snapshot &snapshot)
{
if (!declaration->identifier())
diff --git a/src/plugins/cpptools/symbolfinder.h b/src/plugins/cpptools/symbolfinder.h
index a8cf2e6bb7..6f93138888 100644
--- a/src/plugins/cpptools/symbolfinder.h
+++ b/src/plugins/cpptools/symbolfinder.h
@@ -54,6 +54,9 @@ public:
const CPlusPlus::Snapshot &snapshot,
bool strict = false);
+ CPlusPlus::Symbol *findMatchingVarDefinition(CPlusPlus::Symbol *declaration,
+ const CPlusPlus::Snapshot &snapshot);
+
CPlusPlus::Class *findMatchingClassDeclaration(CPlusPlus::Symbol *declaration,
const CPlusPlus::Snapshot &snapshot);