diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2020-06-11 16:43:25 +0200 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2020-06-18 12:02:00 +0000 |
commit | a0764603d09adef7c7d561c0cbc800ab9a194467 (patch) | |
tree | 3a63455b6f76d4f8200dae4d8c56c2529faf9bb5 /src/plugins/cpptools | |
parent | e34416a966f35d1c28900948fdb9a287d7b4264a (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.cpp | 34 | ||||
-rw-r--r-- | src/plugins/cpptools/symbolfinder.cpp | 122 | ||||
-rw-r--r-- | src/plugins/cpptools/symbolfinder.h | 3 |
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); |