forked from OSchip/llvm-project
[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
This commit is contained in:
parent
3d2ea3c77f
commit
13b2a0c69b
|
@ -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())) {
|
||||
|
|
|
@ -720,6 +720,14 @@ public:
|
|||
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>;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue