diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index f59642dbf721d..558769f209860 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -981,12 +981,23 @@ void maybeAddCalleeArgInfo(const SelectionTree::Node *N, HoverInfo &HI, const auto &OuterNode = N->outerImplicit(); if (!OuterNode.Parent) return; - const auto *CE = OuterNode.Parent->ASTNode.get(); - if (!CE) + + const FunctionDecl *FD = nullptr; + llvm::ArrayRef Args; + + if (const auto *CE = OuterNode.Parent->ASTNode.get()) { + FD = CE->getDirectCallee(); + Args = {CE->getArgs(), CE->getNumArgs()}; + } else if (const auto *CE = + OuterNode.Parent->ASTNode.get()) { + FD = CE->getConstructor(); + Args = {CE->getArgs(), CE->getNumArgs()}; + } + if (!FD) return; - const FunctionDecl *FD = CE->getDirectCallee(); - // For non-function-call-like operatators (e.g. operator+, operator<<) it's - // not immediattely obvious what the "passed as" would refer to and, given + + // For non-function-call-like operators (e.g. operator+, operator<<) it's + // not immediately obvious what the "passed as" would refer to and, given // fixed function signature, the value would be very low anyway, so we choose // to not support that. // Both variadic functions and operator() (especially relevant for lambdas) @@ -999,8 +1010,8 @@ void maybeAddCalleeArgInfo(const SelectionTree::Node *N, HoverInfo &HI, auto Parameters = resolveForwardingParameters(FD); // Find argument index for N. - for (unsigned I = 0; I < CE->getNumArgs() && I < Parameters.size(); ++I) { - if (CE->getArg(I) != OuterNode.ASTNode.get()) + for (unsigned I = 0; I < Args.size() && I < Parameters.size(); ++I) { + if (Args[I] != OuterNode.ASTNode.get()) continue; // Extract matching argument from function declaration. diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 5bf089fbbfeca..ce546f54dd75f 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -956,6 +956,29 @@ class Foo final {})cpp"; HI.CalleeArgInfo->Type = "const float &"; HI.CallPassType = HoverInfo::PassType{PassMode::Value, true}; }}, + { + R"cpp( + struct Foo { + explicit Foo(const float& arg) {} + }; + int main() { + int a = 0; + Foo foo([[^a]]); + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "a"; + HI.Kind = index::SymbolKind::Variable; + HI.NamespaceScope = ""; + HI.Definition = "int a = 0"; + HI.LocalScope = "main::"; + HI.Value = "0"; + HI.Type = "int"; + HI.CalleeArgInfo.emplace(); + HI.CalleeArgInfo->Name = "arg"; + HI.CalleeArgInfo->Type = "const float &"; + HI.CallPassType = HoverInfo::PassType{PassMode::Value, true}; + }}, {// Literal passed to function call R"cpp( void fun(int arg_a, const int &arg_b) {}; @@ -1342,6 +1365,7 @@ class CustomClass { CustomClass(const Base &x) {} CustomClass(int &x) {} CustomClass(float x) {} + CustomClass(int x, int y) {} }; void int_by_ref(int &x) {} @@ -1388,6 +1412,11 @@ void fun() { {"base_by_ref([[^derived]]);", PassMode::Ref, false}, {"base_by_const_ref([[^derived]]);", PassMode::ConstRef, false}, {"base_by_value([[^derived]]);", PassMode::Value, false}, + // Custom class constructor tests + {"CustomClass c1([[^base]]);", PassMode::ConstRef, false}, + {"auto c2 = new CustomClass([[^base]]);", PassMode::ConstRef, false}, + {"CustomClass c3([[^int_x]]);", PassMode::Ref, false}, + {"CustomClass c3(int_x, [[^int_x]]);", PassMode::Value, false}, // Converted tests {"float_by_value([[^int_x]]);", PassMode::Value, true}, {"float_by_value([[^int_ref]]);", PassMode::Value, true},