diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index 0886416e48dffe223ff35fc00d1126e2b5e2e2d2..46586aa5971f543cdc40be90e20345185b8030d4 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -717,239 +717,3 @@ void Snapshot::simplified_helper(Document::Ptr doc, Snapshot *snapshot) const } } -namespace { -class FindMatchingDefinition: public SymbolVisitor -{ - Symbol *_declaration; - const OperatorNameId *_oper; - QList<Function *> _result; - -public: - FindMatchingDefinition(Symbol *declaration) - : _declaration(declaration) - , _oper(0) - { - if (_declaration->name()) - _oper = _declaration->name()->asOperatorNameId(); - } - - QList<Function *> result() const { return _result; } - - using SymbolVisitor::visit; - - virtual bool visit(Function *fun) - { - if (_oper) { - if (const Name *name = fun->unqualifiedName()) { - if (_oper->isEqualTo(name)) - _result.append(fun); - } - } else if (const Identifier *id = _declaration->identifier()) { - if (id->isEqualTo(fun->identifier())) - _result.append(fun); - } - - return false; - } - - virtual bool visit(Block *) - { - return false; - } -}; -} // end of anonymous namespace - -// strict means the returned symbol has to match exactly, -// including argument count and argument types -Symbol *Snapshot::findMatchingDefinition(Symbol *declaration, bool strict) const -{ - if (!declaration) - return 0; - - Document::Ptr thisDocument = document(QString::fromUtf8(declaration->fileName(), declaration->fileNameLength())); - if (! thisDocument) { - qWarning() << "undefined document:" << declaration->fileName(); - return 0; - } - - Function *declarationTy = declaration->type()->asFunctionType(); - if (! declarationTy) { - qWarning() << "not a function:" << declaration->fileName() << declaration->line() << declaration->column(); - return 0; - } - - foreach (Document::Ptr doc, *this) { - const Identifier *id = declaration->identifier(); - if (id && ! doc->control()->findIdentifier(id->chars(), - id->size())) - continue; - if (!id) { - if (!declaration->name()) - continue; - const OperatorNameId *oper = declaration->name()->asOperatorNameId(); - if (!oper) - continue; - if (!doc->control()->findOperatorNameId(oper->kind())) - continue; - } - - FindMatchingDefinition candidates(declaration); - candidates.accept(doc->globalNamespace()); - - const QList<Function *> result = candidates.result(); - if (! result.isEmpty()) { - LookupContext context(doc, *this); - - QList<Function *> viableFunctions; - - ClassOrNamespace *enclosingType = context.lookupType(declaration); - if (! enclosingType) - continue; // nothing to do - - foreach (Function *fun, result) { - const QList<LookupItem> declarations = context.lookup(fun->name(), fun->enclosingScope()); - if (declarations.isEmpty()) - continue; - - const LookupItem best = declarations.first(); - if (enclosingType == context.lookupType(best.declaration())) - viableFunctions.append(fun); - } - - if (viableFunctions.isEmpty()) - continue; - - else if (! strict && viableFunctions.length() == 1) - return viableFunctions.first(); - - Function *best = 0; - - foreach (Function *fun, viableFunctions) { - if (! (fun->unqualifiedName() && fun->unqualifiedName()->isEqualTo(declaration->unqualifiedName()))) - continue; - else if (fun->argumentCount() == declarationTy->argumentCount()) { - if (! strict && ! 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 (strict && ! best) - continue; - - if (! best) - best = viableFunctions.first(); - return best; - } - } - - return 0; -} - -Class *Snapshot::findMatchingClassDeclaration(Symbol *declaration) const -{ - if (! declaration->identifier()) - return 0; - - foreach (Document::Ptr doc, *this) { - if (! doc->control()->findIdentifier(declaration->identifier()->chars(), - declaration->identifier()->size())) - continue; - - LookupContext context(doc, *this); - - ClassOrNamespace *type = context.lookupType(declaration); - if (!type) - continue; - - foreach (Symbol *s, type->symbols()) { - if (Class *c = s->asClass()) - return c; - } - } - - return 0; -} - -void CPlusPlus::findMatchingDeclaration(const LookupContext &context, - Function *functionType, - QList<Declaration *> *typeMatch, - QList<Declaration *> *argumentCountMatch, - QList<Declaration *> *nameMatch) -{ - Scope *enclosingScope = functionType->enclosingScope(); - while (! (enclosingScope->isNamespace() || enclosingScope->isClass())) - enclosingScope = enclosingScope->enclosingScope(); - Q_ASSERT(enclosingScope != 0); - - const Name *functionName = functionType->name(); - if (! functionName) - return; // anonymous function names are not valid c++ - - ClassOrNamespace *binding = 0; - const QualifiedNameId *qName = functionName->asQualifiedNameId(); - if (qName) { - if (qName->base()) - binding = context.lookupType(qName->base(), enclosingScope); - else - binding = context.globalNamespace(); - functionName = qName->name(); - } - - if (!binding) { // declaration for a global function - binding = context.lookupType(enclosingScope); - - if (!binding) - return; - } - - const Identifier *funcId = functionName->identifier(); - if (!funcId) // E.g. operator, which we might be able to handle in the future... - return; - - foreach (Symbol *s, binding->symbols()) { - Scope *scope = s->asScope(); - if (!scope) - continue; - - for (Symbol *s = scope->find(funcId); s; s = s->next()) { - if (! s->name()) - continue; - else if (! funcId->isEqualTo(s->identifier())) - continue; - else if (! s->type()->isFunctionType()) - continue; - else if (Declaration *decl = s->asDeclaration()) { - if (Function *declFunTy = decl->type()->asFunctionType()) { - if (functionType->isEqualTo(declFunTy)) - typeMatch->prepend(decl); - else if (functionType->argumentCount() == declFunTy->argumentCount()) - argumentCountMatch->prepend(decl); - else - nameMatch->append(decl); - } - } - } - } -} - -QList<Declaration *> CPlusPlus::findMatchingDeclaration(const LookupContext &context, Function *functionType) -{ - QList<Declaration *> result; - QList<Declaration *> nameMatch, argumentCountMatch, typeMatch; - findMatchingDeclaration(context, functionType, &typeMatch, &argumentCountMatch, &nameMatch); - result.append(typeMatch); - result.append(argumentCountMatch); - result.append(nameMatch); - return result; -} diff --git a/src/libs/cplusplus/CppDocument.h b/src/libs/cplusplus/CppDocument.h index fdd75447774c7db4d45a8a419db132310a2204e8..33447a4969285e48f99dd119f461537f5f9d2acb 100644 --- a/src/libs/cplusplus/CppDocument.h +++ b/src/libs/cplusplus/CppDocument.h @@ -381,9 +381,6 @@ public: Document::Ptr documentFromSource(const QByteArray &preprocessedCode, const QString &fileName) const; - Symbol *findMatchingDefinition(Symbol *symbol, bool strict = false) const; - Class *findMatchingClassDeclaration(Symbol *symbol) const; - private: void simplified_helper(Document::Ptr doc, Snapshot *snapshot) const; @@ -391,15 +388,6 @@ private: _Base _documents; }; -void CPLUSPLUS_EXPORT findMatchingDeclaration( - const LookupContext &context, - Function *functionType, - QList<Declaration *> *typeMatch, - QList<Declaration *> *argumentCountMatch, - QList<Declaration *> *nameMatch); -QList<Declaration *> CPLUSPLUS_EXPORT findMatchingDeclaration( - const LookupContext &context, Function *functionType); - } // namespace CPlusPlus #endif // CPLUSPLUS_CPPDOCUMENT_H diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 5b311ed3d5bb6f95b03cc4368ad88d83956d59f8..e9d25f2e2380c5956d16d64817b324cc07d0d0b5 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -71,6 +71,7 @@ #include <cpptools/cpptoolsreuse.h> #include <cpptools/doxygengenerator.h> #include <cpptools/cpptoolssettings.h> +#include <cpptools/symbolfinder.h> #include <coreplugin/icore.h> #include <coreplugin/actionmanager/actionmanager.h> @@ -419,6 +420,7 @@ CPPEditorWidget::CPPEditorWidget(QWidget *parent) , m_firstRenameChange(false) , m_objcEnabled(false) , m_commentsSettings(CppTools::CppToolsSettings::instance()->commentsSettings()) + , m_symbolFinder(new CppTools::SymbolFinder(QString())) { m_initialized = false; qRegisterMetaType<CppEditor::Internal::SemanticInfo>("CppEditor::Internal::SemanticInfo"); @@ -862,7 +864,9 @@ void CPPEditorWidget::onContentsChanged(int position, int charsRemoved, int char } void CPPEditorWidget::updateFileName() -{ } +{ + m_symbolFinder.reset(new CppTools::SymbolFinder(file()->fileName())); +} void CPPEditorWidget::jumpToOutlineElement(int) { @@ -1076,7 +1080,7 @@ void CPPEditorWidget::switchDeclarationDefinition() openCppEditorAt(linkToSymbol(best.first())); } else if (lastVisibleSymbol && lastVisibleSymbol->isDeclaration() && lastVisibleSymbol->type()->isFunctionType()) { - if (Symbol *def = snapshot.findMatchingDefinition(lastVisibleSymbol)) + if (Symbol *def = m_symbolFinder->findMatchingDefinition(lastVisibleSymbol, snapshot)) openCppEditorAt(linkToSymbol(def)); } } @@ -1171,12 +1175,13 @@ CPPEditorWidget::Link CPPEditorWidget::attemptFuncDeclDef(const QTextCursor &cur Symbol *target = 0; if (FunctionDefinitionAST *funDef = declParent->asFunctionDefinition()) { - QList<Declaration *> candidates = findMatchingDeclaration(LookupContext(doc, snapshot), - funDef->symbol); + QList<Declaration *> candidates = + m_symbolFinder->findMatchingDeclaration(LookupContext(doc, snapshot), + funDef->symbol); if (!candidates.isEmpty()) // TODO: improve disambiguation target = candidates.first(); } else if (declParent->asSimpleDeclaration()) { - target = snapshot.findMatchingDefinition(funcDecl->symbol); + target = m_symbolFinder->findMatchingDefinition(funcDecl->symbol, snapshot); } if (target) { @@ -1426,9 +1431,8 @@ CPPEditorWidget::Link CPPEditorWidget::findLinkAt(const QTextCursor &cursor, if (def == lastVisibleSymbol) def = 0; // jump to declaration then. - if (symbol->isForwardClassDeclaration()) { - def = snapshot.findMatchingClassDeclaration(symbol); - } + if (symbol->isForwardClassDeclaration()) + def = m_symbolFinder->findMatchingClassDeclaration(symbol, snapshot); } link = linkToSymbol(def ? def : symbol); @@ -1464,7 +1468,7 @@ Symbol *CPPEditorWidget::findDefinition(Symbol *symbol, const Snapshot &snapshot else if (! symbol->type()->isFunctionType()) return 0; // not a function declaration - return snapshot.findMatchingDefinition(symbol); + return m_symbolFinder->findMatchingDefinition(symbol, snapshot); } unsigned CPPEditorWidget::editorRevision() const @@ -2254,6 +2258,11 @@ void CPPEditorWidget::applyDeclDefLinkChanges(bool jumpToMatch) updateFunctionDeclDefLink(); } +CppTools::SymbolFinder *CPPEditorWidget::symbolFinder() const +{ + return m_symbolFinder.data(); +} + void CPPEditorWidget::abortDeclDefLink() { if (!m_declDefLink) diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index 2cc792006c612a008520867ada4b12eed6be6437..eb55422bcbf4ab18e87825c2c2185d1acc2eeb3b 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -50,6 +50,7 @@ #include <QtCore/QFutureWatcher> #include <QtCore/QModelIndex> #include <QtCore/QVector> +#include <QtCore/QScopedPointer> QT_BEGIN_NAMESPACE class QComboBox; @@ -65,6 +66,7 @@ class CppModelManagerInterface; namespace CppTools { class CppCodeStyleSettings; class CppRefactoringFile; +class SymbolFinder; } namespace TextEditor { @@ -200,6 +202,8 @@ public: QSharedPointer<FunctionDeclDefLink> declDefLink() const; void applyDeclDefLinkChanges(bool jumpToMatch); + CppTools::SymbolFinder *symbolFinder() const; + Q_SIGNALS: void outlineModelIndexChanged(const QModelIndex &index); @@ -333,6 +337,7 @@ private: QSharedPointer<FunctionDeclDefLink> m_declDefLink; CppTools::CommentsSettings m_commentsSettings; + QScopedPointer<CppTools::SymbolFinder> m_symbolFinder; }; diff --git a/src/plugins/cppeditor/cppelementevaluator.cpp b/src/plugins/cppeditor/cppelementevaluator.cpp index 8e0c7bb46141b8019ee56d4c6f74075a36fc52f7..76dc4ec6eb2af0f2ce53a2fae4455c1419a03425 100644 --- a/src/plugins/cppeditor/cppelementevaluator.cpp +++ b/src/plugins/cppeditor/cppelementevaluator.cpp @@ -34,6 +34,7 @@ #include <coreplugin/ifile.h> #include <cpptools/cpptoolsreuse.h> +#include <cpptools/symbolfinder.h> #include <FullySpecifiedType.h> #include <Literals.h> @@ -184,8 +185,11 @@ void CppElementEvaluator::handleLookupItemMatch(const Snapshot &snapshot, && (declaration->asTemplate()->declaration()->isClass() || declaration->asTemplate()->declaration()->isForwardClassDeclaration()))) { if (declaration->isForwardClassDeclaration()) - if (Symbol *classDeclaration = snapshot.findMatchingClassDeclaration(declaration)) + if (Symbol *classDeclaration = + m_editor->symbolFinder()->findMatchingClassDeclaration( + declaration, snapshot)) { declaration = classDeclaration; + } CppClass *cppClass = new CppClass(declaration); if (m_lookupBaseClasses) cppClass->lookupBases(declaration, context); diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index e1dae57f518a1cf0120da3be18457d5a02632f4a..ee9bcb1fffdc5b3e29ce1c132e01606c7b77818c 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -45,6 +45,7 @@ #include <cplusplus/LookupContext.h> #include <cplusplus/Overview.h> #include <cpptools/cpprefactoringchanges.h> +#include <cpptools/symbolfinder.h> #include <texteditor/refactoroverlay.h> #include <texteditor/tooltip/tooltip.h> #include <texteditor/tooltip/tipcontents.h> @@ -165,13 +166,16 @@ static QSharedPointer<FunctionDeclDefLink> findLinkHelper(QSharedPointer<Functio Symbol *target = 0; if (FunctionDefinitionAST *funcDef = link->sourceDeclaration->asFunctionDefinition()) { QList<Declaration *> nameMatch, argumentCountMatch, typeMatch; - findMatchingDeclaration(LookupContext(link->sourceDocument, snapshot), - funcDef->symbol, - &typeMatch, &argumentCountMatch, &nameMatch); + CppTools::SymbolFinder finder(funcDef->symbol->fileName(), funcDef->symbol->fileNameLength()); + finder.findMatchingDeclaration(LookupContext(link->sourceDocument, snapshot), + funcDef->symbol, + &typeMatch, &argumentCountMatch, &nameMatch); if (!typeMatch.isEmpty()) target = typeMatch.first(); } else if (link->sourceDeclaration->asSimpleDeclaration()) { - target = snapshot.findMatchingDefinition(link->sourceFunctionDeclarator->symbol, true); + CppTools::SymbolFinder finder(link->sourceFunctionDeclarator->symbol->fileName(), + link->sourceFunctionDeclarator->symbol->fileNameLength()); + target = finder.findMatchingDefinition(link->sourceFunctionDeclarator->symbol, snapshot, true); } if (!target) { return noResult; diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 34844936e880483e2347bd367935b680dfd003b2..113583e52253228654574fc30ab1d1a32aa0bd0f 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -64,6 +64,7 @@ #include <cpptools/cpptoolsreuse.h> #include <cpptools/cppclassesfilter.h> #include <cpptools/searchsymbols.h> +#include <cpptools/symbolfinder.h> #include <extensionsystem/iplugin.h> #include <extensionsystem/pluginmanager.h> @@ -1552,7 +1553,10 @@ private: { Q_ASSERT(fwdClass != 0); - if (Class *k = assistInterface()->snapshot().findMatchingClassDeclaration(fwdClass)) { + CppTools::SymbolFinder symbolFinder(fwdClass->fileName(), fwdClass->fileNameLength()); + if (Class *k = + symbolFinder.findMatchingClassDeclaration(fwdClass, + assistInterface()->snapshot())) { const QString headerFile = QString::fromUtf8(k->fileName(), k->fileNameLength()); // collect the fwd headers diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index cbf4d3cd702561ec9773ca3edaebf2ebb54212fd..8bce1abd05d02c9e5bc16b93d2dfbcebd50b788f 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -37,7 +37,8 @@ HEADERS += completionsettingspage.h \ cppcodestylepreferences.h \ cpptoolsreuse.h \ doxygengenerator.h \ - commentssettings.h + commentssettings.h \ + symbolfinder.h SOURCES += completionsettingspage.cpp \ cppclassesfilter.cpp \ @@ -66,7 +67,8 @@ SOURCES += completionsettingspage.cpp \ cppcodestylepreferences.cpp \ cpptoolsreuse.cpp \ doxygengenerator.cpp \ - commentssettings.cpp + commentssettings.cpp \ + symbolfinder.cpp FORMS += completionsettingspage.ui \ cppfilesettingspage.ui \ diff --git a/src/plugins/cpptools/insertionpointlocator.cpp b/src/plugins/cpptools/insertionpointlocator.cpp index 855e5075a071f06e99c010d84bda4f20b97c4f7f..baecd498c1f03fdb10087866b589a0036ac1cfe7 100644 --- a/src/plugins/cpptools/insertionpointlocator.cpp +++ b/src/plugins/cpptools/insertionpointlocator.cpp @@ -33,6 +33,7 @@ #include "cpptoolsplugin.h" #include "cpprefactoringchanges.h" #include "insertionpointlocator.h" +#include "symbolfinder.h" #include <AST.h> #include <ASTVisitor.h> @@ -516,7 +517,10 @@ static InsertionLocation nextToSurroundingDefinitions(Declaration *declaration, } // find the declaration's definition - Symbol *definition = changes.snapshot().findMatchingDefinition(surroundingFunctionDecl); + CppTools::SymbolFinder symbolFinder(surroundingFunctionDecl->fileName(), + surroundingFunctionDecl->fileNameLength()); + Symbol *definition = symbolFinder.findMatchingDefinition(surroundingFunctionDecl, + changes.snapshot()); if (!definition) return noResult; @@ -555,7 +559,10 @@ QList<InsertionLocation> InsertionPointLocator::methodDefinition( if (!declaration) return result; - if (Symbol *s = m_refactoringChanges.snapshot().findMatchingDefinition(declaration, true)) { + CppTools::SymbolFinder symbolFinder(declaration->fileName(), declaration->fileNameLength()); + if (Symbol *s = symbolFinder.findMatchingDefinition(declaration, + m_refactoringChanges.snapshot(), + true)) { if (Function *f = s->asFunction()) { if (f->isConst() == declaration->type().isConst() && f->isVolatile() == declaration->type().isVolatile()) diff --git a/src/plugins/cpptools/symbolfinder.cpp b/src/plugins/cpptools/symbolfinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bb7a795817204813e5ce08ed42215a13013d27e8 --- /dev/null +++ b/src/plugins/cpptools/symbolfinder.cpp @@ -0,0 +1,338 @@ +#if defined(_MSC_VER) +#pragma warning(disable:4996) +#endif + +#include "symbolfinder.h" + +#include <Symbols.h> +#include <Names.h> +#include <Literals.h> +#include <SymbolVisitor.h> +#include <Control.h> +#include <LookupContext.h> + +#include <QtCore/QDebug> + +#include <algorithm> +#include <utility> + +using namespace CPlusPlus; +using namespace CppTools; + +namespace { + +class FindMatchingDefinition: public SymbolVisitor +{ + Symbol *_declaration; + const OperatorNameId *_oper; + QList<Function *> _result; + +public: + FindMatchingDefinition(Symbol *declaration) + : _declaration(declaration) + , _oper(0) + { + if (_declaration->name()) + _oper = _declaration->name()->asOperatorNameId(); + } + + QList<Function *> result() const { return _result; } + + using SymbolVisitor::visit; + + virtual bool visit(Function *fun) + { + if (_oper) { + if (const Name *name = fun->unqualifiedName()) { + if (_oper->isEqualTo(name)) + _result.append(fun); + } + } else if (const Identifier *id = _declaration->identifier()) { + if (id->isEqualTo(fun->identifier())) + _result.append(fun); + } + + return false; + } + + virtual bool visit(Block *) + { + return false; + } +}; + +} // end of anonymous namespace + + +SymbolFinder::SymbolFinder(const QString &referenceFileName) + : m_referenceFile(referenceFileName) +{} + +SymbolFinder::SymbolFinder(const char *referenceFileName, unsigned referenceFileLength) + : m_referenceFile(QString::fromUtf8(referenceFileName, referenceFileLength)) +{} + +// strict means the returned symbol has to match exactly, +// including argument count and argument types +Symbol *SymbolFinder::findMatchingDefinition(Symbol *declaration, + const Snapshot &snapshot, + bool strict) +{ + if (!declaration) + return 0; + + QString declFile = QString::fromUtf8(declaration->fileName(), declaration->fileNameLength()); + Q_ASSERT(declFile == m_referenceFile); + + Document::Ptr thisDocument = snapshot.document(declFile); + if (! thisDocument) { + qWarning() << "undefined document:" << declaration->fileName(); + return 0; + } + + Function *declarationTy = declaration->type()->asFunctionType(); + if (! declarationTy) { + qWarning() << "not a function:" << declaration->fileName() + << declaration->line() << declaration->column(); + return 0; + } + + foreach (const QString &fileName, fileIterationOrder(snapshot)) { + Document::Ptr doc = snapshot.document(fileName); + if (!doc) { + clear(fileName); + continue; + } + + const Identifier *id = declaration->identifier(); + if (id && ! doc->control()->findIdentifier(id->chars(), id->size())) + continue; + + if (!id) { + if (!declaration->name()) + continue; + const OperatorNameId *oper = declaration->name()->asOperatorNameId(); + if (!oper) + continue; + if (!doc->control()->findOperatorNameId(oper->kind())) + continue; + } + + FindMatchingDefinition candidates(declaration); + candidates.accept(doc->globalNamespace()); + + const QList<Function *> result = candidates.result(); + if (! result.isEmpty()) { + LookupContext context(doc, snapshot); + + QList<Function *> viableFunctions; + + ClassOrNamespace *enclosingType = context.lookupType(declaration); + if (! enclosingType) + continue; // nothing to do + + foreach (Function *fun, result) { + const QList<LookupItem> declarations = context.lookup(fun->name(), fun->enclosingScope()); + if (declarations.isEmpty()) + continue; + + const LookupItem best = declarations.first(); + if (enclosingType == context.lookupType(best.declaration())) + viableFunctions.append(fun); + } + + if (viableFunctions.isEmpty()) + continue; + + else if (! strict && viableFunctions.length() == 1) + return viableFunctions.first(); + + Function *best = 0; + + foreach (Function *fun, viableFunctions) { + if (! (fun->unqualifiedName() && fun->unqualifiedName()->isEqualTo(declaration->unqualifiedName()))) + continue; + else if (fun->argumentCount() == declarationTy->argumentCount()) { + if (! strict && ! 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 (strict && ! best) + continue; + + if (! best) + best = viableFunctions.first(); + return best; + } + } + + return 0; +} + +Class *SymbolFinder::findMatchingClassDeclaration(Symbol *declaration, const Snapshot &snapshot) +{ + if (! declaration->identifier()) + return 0; + + QString declFile = QString::fromUtf8(declaration->fileName(), declaration->fileNameLength()); + Q_ASSERT(declFile == m_referenceFile); + + foreach (const QString &file, fileIterationOrder(snapshot)) { + Document::Ptr doc = snapshot.document(file); + if (!doc) { + clear(file); + continue; + } + + if (! doc->control()->findIdentifier(declaration->identifier()->chars(), + declaration->identifier()->size())) + continue; + + LookupContext context(doc, snapshot); + + ClassOrNamespace *type = context.lookupType(declaration); + if (!type) + continue; + + foreach (Symbol *s, type->symbols()) { + if (Class *c = s->asClass()) + return c; + } + } + + return 0; +} + +void SymbolFinder::findMatchingDeclaration(const LookupContext &context, + Function *functionType, + QList<Declaration *> *typeMatch, + QList<Declaration *> *argumentCountMatch, + QList<Declaration *> *nameMatch) +{ + Scope *enclosingScope = functionType->enclosingScope(); + while (! (enclosingScope->isNamespace() || enclosingScope->isClass())) + enclosingScope = enclosingScope->enclosingScope(); + Q_ASSERT(enclosingScope != 0); + + const Name *functionName = functionType->name(); + if (! functionName) + return; // anonymous function names are not valid c++ + + ClassOrNamespace *binding = 0; + const QualifiedNameId *qName = functionName->asQualifiedNameId(); + if (qName) { + if (qName->base()) + binding = context.lookupType(qName->base(), enclosingScope); + else + binding = context.globalNamespace(); + functionName = qName->name(); + } + + if (!binding) { // declaration for a global function + binding = context.lookupType(enclosingScope); + + if (!binding) + return; + } + + const Identifier *funcId = functionName->identifier(); + if (!funcId) // E.g. operator, which we might be able to handle in the future... + return; + + foreach (Symbol *s, binding->symbols()) { + Scope *scope = s->asScope(); + if (!scope) + continue; + + for (Symbol *s = scope->find(funcId); s; s = s->next()) { + if (! s->name()) + continue; + else if (! funcId->isEqualTo(s->identifier())) + continue; + else if (! s->type()->isFunctionType()) + continue; + else if (Declaration *decl = s->asDeclaration()) { + if (Function *declFunTy = decl->type()->asFunctionType()) { + if (functionType->isEqualTo(declFunTy)) + typeMatch->prepend(decl); + else if (functionType->argumentCount() == declFunTy->argumentCount()) + argumentCountMatch->prepend(decl); + else + nameMatch->append(decl); + } + } + } + } +} + +QList<Declaration *> SymbolFinder::findMatchingDeclaration(const LookupContext &context, + Function *functionType) +{ + QList<Declaration *> result; + QList<Declaration *> nameMatch, argumentCountMatch, typeMatch; + findMatchingDeclaration(context, functionType, &typeMatch, &argumentCountMatch, &nameMatch); + result.append(typeMatch); + result.append(argumentCountMatch); + result.append(nameMatch); + return result; +} + +#include <QtCore/QThread> +QStringList SymbolFinder::fileIterationOrder(const Snapshot &snapshot) +{ + if (m_filePriorityCache.isEmpty()) { + foreach (const Document::Ptr &doc, snapshot) + insert(doc->fileName()); + } else { + checkCacheConsistency(snapshot); + } + + return m_filePriorityCache.values(); +} + +void SymbolFinder::checkCacheConsistency(const Snapshot &snapshot) +{ + // We only check for "new" files, which which are in the snapshot but not in the cache. + // The counterpart validation for "old" files is done when one tries to access the + // corresponding document and notices it's now null. + foreach (const Document::Ptr &doc, snapshot) { + if (!m_fileMetaCache.contains(doc->fileName())) + insert(doc->fileName()); + } +} + +void SymbolFinder::clear(const QString &comparingFile) +{ + m_filePriorityCache.remove(computeKey(m_referenceFile, comparingFile), comparingFile); + m_fileMetaCache.remove(comparingFile); +} + +void SymbolFinder::insert(const QString &comparingFile) +{ + // We want an ordering such that the documents with the most common path appear first. + m_filePriorityCache.insert(computeKey(m_referenceFile, comparingFile), comparingFile); + m_fileMetaCache.insert(comparingFile); +} + +int SymbolFinder::computeKey(const QString &referenceFile, const QString &comparingFile) +{ + // As similar the path from the comparing file is to the path from the reference file, + // the smaller the key is, which is then used for sorting the map. + std::pair<QString::const_iterator, + QString::const_iterator> r = std::mismatch(referenceFile.begin(), + referenceFile.end(), + comparingFile.begin()); + return referenceFile.length() - (r.first - referenceFile.begin()); +} diff --git a/src/plugins/cpptools/symbolfinder.h b/src/plugins/cpptools/symbolfinder.h new file mode 100644 index 0000000000000000000000000000000000000000..80330e98c68b5159c4724508140a2a769ce30fa6 --- /dev/null +++ b/src/plugins/cpptools/symbolfinder.h @@ -0,0 +1,55 @@ +#ifndef SYMBOLFINDER_H +#define SYMBOLFINDER_H + +#include "cpptools_global.h" + +#include <CppDocument.h> +#include <CPlusPlusForwardDeclarations.h> + +#include <QtCore/QHash> +#include <QtCore/QStringList> +#include <QtCore/QQueue> +#include <QtCore/QMultiMap> + +namespace CppTools { + +class CPPTOOLS_EXPORT SymbolFinder +{ +public: + SymbolFinder(const QString &referenceFileName); + SymbolFinder(const char *referenceFileName, unsigned referenceFileLength); + + CPlusPlus::Symbol *findMatchingDefinition(CPlusPlus::Symbol *symbol, + const CPlusPlus::Snapshot &snapshot, + bool strict = false); + + CPlusPlus::Class *findMatchingClassDeclaration(CPlusPlus::Symbol *declaration, + const CPlusPlus::Snapshot &snapshot); + + void findMatchingDeclaration(const CPlusPlus::LookupContext &context, + CPlusPlus::Function *functionType, + QList<CPlusPlus::Declaration *> *typeMatch, + QList<CPlusPlus::Declaration *> *argumentCountMatch, + QList<CPlusPlus::Declaration *> *nameMatch); + + QList<CPlusPlus::Declaration *> findMatchingDeclaration(const CPlusPlus::LookupContext &context, + CPlusPlus::Function *functionType); + +private: + QStringList fileIterationOrder(const CPlusPlus::Snapshot &snapshot); + + void checkCacheConsistency(const CPlusPlus::Snapshot &snapshot); + void clear(const QString &comparingFile); + void insert(const QString &comparingFile); + + static int computeKey(const QString &referenceFile, const QString &comparingFile); + + QMultiMap<int, QString> m_filePriorityCache; + QSet<QString> m_fileMetaCache; + QString m_referenceFile; +}; + +} // namespace CppTools + +#endif // SYMBOLFINDER_H + diff --git a/src/plugins/designer/qtcreatorintegration.cpp b/src/plugins/designer/qtcreatorintegration.cpp index e63074b8ec96cc8af556a9330b68132da6195953..c5c34c014b6aabcfb6c8f0b2d455e5f09836ef95 100644 --- a/src/plugins/designer/qtcreatorintegration.cpp +++ b/src/plugins/designer/qtcreatorintegration.cpp @@ -42,6 +42,7 @@ #include <cpptools/cpprefactoringchanges.h> #include <cpptools/cpptoolsconstants.h> #include <cpptools/insertionpointlocator.h> +#include <cpptools/symbolfinder.h> #include <cplusplus/ModelManagerInterface.h> #include <cplusplus/Symbols.h> #include <cplusplus/Overview.h> @@ -273,8 +274,9 @@ static Document::Ptr findDefinition(Function *functionDeclaration, int *line) { if (CppModelManagerInterface *cppModelManager = CppModelManagerInterface::instance()) { const Snapshot snapshot = cppModelManager->snapshot(); - - if (Symbol *def = snapshot.findMatchingDefinition(functionDeclaration)) { + CppTools::SymbolFinder symbolFinder(functionDeclaration->fileName(), + functionDeclaration->fileNameLength()); + if (Symbol *def = symbolFinder.findMatchingDefinition(functionDeclaration, snapshot)) { if (line) *line = def->line();