aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp76
-rw-r--r--src/plugins/cpptools/symbolfinder.cpp119
-rw-r--r--src/tools/clangbackend/source/clangfollowsymbol.cpp9
3 files changed, 131 insertions, 73 deletions
diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp
index 8bbb010422e..7532b77e8dc 100644
--- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp
+++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp
@@ -935,6 +935,16 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_data()
"void Foo::foo(int) {}\n"
);
+ QTest::newRow("matchFunctionSignature_Follow_3.5") << _(
+ "void foo(int);\n"
+ "void @$foo() {}\n"
+ );
+
+ QTest::newRow("matchFunctionSignature_Follow_3.6") << _(
+ "void foo(int);\n"
+ "void @$foo(double) {}\n"
+ );
+
QTest::newRow("matchFunctionSignature_Follow_4") << _(
"class Foo {\n"
" void foo(int);\n"
@@ -963,17 +973,33 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_data()
"void Foo::@foo(int) {}\n"
);
- QTest::newRow("matchFunctionSignature_Follow_8") << _(
+ QTest::newRow("matchFunctionSignature_Follow_8_fuzzy") << _(
"class Foo {\n"
- " void @$foo(int *);\n"
+ " void @foo(int *);\n"
+ "};\n"
+ "void Foo::$foo(const int *) {}\n"
+ );
+
+ QTest::newRow("matchFunctionSignature_Follow_8_exact") << _(
+ "class Foo {\n"
+ " void @foo(int *);\n"
"};\n"
"void Foo::foo(const int *) {}\n"
+ "void Foo::$foo(int *) {}\n"
);
- QTest::newRow("matchFunctionSignature_Follow_9") << _(
+ QTest::newRow("matchFunctionSignature_Follow_9_fuzzy") << _(
"class Foo {\n"
- " void @$foo(int&);\n"
+ " void @foo(int&);\n"
"};\n"
+ "void Foo::$foo(const int&) {}\n"
+ );
+
+ QTest::newRow("matchFunctionSignature_Follow_9_exact") << _(
+ "class Foo {\n"
+ " void @foo(int&);\n"
+ "};\n"
+ "void Foo::$foo(int&) {}\n"
"void Foo::foo(const int&) {}\n"
);
@@ -1171,6 +1197,48 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_multipleDocuments_data()
"foo.cpp")
);
+ QTest::newRow("matchFunctionSignatureFuzzy1Forward") << (QList<TestDocumentPtr>()
+ << TestDocument::create("class Foo {\n"
+ " void @foo(int);\n"
+ " void foo();\n"
+ "};\n",
+ "foo.h")
+ << TestDocument::create("#include \"foo.h\"\n"
+ "void Foo::$foo() {}\n",
+ "foo.cpp")
+ );
+
+ QTest::newRow("matchFunctionSignatureFuzzy1Backward") << (QList<TestDocumentPtr>()
+ << TestDocument::create("class Foo {\n"
+ " void $foo(int);\n"
+ "};\n",
+ "foo.h")
+ << TestDocument::create("#include \"foo.h\"\n"
+ "void Foo::@foo() {}\n",
+ "foo.cpp")
+ );
+
+ QTest::newRow("matchFunctionSignatureFuzzy2Forward") << (QList<TestDocumentPtr>()
+ << TestDocument::create("class Foo {\n"
+ " void foo(int);\n"
+ " void @foo();\n"
+ "};\n",
+ "foo.h")
+ << TestDocument::create("#include \"foo.h\"\n"
+ "void Foo::$foo(int) {}\n",
+ "foo.cpp")
+ );
+
+ QTest::newRow("matchFunctionSignatureFuzzy2Backward") << (QList<TestDocumentPtr>()
+ << TestDocument::create("class Foo {\n"
+ " void $foo();\n"
+ "};\n",
+ "foo.h")
+ << TestDocument::create("#include \"foo.h\"\n"
+ "void Foo::@foo(int) {}\n",
+ "foo.cpp")
+ );
+
QTest::newRow("globalVar") << QList<TestDocumentPtr>{
TestDocument::create("namespace NS { extern int @globalVar; }\n", "file.h"),
TestDocument::create(
diff --git a/src/plugins/cpptools/symbolfinder.cpp b/src/plugins/cpptools/symbolfinder.cpp
index 34b81a8499a..6ee966161cd 100644
--- a/src/plugins/cpptools/symbolfinder.cpp
+++ b/src/plugins/cpptools/symbolfinder.cpp
@@ -46,21 +46,30 @@ using namespace CppTools;
namespace {
+struct Hit {
+ Hit(Function *func, bool exact) : func(func), exact(exact) {}
+ Hit() = default;
+
+ Function *func = nullptr;
+ bool exact = false;
+};
+
class FindMatchingDefinition: public SymbolVisitor
{
Symbol *_declaration = nullptr;
const OperatorNameId *_oper = nullptr;
- QList<Function *> _result;
+ const bool _strict;
+ QList<Hit> _result;
public:
- explicit FindMatchingDefinition(Symbol *declaration)
- : _declaration(declaration)
+ explicit FindMatchingDefinition(Symbol *declaration, bool strict)
+ : _declaration(declaration), _strict(strict)
{
if (_declaration->name())
_oper = _declaration->name()->asOperatorNameId();
}
- QList<Function *> result() const { return _result; }
+ const QList<Hit> result() const { return _result; }
using SymbolVisitor::visit;
@@ -69,11 +78,15 @@ public:
if (_oper) {
if (const Name *name = fun->unqualifiedName()) {
if (_oper->match(name))
- _result.append(fun);
+ _result.append({fun, true});
}
} else if (Function *decl = _declaration->type()->asFunctionType()) {
- if (fun->match(decl))
- _result.append(fun);
+ if (fun->match(decl)) {
+ _result.prepend({fun, true});
+ } else if (!_strict
+ && Matcher::match(fun->unqualifiedName(), decl->unqualifiedName())) {
+ _result.append({fun, false});
+ }
}
return false;
@@ -155,6 +168,7 @@ Function *SymbolFinder::findMatchingDefinition(Symbol *declaration,
return nullptr;
}
+ Hit best;
foreach (const QString &fileName, fileIterationOrder(declFile, snapshot)) {
Document::Ptr doc = snapshot.document(fileName);
if (!doc) {
@@ -176,76 +190,38 @@ Function *SymbolFinder::findMatchingDefinition(Symbol *declaration,
continue;
}
- FindMatchingDefinition candidates(declaration);
+ FindMatchingDefinition candidates(declaration, strict);
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) {
- if (fun->unqualifiedName()->isDestructorNameId() != declaration->unqualifiedName()->isDestructorNameId())
- continue;
+ const QList<Hit> result = candidates.result();
+ if (result.isEmpty())
+ continue;
- const QList<LookupItem> declarations = context.lookup(fun->name(), fun->enclosingScope());
- if (declarations.isEmpty())
- continue;
+ LookupContext context(doc, snapshot);
+ ClassOrNamespace *enclosingType = context.lookupType(declaration);
+ if (!enclosingType)
+ continue; // nothing to do
- const LookupItem best = declarations.first();
- if (enclosingType == context.lookupType(best.declaration()))
- viableFunctions.append(fun);
- }
+ for (const Hit &hit : result) {
+ QTC_CHECK(!strict || hit.exact);
- if (viableFunctions.isEmpty())
+ const QList<LookupItem> declarations = context.lookup(hit.func->name(),
+ hit.func->enclosingScope());
+ if (declarations.isEmpty())
continue;
-
- else if (!strict && viableFunctions.length() == 1)
- return viableFunctions.first();
-
- Function *best = nullptr;
-
- foreach (Function *fun, viableFunctions) {
- if (!(fun->unqualifiedName()
- && fun->unqualifiedName()->match(declaration->unqualifiedName()))) {
- continue;
- }
- if (fun->argumentCount() == declarationTy->argumentCount()) {
- if (!strict && !best)
- best = fun;
-
- const unsigned argc = declarationTy->argumentCount();
- unsigned argIt = 0;
- for (; argIt < argc; ++argIt) {
- Symbol *arg = fun->argumentAt(argIt);
- Symbol *otherArg = declarationTy->argumentAt(argIt);
- if (!arg->type().match(otherArg->type()))
- break;
- }
-
- if (argIt == argc
- && fun->isConst() == declaration->type().isConst()
- && fun->isVolatile() == declaration->type().isVolatile()) {
- best = fun;
- }
- }
- }
-
- if (strict && !best)
+ if (enclosingType != context.lookupType(declarations.first().declaration()))
continue;
- if (!best)
- best = viableFunctions.first();
- return best;
+ if (hit.exact)
+ return hit.func;
+
+ if (!best.func || hit.func->argumentCount() == declarationTy->argumentCount())
+ best = hit;
}
}
- return nullptr;
+ QTC_CHECK(!best.exact);
+ return strict ? nullptr : best.func;
}
Symbol *SymbolFinder::findMatchingVarDefinition(Symbol *declaration, const Snapshot &snapshot)
@@ -455,7 +431,16 @@ QList<Declaration *> SymbolFinder::findMatchingDeclaration(const LookupContext &
QList<Declaration *> nameMatch, argumentCountMatch, typeMatch;
findMatchingDeclaration(context, functionType, &typeMatch, &argumentCountMatch, &nameMatch);
result.append(typeMatch);
- result.append(argumentCountMatch);
+
+ // For member functions not defined inline, add fuzzy matches as fallbacks. We cannot do
+ // this for free functions, because there is no guarantee that there's a separate declaration.
+ QList<Declaration *> fuzzyMatches = argumentCountMatch + nameMatch;
+ if (!functionType->enclosingScope() || !functionType->enclosingScope()->isClass()) {
+ for (Declaration * const d : fuzzyMatches) {
+ if (d->enclosingScope() && d->enclosingScope()->isClass())
+ result.append(d);
+ }
+ }
return result;
}
diff --git a/src/tools/clangbackend/source/clangfollowsymbol.cpp b/src/tools/clangbackend/source/clangfollowsymbol.cpp
index 7ad610d41bd..c38d397eeb1 100644
--- a/src/tools/clangbackend/source/clangfollowsymbol.cpp
+++ b/src/tools/clangbackend/source/clangfollowsymbol.cpp
@@ -131,7 +131,11 @@ FollowSymbolResult FollowSymbol::followSymbol(CXTranslationUnit tu,
return extractMatchingTokenRange(declCursor, declCursor.spelling());
}
- return extractMatchingTokenRange(cursor.canonical(), tokenSpelling);
+ const Cursor declCursor = cursor.canonical();
+ FollowSymbolResult result;
+ result.range = extractMatchingTokenRange(declCursor, tokenSpelling);
+ result.isResultOnlyForFallBack = cursor.isFunctionLike() && declCursor == cursor;
+ return result;
}
if (!cursor.isDeclaration()) {
@@ -150,12 +154,13 @@ FollowSymbolResult FollowSymbol::followSymbol(CXTranslationUnit tu,
return result;
}
+ const bool isFunction = cursor.isFunctionLike();
cursor = cursor.definition();
// If we are able to find a definition in current TU
if (!cursor.isNull())
return extractMatchingTokenRange(cursor, tokenSpelling);
- return SourceRangeContainer();
+ return FollowSymbolResult({}, isFunction);
}
} // namespace ClangBackEnd