diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index 1f2ee33368a359b06676a314f517383127023e4c..cf4dd079401733660de30435c8e87c07a46d5ae0 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -29,6 +29,8 @@ #include "CppDocument.h" #include "FastPreprocessor.h" +#include "LookupContext.h" +#include "Overview.h" #include <Control.h> #include <TranslationUnit.h> @@ -36,8 +38,10 @@ #include <Semantic.h> #include <Literals.h> #include <Symbols.h> +#include <Names.h> #include <AST.h> #include <Scope.h> +#include <SymbolVisitor.h> #include <QtCore/QByteArray> #include <QtCore/QBitArray> @@ -570,3 +574,120 @@ void Snapshot::simplified_helper(Document::Ptr doc, Snapshot *snapshot) const } } } + +namespace { +class FindMatchingDefinition: public SymbolVisitor +{ + Symbol *_declaration; + QList<Function *> _result; + +public: + FindMatchingDefinition(Symbol *declaration) + : _declaration(declaration) {} + + QList<Function *> result() const { return _result; } + + using SymbolVisitor::visit; + + virtual bool visit(Function *fun) + { + if (_declaration->identifier()->isEqualTo(fun->identifier())) + _result.append(fun); + + return false; + } + + virtual bool visit(Block *) + { + return false; + } +}; +} // end of anonymous namespace + +Symbol *Snapshot::findMatchingDefinition(Symbol *symbol) const +{ + if (! symbol->identifier()) + return 0; + + Document::Ptr thisDocument = document(QString::fromUtf8(symbol->fileName(), symbol->fileNameLength())); + if (! thisDocument) { + qWarning() << "undefined document:" << symbol->fileName(); + return 0; + } + + LookupContext thisContext(thisDocument, *this); + const QList<Symbol *> declarationCandidates = thisContext.lookup(symbol->name(), symbol); + if (declarationCandidates.isEmpty()) { + qWarning() << "unresolved declaration:" << symbol->fileName() << symbol->line() << symbol->column(); + return 0; + } + + Symbol *declaration = declarationCandidates.first(); + Function *declarationTy = declaration->type()->asFunctionType(); + if (! declarationTy) { + qWarning() << "not a function:" << declaration->fileName() << declaration->line() << declaration->column(); + return 0; + } + + foreach (Document::Ptr doc, *this) { + if (! doc->control()->findIdentifier(declaration->identifier()->chars(), + declaration->identifier()->size())) + continue; + + FindMatchingDefinition candidates(declaration); + candidates.accept(doc->globalNamespace()); + + const QList<Function *> result = candidates.result(); + if (! result.isEmpty()) { + LookupContext context(doc, *this); + + QList<Function *> viableFunctions; + + foreach (Function *fun, result) { + const QList<Symbol *> declarations = context.lookup(fun->name(), fun); + + if (declarations.contains(declaration)) + viableFunctions.append(fun); + + else if (false) + qDebug() << "does not contain" << declaration->fileName() << declaration->line() << declaration->column(); + } + + if (viableFunctions.isEmpty()) + continue; + + else if (viableFunctions.length() == 1) + return viableFunctions.first(); + + Function *best = 0; + + foreach (Function *fun, viableFunctions) { + if (fun->identity()->isEqualTo(declaration->identity())) + continue; + + else if (fun->argumentCount() == declarationTy->argumentCount()) { + if (! best) + best = fun; + + unsigned argc = 0; + for (; argc < declarationTy->argumentCount(); ++argc) { + Symbol *arg = fun->argumentAt(argc); + Symbol *otherArg = declarationTy->argumentAt(argc); + if (! arg->type().isEqualTo(otherArg->type())) + break; + } + + if (argc == declarationTy->argumentCount()) + best = fun; + } + } + + if (! best) + best = viableFunctions.first(); + + return best; + } + } + + return 0; +} diff --git a/src/libs/cplusplus/CppDocument.h b/src/libs/cplusplus/CppDocument.h index f2cb24856d257961a5f3b6c00465a71277bb6f85..854da42a0ce1dd811f9a152933dc0c20918e27c6 100644 --- a/src/libs/cplusplus/CppDocument.h +++ b/src/libs/cplusplus/CppDocument.h @@ -364,6 +364,8 @@ public: Document::Ptr documentFromSource(const QByteArray &preprocessedCode, const QString &fileName) const; + Symbol *findMatchingDefinition(Symbol *symbol) const; + private: void simplified_helper(Document::Ptr doc, Snapshot *snapshot) const; diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 2cd4dea274f473840c2f201f6614f1e0758395ee..3951d624816ef8cdf8a6a7db8a341f51757f57db 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -46,12 +46,12 @@ using namespace CPlusPlus; -static void fullyQualifiedName(Symbol *symbol, QList<const Name *> *names) +static void fullyQualifiedName_helper(Symbol *symbol, QList<const Name *> *names) { if (! symbol) return; - fullyQualifiedName(symbol->enclosingSymbol(), names); + fullyQualifiedName_helper(symbol->enclosingSymbol(), names); if (symbol->name() && (symbol->isClass() || symbol->isNamespace())) { if (const QualifiedNameId *q = symbol->name()->asQualifiedNameId()) { @@ -119,6 +119,13 @@ LookupContext &LookupContext::operator = (const LookupContext &other) return *this; } +QList<const Name *> LookupContext::fullyQualifiedName(Symbol *symbol) +{ + QList<const Name *> names; + fullyQualifiedName_helper(symbol, &names); + return names; +} + QSharedPointer<CreateBindings> LookupContext::bindings() const { if (! _bindings) @@ -230,8 +237,7 @@ QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const if (fun->name() && fun->name()->isQualifiedNameId()) { const QualifiedNameId *q = fun->name()->asQualifiedNameId(); - QList<const Name *> path; - fullyQualifiedName(scope->owner(), &path); + QList<const Name *> path = fullyQualifiedName(scope->owner()); for (unsigned index = 0; index < q->nameCount() - 1; ++index) { // ### TODO remove me. const Name *name = q->nameAt(index); @@ -681,8 +687,7 @@ ClassOrNamespace *CreateBindings::globalNamespace() const ClassOrNamespace *CreateBindings::findClassOrNamespace(Symbol *symbol) { - QList<const Name *> names; - fullyQualifiedName(symbol, &names); + const QList<const Name *> names = LookupContext::fullyQualifiedName(symbol); if (names.isEmpty()) return _globalNamespace; diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index 4dff4c4cd361d82cfbb967a5627c3b9830f92645..04a74440469a9f6a0e68b62e314398c46cfba314 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -231,6 +231,8 @@ public: Control *control() const; // ### deprecate + static QList<const Name *> fullyQualifiedName(Symbol *symbol); + private: Control *_control; diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 454f889e23d904cd6cea8da7c9b0503bd0a15520..2d1a06d21d88993cac114becc88068b8df9fc2dd 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -1271,7 +1271,7 @@ void CPPEditor::switchDeclarationDefinition() if (declaration) openCppEditorAt(linkToSymbol(declaration)); } else if (lastSymbol->type()->isFunctionType()) { - if (Symbol *def = findDefinition(lastSymbol)) + if (Symbol *def = findDefinition(lastSymbol, snapshot)) openCppEditorAt(linkToSymbol(def)); } } @@ -1444,7 +1444,7 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, if (Symbol *symbol = result.lastVisibleSymbol()) { Symbol *def = 0; if (resolveTarget && !lastSymbol->isFunction()) - def = findDefinition(symbol); + def = findDefinition(symbol, snapshot); link = linkToSymbol(def ? def : symbol); link.begin = beginOfToken; @@ -1482,91 +1482,15 @@ void CPPEditor::jumpToDefinition() openLink(findLinkAt(textCursor())); } -Symbol *CPPEditor::findDefinition(Symbol *symbol) +Symbol *CPPEditor::findDefinition(Symbol *symbol, const Snapshot &snapshot) { if (symbol->isFunction()) return 0; // symbol is a function definition. - Function *funTy = symbol->type()->asFunctionType(); - if (! funTy) - return 0; // symbol does not have function type. + else if (! symbol->type()->isFunctionType()) + return 0; // not a function declaration - const Name *name = symbol->name(); - if (! name) - return 0; // skip anonymous functions! - - if (const QualifiedNameId *q = name->asQualifiedNameId()) - name = q->unqualifiedNameId(); - - // map from file names to function definitions. - QMap<QString, QList<Function *> > functionDefinitions; - - // find function definitions. - FindFunctionDefinitions findFunctionDefinitions; - - // save the current snapshot - const Snapshot snapshot = m_modelManager->snapshot(); - - foreach (Document::Ptr doc, snapshot) { - if (Scope *globals = doc->globalSymbols()) { - QList<Function *> *localFunctionDefinitions = - &functionDefinitions[doc->fileName()]; - - findFunctionDefinitions(name, globals, - localFunctionDefinitions); - } - } - - // a dummy document. - Document::Ptr expressionDocument = Document::create("<empty>"); - - Function *bestMatch = 0; - int bestScore = -1; - - QMapIterator<QString, QList<Function *> > it(functionDefinitions); - while (it.hasNext()) { - it.next(); - - // get the instance of the document. - Document::Ptr thisDocument = snapshot.document(it.key()); - - foreach (Function *f, it.value()) { - int score = 0; // current function's score - - const int funTyArgsCount = funTy->argumentCount(); - const int fArgsCount = f->argumentCount(); - - // max score if arguments count equals - if (funTyArgsCount == fArgsCount) - score += funTyArgsCount + 1; - else - score += (funTyArgsCount < fArgsCount) ? funTyArgsCount : fArgsCount; - - // +1 to score for every equal parameter - unsigned minCount = (funTyArgsCount < fArgsCount) ? funTyArgsCount : fArgsCount; - for (unsigned i = 0; i < minCount; ++i) - if (Symbol *funTyArg = funTy->argumentAt(i)) - if (Symbol *fArg = f->argumentAt(i)) - if (funTyArg->type().isEqualTo(fArg->type())) - score++; - - if (score > bestScore) { - // create a lookup context - const DeprecatedLookupContext context(f, expressionDocument, - thisDocument, snapshot); - - // search the matching definition for the function declaration `symbol'. - foreach (Symbol *s, context.resolve(f->name())) { - if (s == symbol) { - bestMatch = f; - bestScore = score; - } - } - } - } - } - - return bestMatch; + return snapshot.findMatchingDefinition(symbol); } unsigned CPPEditor::editorRevision() const diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index 8ab0ab0c6b3b3122d2a01ed3b6f368be1547f485..4e59ffccad4d68358293b8979abf61ceaf7b543b 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -252,7 +252,7 @@ private: CPlusPlus::Symbol *markSymbols(); bool sortedMethodOverview() const; - CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol); + CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot); virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar); TextEditor::ITextEditor *openCppEditorAt(const QString &fileName, int line,