[clang-tools-extra] 13b2a0c - [clangd] Support hover on __func__ etc (PredefinedExpr)

Sam McCall via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 19 05:58:14 PDT 2022


Author: Sam McCall
Date: 2022-08-19T14:51:46+02:00
New Revision: 13b2a0c69ba69c1317308b6e5a8279160561c4b2

URL: https://github.com/llvm/llvm-project/commit/13b2a0c69ba69c1317308b6e5a8279160561c4b2
DIFF: https://github.com/llvm/llvm-project/commit/13b2a0c69ba69c1317308b6e5a8279160561c4b2.diff

LOG: [clangd] Support hover on __func__ etc (PredefinedExpr)

Expose these as variables as that's what the standard calls them (and D131175).

To make this work, we also fix a bug in SelectionTree: PredefinedExpr has
an implicit/invisible StringLiteral, and SelectionTree should not traverse
implicit things.

Reviewed By: ckandeler

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

Added: 
    

Modified: 
    clang-tools-extra/clangd/Hover.cpp
    clang-tools-extra/clangd/Selection.cpp
    clang-tools-extra/clangd/unittests/HoverTests.cpp
    clang-tools-extra/clangd/unittests/SelectionTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index f599f067d6ee..eb44d1e915af 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -32,6 +32,7 @@
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/AST/Type.h"
+#include "clang/Basic/CharInfo.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/Specifiers.h"
 #include "clang/Basic/TokenKinds.h"
@@ -640,6 +641,29 @@ HoverInfo getHoverContents(const NamedDecl *D, const PrintingPolicy &PP,
   return HI;
 }
 
+/// The standard defines __func__ as a "predefined variable".
+llvm::Optional<HoverInfo>
+getPredefinedExprHoverContents(const PredefinedExpr &PE, ASTContext &Ctx,
+                               const PrintingPolicy &PP) {
+  HoverInfo HI;
+  HI.Name = PE.getIdentKindName();
+  HI.Kind = index::SymbolKind::Variable;
+  HI.Documentation = "Name of the current function (predefined variable)";
+  if (const StringLiteral *Name = PE.getFunctionName()) {
+    HI.Value.emplace();
+    llvm::raw_string_ostream OS(*HI.Value);
+    Name->outputString(OS);
+    HI.Type = printType(Name->getType(), Ctx, PP);
+  } else {
+    // Inside templates, the approximate type `const char[]` is still useful.
+    QualType StringType = Ctx.getIncompleteArrayType(
+        Ctx.CharTy.withConst(), ArrayType::ArraySizeModifier::Normal,
+        /*IndexTypeQuals=*/0);
+    HI.Type = printType(StringType, Ctx, PP);
+  }
+  return HI;
+}
+
 /// Generate a \p Hover object given the macro \p MacroDecl.
 HoverInfo getHoverContents(const DefinedMacro &Macro, ParsedAST &AST) {
   HoverInfo HI;
@@ -764,6 +788,8 @@ llvm::Optional<HoverInfo> getHoverContents(const Expr *E, ParsedAST &AST,
   // For `this` expr we currently generate hover with pointee type.
   if (const CXXThisExpr *CTE = dyn_cast<CXXThisExpr>(E))
     return getThisExprHoverContents(CTE, AST.getASTContext(), PP);
+  if (const PredefinedExpr *PE = dyn_cast<PredefinedExpr>(E))
+    return getPredefinedExprHoverContents(*PE, AST.getASTContext(), PP);
   // For expressions we currently print the type and the value, iff it is
   // evaluatable.
   if (auto Val = printExprValue(E, AST.getASTContext())) {

diff  --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp
index e11b43047ec1..80763701d167 100644
--- a/clang-tools-extra/clangd/Selection.cpp
+++ b/clang-tools-extra/clangd/Selection.cpp
@@ -720,6 +720,14 @@ class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> {
     return Base::TraverseTypeConstraint(C);
   }
 
+  // Override child traversal for certain node types.
+  using RecursiveASTVisitor::getStmtChildren;
+  // PredefinedExpr like __func__ has a StringLiteral child for its value.
+  // It's not written, so don't traverse it.
+  Stmt::child_range getStmtChildren(PredefinedExpr *) {
+    return {StmtIterator{}, StmtIterator{}};
+  }
+
 private:
   using Base = RecursiveASTVisitor<SelectionVisitor>;
 

diff  --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 53e4f55c2e3a..997b761e6a69 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -139,6 +139,33 @@ TEST(Hover, Structured) {
          HI.Definition = "int bar";
          HI.Type = "int";
        }},
+      // Predefined variable
+      {R"cpp(
+          void foo() {
+            [[__f^unc__]];
+          }
+          )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "__func__";
+         HI.Kind = index::SymbolKind::Variable;
+         HI.Documentation =
+             "Name of the current function (predefined variable)";
+         HI.Value = "\"foo\"";
+         HI.Type = "const char[4]";
+       }},
+      // Predefined variable (dependent)
+      {R"cpp(
+          template<int> void foo() {
+            [[__f^unc__]];
+          }
+          )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "__func__";
+         HI.Kind = index::SymbolKind::Variable;
+         HI.Documentation =
+             "Name of the current function (predefined variable)";
+         HI.Type = "const char[]";
+       }},
       // Anon namespace and local scope.
       {R"cpp(
           namespace ns1 { namespace {

diff  --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
index 73d6d0d23827..f7a518f3e995 100644
--- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
@@ -527,6 +527,10 @@ TEST(SelectionTest, CommonAncestor) {
         /*error-ok*/
         void func() [[{^]])cpp",
        "CompoundStmt"},
+      {R"cpp(
+        void func() { [[__^func__]]; }
+        )cpp",
+       "PredefinedExpr"},
   };
 
   for (const Case &C : Cases) {


        


More information about the cfe-commits mailing list