[clangd] fix wrong CalleeArgInfo in the hover
authorv1nh1shungry <v1nh1shungry@outlook.com>
Wed, 18 Jan 2023 14:15:28 +0000 (22:15 +0800)
committerv1nh1shungry <v1nh1shungry@outlook.com>
Fri, 10 Feb 2023 14:16:16 +0000 (22:16 +0800)
```
void foobar(int);
int main() {
  foobar(1 + 2);
           ^
}
```

Currently the CalleeArgInfo will be "Passed by reference", which should
be "Passed by value".

Fixes https://github.com/clangd/clangd/issues/1467

Differential Revision: https://reviews.llvm.org/D142014

clang-tools-extra/clangd/Hover.cpp
clang-tools-extra/clangd/unittests/HoverTests.cpp

index 8649ddc..1a51614 100644 (file)
@@ -952,6 +952,15 @@ void addLayoutInfo(const NamedDecl &ND, HoverInfo &HI) {
   }
 }
 
+HoverInfo::PassType::PassMode getPassMode(QualType ParmType) {
+  if (ParmType->isReferenceType()) {
+    if (ParmType->getPointeeType().isConstQualified())
+      return HoverInfo::PassType::ConstRef;
+    return HoverInfo::PassType::Ref;
+  }
+  return HoverInfo::PassType::Value;
+}
+
 // If N is passed as argument to a function, fill HI.CalleeArgInfo with
 // information about that argument.
 void maybeAddCalleeArgInfo(const SelectionTree::Node *N, HoverInfo &HI,
@@ -972,14 +981,19 @@ void maybeAddCalleeArgInfo(const SelectionTree::Node *N, HoverInfo &HI,
   if (!FD || FD->isOverloadedOperator() || FD->isVariadic())
     return;
 
+  HoverInfo::PassType PassType;
+
   // Find argument index for N.
   for (unsigned I = 0; I < CE->getNumArgs() && I < FD->getNumParams(); ++I) {
     if (CE->getArg(I) != OuterNode.ASTNode.get<Expr>())
       continue;
 
     // Extract matching argument from function declaration.
-    if (const ParmVarDecl *PVD = FD->getParamDecl(I))
+    if (const ParmVarDecl *PVD = FD->getParamDecl(I)) {
       HI.CalleeArgInfo.emplace(toHoverInfoParam(PVD, PP));
+      if (N == &OuterNode)
+        PassType.PassBy = getPassMode(PVD->getType());
+    }
     break;
   }
   if (!HI.CalleeArgInfo)
@@ -988,14 +1002,9 @@ void maybeAddCalleeArgInfo(const SelectionTree::Node *N, HoverInfo &HI,
   // If we found a matching argument, also figure out if it's a
   // [const-]reference. For this we need to walk up the AST from the arg itself
   // to CallExpr and check all implicit casts, constructor calls, etc.
-  HoverInfo::PassType PassType;
   if (const auto *E = N->ASTNode.get<Expr>()) {
     if (E->getType().isConstQualified())
       PassType.PassBy = HoverInfo::PassType::ConstRef;
-
-    // No implicit node, literal passed by value
-    if (isLiteral(E) && N->Parent == OuterNode.Parent)
-      PassType.PassBy = HoverInfo::PassType::Value;
   }
 
   for (auto *CastNode = N->Parent;
@@ -1067,9 +1076,8 @@ const NamedDecl *pickDeclToUse(llvm::ArrayRef<const NamedDecl *> Candidates) {
   //     template <typename T> void bar() { fo^o(T{}); }
   // we actually want to show the using declaration,
   // it's not clear which declaration to pick otherwise.
-  auto BaseDecls = llvm::make_filter_range(Candidates, [](const NamedDecl *D) {
-    return llvm::isa<UsingDecl>(D);
-  });
+  auto BaseDecls = llvm::make_filter_range(
+      Candidates, [](const NamedDecl *D) { return llvm::isa<UsingDecl>(D); });
   if (std::distance(BaseDecls.begin(), BaseDecls.end()) == 1)
     return *BaseDecls.begin();
 
index 7fbb885..211fd13 100644 (file)
@@ -900,6 +900,27 @@ class Foo final {})cpp";
          HI.CalleeArgInfo->Type = "int &";
          HI.CallPassType = HoverInfo::PassType{PassMode::Ref, false};
        }},
+      {
+          R"cpp(
+          void foobar(const float &arg);
+          int main() {
+            int a = 0;
+            foobar([[^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) {};
@@ -934,6 +955,38 @@ class Foo final {})cpp";
          HI.CalleeArgInfo->Type = "const int &";
          HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, false};
        }},
+      {
+          R"cpp(
+        int add(int lhs, int rhs);
+        int main() {
+          add(1 [[^+]] 2, 3);
+        }
+        )cpp",
+          [](HoverInfo &HI) {
+            HI.Name = "expression";
+            HI.Kind = index::SymbolKind::Unknown;
+            HI.Type = "int";
+            HI.Value = "3";
+            HI.CalleeArgInfo.emplace();
+            HI.CalleeArgInfo->Name = "lhs";
+            HI.CalleeArgInfo->Type = "int";
+            HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
+          }},
+      {
+          R"cpp(
+        void foobar(const float &arg);
+        int main() {
+          foobar([[^0]]);
+        }
+        )cpp",
+          [](HoverInfo &HI) {
+            HI.Name = "literal";
+            HI.Kind = index::SymbolKind::Unknown;
+            HI.CalleeArgInfo.emplace();
+            HI.CalleeArgInfo->Name = "arg";
+            HI.CalleeArgInfo->Type = "const float &";
+            HI.CallPassType = HoverInfo::PassType{PassMode::Value, true};
+          }},
       {// Extra info for method call.
        R"cpp(
           class C {
@@ -960,6 +1013,29 @@ class Foo final {})cpp";
          HI.CalleeArgInfo->Default = "3";
          HI.CallPassType = HoverInfo::PassType{PassMode::Value, false};
        }},
+      {
+          R"cpp(
+          struct Foo {
+            Foo(const int &);
+          };
+          void foo(Foo);
+          void bar() {
+            const int x = 0;
+            foo([[^x]]);
+          }
+       )cpp",
+          [](HoverInfo &HI) {
+            HI.Name = "x";
+            HI.Kind = index::SymbolKind::Variable;
+            HI.NamespaceScope = "";
+            HI.Definition = "const int x = 0";
+            HI.LocalScope = "bar::";
+            HI.Value = "0";
+            HI.Type = "const int";
+            HI.CalleeArgInfo.emplace();
+            HI.CalleeArgInfo->Type = "Foo";
+            HI.CallPassType = HoverInfo::PassType{PassMode::ConstRef, true};
+          }},
       {// Dont crash on invalid decl
        R"cpp(
         // error-ok
@@ -1673,8 +1749,8 @@ TEST(Hover, All) {
           }},
       {
           R"cpp(// Function definition via using declaration
-            namespace ns { 
-              void foo(); 
+            namespace ns {
+              void foo();
             }
             int main() {
               using ns::foo;