diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 1d5752ca1de..b76bc58b6cc 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -477,7 +477,9 @@ static QList getAstPath(const AstNode &root, const Position &pos) static Usage::Type getUsageType(const QList &path) { bool potentialWrite = false; + bool isFunction = false; const bool symbolIsDataType = path.last().role() == "type" && path.last().kind() == "Record"; + const auto isPotentialWrite = [&] { return potentialWrite && !isFunction; }; for (auto pathIt = path.rbegin(); pathIt != path.rend(); ++pathIt) { if (pathIt->arcanaContains("non_odr_use_unevaluated")) return Usage::Type::Other; @@ -487,11 +489,24 @@ static Usage::Type getUsageType(const QList &path) return Usage::Type::Other; if (pathIt->kind() == "Switch" || pathIt->kind() == "If") return Usage::Type::Read; - if (pathIt->kind() == "Call" || pathIt->kind() == "CXXMemberCall") - return potentialWrite ? Usage::Type::WritableRef : Usage::Type::Read; + if (pathIt->kind() == "Call") + return isFunction ? Usage::Type::Other + : potentialWrite ? Usage::Type::WritableRef : Usage::Type::Read; + if (pathIt->kind() == "CXXMemberCall") { + const auto children = pathIt->children(); + if (children && children->size() == 1 + && children->first() == path.last() + && children->first().arcanaContains("bound member function")) { + return Usage::Type::Other; + } + return isPotentialWrite() ? Usage::Type::WritableRef : Usage::Type::Read; + } if ((pathIt->kind() == "DeclRef" || pathIt->kind() == "Member") && pathIt->arcanaContains("lvalue")) { - potentialWrite = true; + if (pathIt->arcanaContains(" Function ")) + isFunction = true; + else + potentialWrite = true; } if (pathIt->role() == "declaration") { if (symbolIsDataType) @@ -501,6 +516,8 @@ static Usage::Type getUsageType(const QList &path) return Usage::Type::Initialization; if (pathIt->childContainsRange(0, path.last().range())) return Usage::Type::Initialization; + if (isFunction) + return Usage::Type::Read; if (!pathIt->hasConstType()) return Usage::Type::WritableRef; return Usage::Type::Read; @@ -528,7 +545,7 @@ static Usage::Type getUsageType(const QList &path) const int lhsIndex = isBinaryOp ? 0 : 1; if (pathIt->childContainsRange(lhsIndex, path.last().range())) return Usage::Type::Write; - return potentialWrite ? Usage::Type::WritableRef : Usage::Type::Read; + return isPotentialWrite() ? Usage::Type::WritableRef : Usage::Type::Read; } return Usage::Type::Read; } diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index 93aae99ecd3..5d9f6e03589 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -284,6 +284,11 @@ void ClangdTestFindReferences::test_data() QTest::newRow("array variable") << "main.cpp" << 1134 << ItemList{ makeItem(57, 8, Usage::Type::Declaration), makeItem(58, 4, Usage::Type::Write), makeItem(59, 15, Usage::Type::Read)}; + QTest::newRow("free function") << "defs.h" << 510 << ItemList{ + makeItem(24, 5, Usage::Type::Declaration), makeItem(19, 4, Usage::Type::Other), + makeItem(25, 4, Usage::Type::Other), makeItem(60, 26, Usage::Type::Read)}; + QTest::newRow("member function") << "defs.h" << 192 << ItemList{ + makeItem(9, 12, Usage::Type::Declaration), makeItem(40, 8, Usage::Type::Other)}; } // The main point here is to test our access type categorization. diff --git a/src/plugins/clangcodemodel/test/data/find-usages/main.cpp b/src/plugins/clangcodemodel/test/data/find-usages/main.cpp index 36941dc4735..6321c421527 100644 --- a/src/plugins/clangcodemodel/test/data/find-usages/main.cpp +++ b/src/plugins/clangcodemodel/test/data/find-usages/main.cpp @@ -57,4 +57,5 @@ int main() int array[3]; array[S::value] = S::value; S::value = array[S::value]; + const auto funcPtr = &func1; }