diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index d06920acc6a..5034056d997 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -14,7 +14,9 @@ #include #include #include +#include +#include #include #include @@ -219,6 +221,11 @@ public: } private: + void prepareSearch(const QString &) override + { + m_content = TextEditor::TextDocument::currentTextDocument()->plainText(); + } + Core::LocatorFilterEntry generateLocatorEntry(const DocumentSymbol &info, const Core::LocatorFilterEntry &parent) override { @@ -227,8 +234,7 @@ private: entry.displayName = ClangdClient::displayNameFromDocumentSymbol( static_cast(info.kind()), info.name(), info.detail().value_or(QString())); - const Position &pos = info.range().start(); - entry.internalData = QVariant::fromValue(Utils::LineColumn(pos.line(), pos.character())); + entry.internalData = QVariant::fromValue(info); entry.extraInfo = parent.extraInfo; if (!entry.extraInfo.isEmpty()) entry.extraInfo.append("::"); @@ -239,6 +245,66 @@ private: return entry; } + + // Filter out declarations for which a definition is also present. + QList matchesFor(QFutureInterface &future, + const QString &entry) override + { + QList allMatches + = DocumentLocatorFilter::matchesFor(future, entry); + QHash> possibleDuplicates; + for (const Core::LocatorFilterEntry &e : std::as_const(allMatches)) + possibleDuplicates[e.displayName + e.extraInfo] << e; + const QTextDocument doc(m_content); + for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) { + const QList &duplicates = it.value(); + if (duplicates.size() == 1) + continue; + QList declarations; + QList definitions; + for (const Core::LocatorFilterEntry &candidate : duplicates) { + const auto symbol = qvariant_cast(candidate.internalData); + const SymbolKind kind = static_cast(symbol.kind()); + if (kind != SymbolKind::Class && kind != SymbolKind::Function) + break; + const Range range = symbol.range(); + const Range selectionRange = symbol.selectionRange(); + if (kind == SymbolKind::Class) { + if (range.end() == selectionRange.end()) + declarations << candidate; + else + definitions << candidate; + continue; + } + const int startPos = selectionRange.end().toPositionInDocument(&doc); + const int endPos = range.end().toPositionInDocument(&doc); + const QString functionBody = m_content.mid(startPos, endPos - startPos); + + // Hacky, but I don't see anything better. + if (functionBody.contains('{') && functionBody.contains('}')) + definitions << candidate; + else + declarations << candidate; + } + if (definitions.size() == 1 + && declarations.size() + definitions.size() == duplicates.size()) { + for (const Core::LocatorFilterEntry &decl : std::as_const(declarations)) + Utils::erase(allMatches, [&decl](const Core::LocatorFilterEntry &e) { + return e.internalData == decl.internalData; + }); + } + } + + // The base implementation expects the position in the internal data. + for (Core::LocatorFilterEntry &e : allMatches) { + const Position pos = qvariant_cast(e.internalData).range().start(); + e.internalData = QVariant::fromValue(Utils::LineColumn(pos.line(), pos.character())); + } + + return allMatches; + } + + QString m_content; }; class ClangdCurrentDocumentFilter::Private diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp index 6c7c4448069..d17df20717f 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp @@ -9,7 +9,9 @@ #include #include #include +#include +#include #include using namespace CPlusPlus; @@ -100,8 +102,37 @@ QList CppCurrentDocumentFilter::matchesFor( } // entries are unsorted by design! - betterEntries += goodEntries; + + QHash> possibleDuplicates; + for (const Core::LocatorFilterEntry &e : std::as_const(betterEntries)) { + const IndexItem::Ptr info = qvariant_cast(e.internalData); + possibleDuplicates[info->scopedSymbolName() + info->symbolType()] << e; + } + for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) { + const QList &duplicates = it.value(); + if (duplicates.size() == 1) + continue; + QList declarations; + QList definitions; + for (const Core::LocatorFilterEntry &candidate : duplicates) { + const IndexItem::Ptr info = qvariant_cast(candidate.internalData); + if (info->type() != IndexItem::Function) + break; + if (info->isFunctionDefinition()) + definitions << candidate; + else + declarations << candidate; + } + if (definitions.size() == 1 + && declarations.size() + definitions.size() == duplicates.size()) { + for (const Core::LocatorFilterEntry &decl : std::as_const(declarations)) + Utils::erase(betterEntries, [&decl](const Core::LocatorFilterEntry &e) { + return e.internalData == decl.internalData; + }); + } + } + return betterEntries; } diff --git a/src/plugins/cppeditor/cpplocatorfilter_test.cpp b/src/plugins/cppeditor/cpplocatorfilter_test.cpp index 598a6e85640..5b443ad42ce 100644 --- a/src/plugins/cppeditor/cpplocatorfilter_test.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter_test.cpp @@ -319,7 +319,6 @@ void LocatorFilterTest::testCurrentDocumentFilter() ResultData("functionDeclaredOnly()", "MyClass"), ResultData("functionDefinedInClass(bool, int)", "MyClass"), ResultData("functionDefinedOutSideClass(char)", "MyClass"), - ResultData("functionDefinedOutSideClass(char)", "MyClass"), ResultData("int myVariable", "MyNamespace"), ResultData("myFunction(bool, int)", "MyNamespace"), ResultData("MyEnum", "MyNamespace"), @@ -330,9 +329,6 @@ void LocatorFilterTest::testCurrentDocumentFilter() ResultData("functionDeclaredOnly()", "MyNamespace::MyClass"), ResultData("functionDefinedInClass(bool, int)", "MyNamespace::MyClass"), ResultData("functionDefinedOutSideClass(char)", "MyNamespace::MyClass"), - ResultData("functionDefinedOutSideClassAndNamespace(float)", - "MyNamespace::MyClass"), - ResultData("functionDefinedOutSideClass(char)", "MyNamespace::MyClass"), ResultData("functionDefinedOutSideClassAndNamespace(float)", "MyNamespace::MyClass"), ResultData("int myVariable", ""), @@ -345,7 +341,6 @@ void LocatorFilterTest::testCurrentDocumentFilter() ResultData("functionDeclaredOnly()", "::MyClass"), ResultData("functionDefinedInClass(bool, int)", "::MyClass"), ResultData("functionDefinedOutSideClass(char)", "::MyClass"), - ResultData("functionDefinedOutSideClass(char)", "::MyClass"), ResultData("main()", ""), }; diff --git a/src/plugins/cppeditor/indexitem.cpp b/src/plugins/cppeditor/indexitem.cpp index 3094c9d4945..879625263e2 100644 --- a/src/plugins/cppeditor/indexitem.cpp +++ b/src/plugins/cppeditor/indexitem.cpp @@ -9,7 +9,8 @@ namespace CppEditor { IndexItem::Ptr IndexItem::create(const QString &symbolName, const QString &symbolType, const QString &symbolScope, IndexItem::ItemType type, - const QString &fileName, int line, int column, const QIcon &icon) + const QString &fileName, int line, int column, const QIcon &icon, + bool isFunctionDefinition) { Ptr ptr(new IndexItem); @@ -21,6 +22,7 @@ IndexItem::Ptr IndexItem::create(const QString &symbolName, const QString &symbo ptr->m_line = line; ptr->m_column = column; ptr->m_icon = icon; + ptr->m_isFuncDef = isFunctionDefinition; return ptr; } diff --git a/src/plugins/cppeditor/indexitem.h b/src/plugins/cppeditor/indexitem.h index eda023394df..135bd60adcd 100644 --- a/src/plugins/cppeditor/indexitem.h +++ b/src/plugins/cppeditor/indexitem.h @@ -40,7 +40,8 @@ public: const QString &fileName, int line, int column, - const QIcon &icon); + const QIcon &icon, + bool isFunctionDefinition); static Ptr create(const QString &fileName, int sizeHint); QString scopedSymbolName() const @@ -64,6 +65,7 @@ public: ItemType type() const { return m_type; } int line() const { return m_line; } int column() const { return m_column; } + bool isFunctionDefinition() const { return m_isFuncDef; } void addChild(IndexItem::Ptr childItem) { m_children.append(childItem); } void squeeze(); @@ -106,6 +108,7 @@ private: ItemType m_type = All; int m_line = 0; int m_column = 0; + bool m_isFuncDef = false; QVector m_children; }; diff --git a/src/plugins/cppeditor/searchsymbols.cpp b/src/plugins/cppeditor/searchsymbols.cpp index 22e0c281975..2aea7f8e1bf 100644 --- a/src/plugins/cppeditor/searchsymbols.cpp +++ b/src/plugins/cppeditor/searchsymbols.cpp @@ -285,7 +285,8 @@ IndexItem::Ptr SearchSymbols::addChildItem(const QString &symbolName, const QStr StringTable::insert(path), symbol->line(), symbol->column() - 1, // 1-based vs 0-based column - icon); + icon, + symbol->asFunction()); _parent->addChild(newItem); return newItem; }