diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp --- a/clang-tools-extra/clangd/AST.cpp +++ b/clang-tools-extra/clangd/AST.cpp @@ -350,8 +350,7 @@ return true; if (auto *AT = D->getType()->getContainedAutoType()) { - if (!AT->getDeducedType().isNull()) - DeducedType = AT->getDeducedType(); + DeducedType = AT->desugar(); } return true; } diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -27,6 +27,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/OperationKinds.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" @@ -550,29 +551,6 @@ return HI; } -/// Generate a \p Hover object given the type \p T. -HoverInfo getHoverContents(QualType T, ASTContext &ASTCtx, - const SymbolIndex *Index, - bool SuppressScope = false) { - HoverInfo HI; - - if (const auto *D = T->getAsTagDecl()) { - HI.Name = printName(ASTCtx, *D); - HI.Kind = index::getSymbolInfo(D).Kind; - - const auto *CommentD = getDeclForComment(D); - HI.Documentation = getDeclComment(ASTCtx, *CommentD); - enhanceFromIndex(HI, *CommentD, Index); - } else { - // Builtin types - auto Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy()); - Policy.SuppressTagKeyword = true; - Policy.SuppressScope = SuppressScope; - HI.Name = T.getAsString(Policy); - } - return HI; -} - /// Generate a \p Hover object given the macro \p MacroDecl. HoverInfo getHoverContents(const DefinedMacro &Macro, ParsedAST &AST) { HoverInfo HI; @@ -608,6 +586,54 @@ return HI; } +llvm::Optional getThisExprHoverContents(const CXXThisExpr *CTE, + ASTContext &ASTCtx, + const SymbolIndex *Index) { + QualType OriginThisType = CTE->getType()->getPointeeType(); + QualType ClassType = declaredType(OriginThisType->getAsTagDecl()); + // For partial specialization class, origin `this` pointee type will be + // parsed as `InjectedClassNameType`, which will ouput template arguments + // like "type-parameter-0-0". So we retrieve user written class type in this + // case. + QualType PrettyThisType = ASTCtx.getPointerType( + QualType(ClassType.getTypePtr(), OriginThisType.getCVRQualifiers())); + + auto Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy()); + Policy.SuppressTagKeyword = true; + Policy.SuppressScope = true; + HoverInfo HI; + HI.Name = "this"; + HI.Definition = PrettyThisType.getAsString(Policy); + return HI; +} + +/// Generate a HoverInfo object given the deduced type \p QT +HoverInfo getDeducedTypeHoverContents(QualType QT, const syntax::Token &Tok, + ASTContext &ASTCtx, + const SymbolIndex *Index) { + HoverInfo HI; + // FIXME: distinguish decltype(auto) vs decltype(expr) + HI.Name = tok::getTokenName(Tok.kind()); + HI.Kind = index::SymbolKind::TypeAlias; + + auto PP = printingPolicyForDecls(ASTCtx.getLangOpts()); + PP.SuppressTagKeyword = false; + + if (QT->isUndeducedAutoType()) { + HI.Definition = "/* not deduced */"; + } else { + HI.Definition = QT.getAsString(PP); + + if (const auto *D = QT->getAsTagDecl()) { + const auto *CommentD = getDeclForComment(D); + HI.Documentation = getDeclComment(ASTCtx, *CommentD); + enhanceFromIndex(HI, *CommentD, Index); + } + } + + return HI; +} + bool isLiteral(const Expr *E) { // Unfortunately there's no common base Literal classes inherits from // (apart from Expr), therefore these exclusions. @@ -642,16 +668,7 @@ HoverInfo HI; // For `this` expr we currently generate hover with pointee type. if (const CXXThisExpr *CTE = dyn_cast(E)) { - QualType OriginThisType = CTE->getType()->getPointeeType(); - QualType ClassType = declaredType(OriginThisType->getAsTagDecl()); - // For partial specialization class, origin `this` pointee type will be - // parsed as `InjectedClassNameType`, which will ouput template arguments - // like "type-parameter-0-0". So we retrieve user written class type in this - // case. - QualType PrettyThisType = AST.getASTContext().getPointerType( - QualType(ClassType.getTypePtr(), OriginThisType.getCVRQualifiers())); - return getHoverContents(PrettyThisType, AST.getASTContext(), Index, - /*SuppressScope=*/true); + return getThisExprHoverContents(CTE, AST.getASTContext(), Index); } // For expressions we currently print the type and the value, iff it is // evaluatable. @@ -849,10 +866,16 @@ } } else if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) { if (auto Deduced = getDeducedType(AST.getASTContext(), Tok.location())) { - HI = getHoverContents(*Deduced, AST.getASTContext(), Index); + HI = getDeducedTypeHoverContents(*Deduced, Tok, AST.getASTContext(), + Index); HighlightRange = Tok.range(SM).toCharRange(SM); break; } + + // If we can't find interesting hover information for this + // auto/decltype keyword, return nothing to avoid showing + // irrelevant or incorrect informations. + return llvm::None; } } diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -379,6 +379,30 @@ HI.Definition = "class X {}"; }}, + // auto on structured bindings + {R"cpp( + void foo() { + struct S { int x; float y; }; + [[au^to]] [x, y] = S(); + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "struct S"; + }}, + // undeduced auto + {R"cpp( + template + void foo() { + [[au^to]] x = T{}; + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "/* not deduced */"; + }}, // auto on lambda {R"cpp( void foo() { @@ -386,8 +410,9 @@ } )cpp", [](HoverInfo &HI) { - HI.Name = "(lambda)"; - HI.Kind = index::SymbolKind::Class; + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "class(lambda)"; }}, // auto on template instantiation {R"cpp( @@ -397,8 +422,9 @@ } )cpp", [](HoverInfo &HI) { - HI.Name = "Foo"; - HI.Kind = index::SymbolKind::Class; + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "class Foo"; }}, // auto on specialized template {R"cpp( @@ -409,8 +435,9 @@ } )cpp", [](HoverInfo &HI) { - HI.Name = "Foo"; - HI.Kind = index::SymbolKind::Class; + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "class Foo"; }}, // macro @@ -582,8 +609,9 @@ } )cpp", [](HoverInfo &HI) { - HI.Name = "Foo"; - HI.Kind = index::SymbolKind::Class; + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "class Foo"; }}, {// Falls back to primary template, when the type is not instantiated. R"cpp( @@ -955,20 +983,9 @@ llvm::StringRef Tests[] = { "^int main() {}", "void foo() {^}", - R"cpp(// structured binding. Not supported yet - struct Bar {}; - void foo() { - Bar a[2]; - ^auto [x,y] = a; - } - )cpp", - R"cpp(// Template auto parameter. Nothing (Not useful). - template - void func() { - } - void foo() { - func<1>(); - } + "decltype(au^to) x = 0;", + R"cpp(// Lambda auto parameter. Nothing (Not useful). + auto lamb = [](a^uto){}; )cpp", R"cpp(// non-named decls don't get hover. Don't crash! ^static_assert(1, ""); @@ -1545,9 +1562,9 @@ } )cpp", [](HoverInfo &HI) { - HI.Name = "int"; - // FIXME: Should be Builtin/Integral. - HI.Kind = index::SymbolKind::Unknown; + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int"; }}, { R"cpp(// Simple initialization with const auto @@ -1555,14 +1572,22 @@ const ^[[auto]] i = 1; } )cpp", - [](HoverInfo &HI) { HI.Name = "int"; }}, + [](HoverInfo &HI) { + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int"; + }}, { R"cpp(// Simple initialization with const auto& void foo() { const ^[[auto]]& i = 1; } )cpp", - [](HoverInfo &HI) { HI.Name = "int"; }}, + [](HoverInfo &HI) { + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int"; + }}, { R"cpp(// Simple initialization with auto& void foo() { @@ -1570,7 +1595,11 @@ ^[[auto]]& i = x; } )cpp", - [](HoverInfo &HI) { HI.Name = "int"; }}, + [](HoverInfo &HI) { + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int"; + }}, { R"cpp(// Simple initialization with auto* void foo() { @@ -1578,7 +1607,23 @@ ^[[auto]]* i = &a; } )cpp", - [](HoverInfo &HI) { HI.Name = "int"; }}, + [](HoverInfo &HI) { + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int"; + }}, + { + R"cpp(// Simple initialization with auto from pointer + void foo() { + int a = 1; + ^[[auto]] i = &a; + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int *"; + }}, { R"cpp(// Auto with initializer list. namespace std @@ -1591,8 +1636,9 @@ } )cpp", [](HoverInfo &HI) { - HI.Name = "initializer_list"; - HI.Kind = index::SymbolKind::Class; + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "class std::initializer_list"; }}, { R"cpp(// User defined conversion to auto @@ -1600,14 +1646,22 @@ operator ^[[auto]]() const { return 10; } }; )cpp", - [](HoverInfo &HI) { HI.Name = "int"; }}, + [](HoverInfo &HI) { + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int"; + }}, { R"cpp(// Simple initialization with decltype(auto) void foo() { ^[[decltype]](auto) i = 1; } )cpp", - [](HoverInfo &HI) { HI.Name = "int"; }}, + [](HoverInfo &HI) { + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int"; + }}, { R"cpp(// Simple initialization with const decltype(auto) void foo() { @@ -1615,7 +1669,11 @@ ^[[decltype]](auto) i = j; } )cpp", - [](HoverInfo &HI) { HI.Name = "const int"; }}, + [](HoverInfo &HI) { + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "const int"; + }}, { R"cpp(// Simple initialization with const& decltype(auto) void foo() { @@ -1624,7 +1682,11 @@ ^[[decltype]](auto) i = j; } )cpp", - [](HoverInfo &HI) { HI.Name = "const int &"; }}, + [](HoverInfo &HI) { + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "const int &"; + }}, { R"cpp(// Simple initialization with & decltype(auto) void foo() { @@ -1633,100 +1695,115 @@ ^[[decltype]](auto) i = j; } )cpp", - [](HoverInfo &HI) { HI.Name = "int &"; }}, + [](HoverInfo &HI) { + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int &"; + }}, { R"cpp(// simple trailing return type ^[[auto]] main() -> int { return 0; } )cpp", - [](HoverInfo &HI) { HI.Name = "int"; }}, + [](HoverInfo &HI) { + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int"; + }}, { - R"cpp(// auto function return with trailing type + R"cpp( struct Bar {}; + // auto function return with trailing type ^[[auto]] test() -> decltype(Bar()) { return Bar(); } )cpp", [](HoverInfo &HI) { - HI.Name = "Bar"; - HI.Kind = index::SymbolKind::Struct; - HI.Documentation = "auto function return with trailing type"; + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "struct Bar"; }}, { - R"cpp(// trailing return type + R"cpp( struct Bar {}; + // trailing return type auto test() -> ^[[decltype]](Bar()) { return Bar(); } )cpp", [](HoverInfo &HI) { - HI.Name = "Bar"; - HI.Kind = index::SymbolKind::Struct; - HI.Documentation = "trailing return type"; + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "struct Bar"; }}, { - R"cpp(// auto in function return + R"cpp( struct Bar {}; + // auto in function return ^[[auto]] test() { return Bar(); } )cpp", [](HoverInfo &HI) { - HI.Name = "Bar"; - HI.Kind = index::SymbolKind::Struct; - HI.Documentation = "auto in function return"; + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "struct Bar"; }}, { - R"cpp(// auto& in function return + R"cpp( struct Bar {}; + // auto& in function return ^[[auto]]& test() { static Bar x; return x; } )cpp", [](HoverInfo &HI) { - HI.Name = "Bar"; - HI.Kind = index::SymbolKind::Struct; - HI.Documentation = "auto& in function return"; + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "struct Bar"; }}, { - R"cpp(// auto* in function return + R"cpp( struct Bar {}; + // auto* in function return ^[[auto]]* test() { Bar* bar; return bar; } )cpp", [](HoverInfo &HI) { - HI.Name = "Bar"; - HI.Kind = index::SymbolKind::Struct; - HI.Documentation = "auto* in function return"; + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "struct Bar"; }}, { - R"cpp(// const auto& in function return + R"cpp( struct Bar {}; + // const auto& in function return const ^[[auto]]& test() { static Bar x; return x; } )cpp", [](HoverInfo &HI) { - HI.Name = "Bar"; - HI.Kind = index::SymbolKind::Struct; - HI.Documentation = "const auto& in function return"; + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "struct Bar"; }}, { - R"cpp(// decltype(auto) in function return + R"cpp( struct Bar {}; + // decltype(auto) in function return ^[[decltype]](auto) test() { return Bar(); } )cpp", [](HoverInfo &HI) { - HI.Name = "Bar"; - HI.Kind = index::SymbolKind::Struct; - HI.Documentation = "decltype(auto) in function return"; + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "struct Bar"; }}, { R"cpp(// decltype(auto) reference in function return @@ -1735,7 +1812,11 @@ return (a); } )cpp", - [](HoverInfo &HI) { HI.Name = "int &"; }}, + [](HoverInfo &HI) { + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int &"; + }}, { R"cpp(// decltype lvalue reference void foo() { @@ -1743,7 +1824,11 @@ ^[[decltype]](I) J = I; } )cpp", - [](HoverInfo &HI) { HI.Name = "int"; }}, + [](HoverInfo &HI) { + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int"; + }}, { R"cpp(// decltype lvalue reference void foo() { @@ -1752,7 +1837,11 @@ ^[[decltype]](K) J = I; } )cpp", - [](HoverInfo &HI) { HI.Name = "int &"; }}, + [](HoverInfo &HI) { + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int &"; + }}, { R"cpp(// decltype lvalue reference parenthesis void foo() { @@ -1760,7 +1849,11 @@ ^[[decltype]]((I)) J = I; } )cpp", - [](HoverInfo &HI) { HI.Name = "int &"; }}, + [](HoverInfo &HI) { + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int &"; + }}, { R"cpp(// decltype rvalue reference void foo() { @@ -1768,7 +1861,11 @@ ^[[decltype]](static_cast(I)) J = static_cast(I); } )cpp", - [](HoverInfo &HI) { HI.Name = "int &&"; }}, + [](HoverInfo &HI) { + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int &&"; + }}, { R"cpp(// decltype rvalue reference function call int && bar(); @@ -1777,10 +1874,15 @@ ^[[decltype]](bar()) J = bar(); } )cpp", - [](HoverInfo &HI) { HI.Name = "int &&"; }}, + [](HoverInfo &HI) { + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int &&"; + }}, { - R"cpp(// decltype of function with trailing return type. + R"cpp( struct Bar {}; + // decltype of function with trailing return type. auto test() -> decltype(Bar()) { return Bar(); } @@ -1789,10 +1891,9 @@ } )cpp", [](HoverInfo &HI) { - HI.Name = "Bar"; - HI.Kind = index::SymbolKind::Struct; - HI.Documentation = - "decltype of function with trailing return type."; + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "struct Bar"; }}, { R"cpp(// decltype of var with decltype. @@ -1802,13 +1903,33 @@ ^[[decltype]](J) K = J; } )cpp", - [](HoverInfo &HI) { HI.Name = "int"; }}, + [](HoverInfo &HI) { + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int"; + }}, + { + R"cpp(// decltype of dependent type + template + struct X { + using Y = ^[[decltype]](T::Z); + }; + )cpp", + [](HoverInfo &HI) { + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = ""; + }}, { R"cpp(// More complicated structured types. int bar(); ^[[auto]] (*foo)() = bar; )cpp", - [](HoverInfo &HI) { HI.Name = "int"; }}, + [](HoverInfo &HI) { + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int"; + }}, { R"cpp(// Should not crash when evaluating the initializer. struct Test {}; @@ -1823,32 +1944,88 @@ HI.Definition = "Test &&test = {}"; }}, { - R"cpp(// auto on alias + R"cpp( typedef int int_type; + // auto on alias ^[[auto]] x = int_type(); )cpp", - [](HoverInfo &HI) { HI.Name = "int"; }}, + [](HoverInfo &HI) { + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "int"; + }}, { - R"cpp(// auto on alias + R"cpp( struct cls {}; typedef cls cls_type; + // auto on alias ^[[auto]] y = cls_type(); )cpp", [](HoverInfo &HI) { - HI.Name = "cls"; - HI.Kind = index::SymbolKind::Struct; - HI.Documentation = "auto on alias"; + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "struct cls"; }}, { - R"cpp(// auto on alias + R"cpp( template struct templ {}; + // auto on alias ^[[auto]] z = templ(); )cpp", [](HoverInfo &HI) { - HI.Name = "templ"; - HI.Kind = index::SymbolKind::Struct; - HI.Documentation = "auto on alias"; + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "struct templ"; + }}, + { + R"cpp(// Undeduced auto declaration + template + void foo() { + ^[[auto]] x = T(); + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "/* not deduced */"; + }}, + { + R"cpp(// Undeduced auto return type + template + ^[[auto]] foo() { + return T(); + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "/* not deduced */"; + }}, + { + R"cpp(// Template auto parameter + template<[[a^uto]] T> + void func() { + } + )cpp", + [](HoverInfo &HI) { + // FIXME: not sure this is what we want, but this + // is what we currently get with getDeducedType + HI.Name = "auto"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "/* not deduced */"; + }}, + { + R"cpp(// Undeduced decltype(auto) return type + template + ^[[decltype]](auto) foo() { + return T(); + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "decltype"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "/* not deduced */"; }}, { R"cpp(// should not crash. @@ -2030,7 +2207,10 @@ }; } )cpp", - [](HoverInfo &HI) { HI.Name = "Foo *"; }}, + [](HoverInfo &HI) { + HI.Name = "this"; + HI.Definition = "Foo *"; + }}, { R"cpp(// this expr for template class namespace ns { @@ -2042,7 +2222,10 @@ }; } )cpp", - [](HoverInfo &HI) { HI.Name = "const Foo *"; }}, + [](HoverInfo &HI) { + HI.Name = "this"; + HI.Definition = "const Foo *"; + }}, { R"cpp(// this expr for specialization class namespace ns { @@ -2055,7 +2238,10 @@ }; } )cpp", - [](HoverInfo &HI) { HI.Name = "Foo *"; }}, + [](HoverInfo &HI) { + HI.Name = "this"; + HI.Definition = "Foo *"; + }}, { R"cpp(// this expr for partial specialization struct namespace ns { @@ -2068,7 +2254,10 @@ }; } )cpp", - [](HoverInfo &HI) { HI.Name = "const Foo *"; }}, + [](HoverInfo &HI) { + HI.Name = "this"; + HI.Definition = "const Foo *"; + }}, }; // Create a tiny index, so tests above can verify documentation is fetched. @@ -2119,7 +2308,7 @@ Annotations T(R"cpp( template class X {}; void foo() { - au^to t = X(); + auto t = X(); X^ w; (void)w; })cpp");