[clang-tools-extra] ec64d10 - [clangd] Add desugared type to hover
via cfe-commits
cfe-commits at lists.llvm.org
Tue Dec 7 21:28:49 PST 2021
Author: lh123
Date: 2021-12-08T13:28:12+08:00
New Revision: ec64d10340daacb066ab1bbf6356727062a8236f
URL: https://github.com/llvm/llvm-project/commit/ec64d10340daacb066ab1bbf6356727062a8236f
DIFF: https://github.com/llvm/llvm-project/commit/ec64d10340daacb066ab1bbf6356727062a8236f.diff
LOG: [clangd] Add desugared type to hover
Add desugared type to hover when the desugared type and the pretty-printed type are different.
```c++
template<typename T>
struct TestHover {
using Type = T;
};
int main() {
TestHover<int>::Type a;
}
```
```
variable a
Type: TestHover<int>::Type (aka int)
```
Reviewed By: sammccall
Differential Revision: https://reviews.llvm.org/D114522
Added:
Modified:
clang-tools-extra/clangd/Hover.cpp
clang-tools-extra/clangd/Hover.h
clang-tools-extra/clangd/unittests/HoverTests.cpp
clang/include/clang/AST/ASTDiagnostic.h
clang/lib/AST/ASTDiagnostic.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index 16a7d58325810..143bd4f8785ab 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -18,6 +18,7 @@
#include "support/Logger.h"
#include "support/Markup.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
@@ -46,6 +47,7 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
@@ -138,14 +140,15 @@ const char *getMarkdownLanguage(const ASTContext &Ctx) {
return LangOpts.ObjC ? "objective-c" : "cpp";
}
-std::string printType(QualType QT, const PrintingPolicy &PP) {
+HoverInfo::PrintedType printType(QualType QT, ASTContext &ASTCtx,
+ const PrintingPolicy &PP) {
// TypePrinter doesn't resolve decltypes, so resolve them here.
// FIXME: This doesn't handle composite types that contain a decltype in them.
// We should rather have a printing policy for that.
while (!QT.isNull() && QT->isDecltypeType())
QT = QT->getAs<DecltypeType>()->getUnderlyingType();
- std::string Result;
- llvm::raw_string_ostream OS(Result);
+ HoverInfo::PrintedType Result;
+ llvm::raw_string_ostream OS(Result.Type);
// Special case: if the outer type is a tag type without qualifiers, then
// include the tag for extra clarity.
// This isn't very idiomatic, so don't attempt it for complex cases, including
@@ -154,46 +157,57 @@ std::string printType(QualType QT, const PrintingPolicy &PP) {
if (auto *TT = llvm::dyn_cast<TagType>(QT.getTypePtr()))
OS << TT->getDecl()->getKindName() << " ";
}
- OS.flush();
QT.print(OS, PP);
+ OS.flush();
+ if (!QT.isNull()) {
+ bool ShouldAKA = false;
+ QualType DesugaredTy = clang::desugarForDiagnostic(ASTCtx, QT, ShouldAKA);
+ if (ShouldAKA)
+ Result.AKA = DesugaredTy.getAsString(PP);
+ }
return Result;
}
-std::string printType(const TemplateTypeParmDecl *TTP) {
- std::string Res = TTP->wasDeclaredWithTypename() ? "typename" : "class";
+HoverInfo::PrintedType printType(const TemplateTypeParmDecl *TTP) {
+ HoverInfo::PrintedType Result;
+ Result.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class";
if (TTP->isParameterPack())
- Res += "...";
- return Res;
+ Result.Type += "...";
+ return Result;
}
-std::string printType(const NonTypeTemplateParmDecl *NTTP,
- const PrintingPolicy &PP) {
- std::string Res = printType(NTTP->getType(), PP);
- if (NTTP->isParameterPack())
- Res += "...";
- return Res;
+HoverInfo::PrintedType printType(const NonTypeTemplateParmDecl *NTTP,
+ const PrintingPolicy &PP) {
+ auto PrintedType = printType(NTTP->getType(), NTTP->getASTContext(), PP);
+ if (NTTP->isParameterPack()) {
+ PrintedType.Type += "...";
+ if (PrintedType.AKA)
+ *PrintedType.AKA += "...";
+ }
+ return PrintedType;
}
-std::string printType(const TemplateTemplateParmDecl *TTP,
- const PrintingPolicy &PP) {
- std::string Res;
- llvm::raw_string_ostream OS(Res);
+HoverInfo::PrintedType printType(const TemplateTemplateParmDecl *TTP,
+ const PrintingPolicy &PP) {
+ HoverInfo::PrintedType Result;
+ llvm::raw_string_ostream OS(Result.Type);
OS << "template <";
llvm::StringRef Sep = "";
for (const Decl *Param : *TTP->getTemplateParameters()) {
OS << Sep;
Sep = ", ";
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
- OS << printType(TTP);
+ OS << printType(TTP).Type;
else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
- OS << printType(NTTP, PP);
+ OS << printType(NTTP, PP).Type;
else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param))
- OS << printType(TTPD, PP);
+ OS << printType(TTPD, PP).Type;
}
// FIXME: TemplateTemplateParameter doesn't store the info on whether this
// param was a "typename" or "class".
OS << "> class";
- return OS.str();
+ OS.flush();
+ return Result;
}
std::vector<HoverInfo::Param>
@@ -329,7 +343,7 @@ const Expr *getDefaultArg(const ParmVarDecl *PVD) {
HoverInfo::Param toHoverInfoParam(const ParmVarDecl *PVD,
const PrintingPolicy &PP) {
HoverInfo::Param Out;
- Out.Type = printType(PVD->getType(), PP);
+ Out.Type = printType(PVD->getType(), PVD->getASTContext(), PP);
if (!PVD->getName().empty())
Out.Name = PVD->getNameAsString();
if (const Expr *DefArg = getDefaultArg(PVD)) {
@@ -356,11 +370,11 @@ void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
NK == DeclarationName::CXXConversionFunctionName)
return;
- HI.ReturnType = printType(FD->getReturnType(), PP);
+ HI.ReturnType = printType(FD->getReturnType(), FD->getASTContext(), PP);
QualType QT = FD->getType();
if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) // Lambdas
QT = VD->getType().getDesugaredType(D->getASTContext());
- HI.Type = printType(QT, PP);
+ HI.Type = printType(QT, D->getASTContext(), PP);
// FIXME: handle variadics.
}
@@ -589,13 +603,19 @@ HoverInfo getHoverContents(const NamedDecl *D, const PrintingPolicy &PP,
if (const FunctionDecl *FD = getUnderlyingFunction(D))
fillFunctionTypeAndParams(HI, D, FD, PP);
else if (const auto *VD = dyn_cast<ValueDecl>(D))
- HI.Type = printType(VD->getType(), PP);
+ HI.Type = printType(VD->getType(), VD->getASTContext(), PP);
else if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D))
HI.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class";
else if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(D))
HI.Type = printType(TTP, PP);
else if (const auto *VT = dyn_cast<VarTemplateDecl>(D))
- HI.Type = printType(VT->getTemplatedDecl()->getType(), PP);
+ HI.Type =
+ printType(VT->getTemplatedDecl()->getType(), VT->getASTContext(), PP);
+ else if (const auto *TN = dyn_cast<TypedefNameDecl>(D))
+ HI.Type = printType(TN->getUnderlyingType(), TN->getASTContext(), PP);
+ else if (const auto *TAT = dyn_cast<TypeAliasTemplateDecl>(D))
+ HI.Type = printType(TAT->getTemplatedDecl()->getUnderlyingType(),
+ TAT->getASTContext(), PP);
// Fill in value with evaluated initializer if possible.
if (const auto *Var = dyn_cast<VarDecl>(D)) {
@@ -646,6 +666,16 @@ HoverInfo getHoverContents(const DefinedMacro &Macro, ParsedAST &AST) {
return HI;
}
+std::string typeAsDefinition(const HoverInfo::PrintedType &PType) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ OS << PType.Type;
+ if (PType.AKA)
+ OS << " // aka: " << *PType.AKA;
+ OS.flush();
+ return Result;
+}
+
llvm::Optional<HoverInfo> getThisExprHoverContents(const CXXThisExpr *CTE,
ASTContext &ASTCtx,
const PrintingPolicy &PP) {
@@ -660,7 +690,7 @@ llvm::Optional<HoverInfo> getThisExprHoverContents(const CXXThisExpr *CTE,
HoverInfo HI;
HI.Name = "this";
- HI.Definition = printType(PrettyThisType, PP);
+ HI.Definition = typeAsDefinition(printType(PrettyThisType, ASTCtx, PP));
return HI;
}
@@ -677,7 +707,7 @@ HoverInfo getDeducedTypeHoverContents(QualType QT, const syntax::Token &Tok,
if (QT->isUndeducedAutoType()) {
HI.Definition = "/* not deduced */";
} else {
- HI.Definition = printType(QT, PP);
+ HI.Definition = typeAsDefinition(printType(QT, ASTCtx, PP));
if (const auto *D = QT->getAsTagDecl()) {
const auto *CommentD = getDeclForComment(D);
@@ -728,7 +758,7 @@ llvm::Optional<HoverInfo> getHoverContents(const Expr *E, ParsedAST &AST,
// For expressions we currently print the type and the value, iff it is
// evaluatable.
if (auto Val = printExprValue(E, AST.getASTContext())) {
- HI.Type = printType(E->getType(), PP);
+ HI.Type = printType(E->getType(), AST.getASTContext(), PP);
HI.Value = *Val;
HI.Name = std::string(getNameForExpr(E));
return HI;
@@ -1059,24 +1089,22 @@ markup::Document HoverInfo::present() const {
// Parameters:
// - `bool param1`
// - `int param2 = 5`
- Output.addParagraph().appendText("→ ").appendCode(*ReturnType);
+ Output.addParagraph().appendText("→ ").appendCode(
+ llvm::to_string(*ReturnType));
}
if (Parameters && !Parameters->empty()) {
Output.addParagraph().appendText("Parameters: ");
markup::BulletList &L = Output.addBulletList();
- for (const auto &Param : *Parameters) {
- std::string Buffer;
- llvm::raw_string_ostream OS(Buffer);
- OS << Param;
- L.addItem().addParagraph().appendCode(std::move(OS.str()));
- }
+ for (const auto &Param : *Parameters)
+ L.addItem().addParagraph().appendCode(llvm::to_string(Param));
}
// Don't print Type after Parameters or ReturnType as this will just duplicate
// the information
if (Type && !ReturnType && !Parameters)
- Output.addParagraph().appendText("Type: ").appendCode(*Type);
+ Output.addParagraph().appendText("Type: ").appendCode(
+ llvm::to_string(*Type));
if (Value) {
markup::Paragraph &P = Output.addParagraph();
@@ -1109,7 +1137,7 @@ markup::Document HoverInfo::present() const {
if (CalleeArgInfo->Name)
OS << "as " << CalleeArgInfo->Name;
if (CallPassType->Converted && CalleeArgInfo->Type)
- OS << " (converted to " << CalleeArgInfo->Type << ")";
+ OS << " (converted to " << CalleeArgInfo->Type->Type << ")";
Output.addParagraph().appendText(OS.str());
}
@@ -1217,16 +1245,24 @@ void parseDocumentation(llvm::StringRef Input, markup::Document &Output) {
FlushParagraph();
}
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const HoverInfo::PrintedType &T) {
+ OS << T.Type;
+ if (T.AKA)
+ OS << " (aka " << *T.AKA << ")";
+ return OS;
+}
+
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
const HoverInfo::Param &P) {
- std::vector<llvm::StringRef> Output;
if (P.Type)
- Output.push_back(*P.Type);
+ OS << P.Type->Type;
if (P.Name)
- Output.push_back(*P.Name);
- OS << llvm::join(Output, " ");
+ OS << " " << *P.Name;
if (P.Default)
OS << " = " << *P.Default;
+ if (P.Type && P.Type->AKA)
+ OS << " (aka " << *P.Type->AKA << ")";
return OS;
}
diff --git a/clang-tools-extra/clangd/Hover.h b/clang-tools-extra/clangd/Hover.h
index 4e6314dfc5ed6..7478ede88a46c 100644
--- a/clang-tools-extra/clangd/Hover.h
+++ b/clang-tools-extra/clangd/Hover.h
@@ -22,15 +22,28 @@ namespace clangd {
/// embedding clients can use the structured information to provide their own
/// UI.
struct HoverInfo {
+ /// Contains pretty-printed type and desugared type
+ struct PrintedType {
+ PrintedType() = default;
+ PrintedType(const char *Type) : Type(Type) {}
+ PrintedType(const char *Type, const char *AKAType)
+ : Type(Type), AKA(AKAType) {}
+
+ /// Pretty-printed type
+ std::string Type;
+ /// Desugared type
+ llvm::Optional<std::string> AKA;
+ };
+
/// Represents parameters of a function, a template or a macro.
/// For example:
/// - void foo(ParamType Name = DefaultValue)
/// - #define FOO(Name)
/// - template <ParamType Name = DefaultType> class Foo {};
struct Param {
- /// The pretty-printed parameter type, e.g. "int", or "typename" (in
+ /// The printable parameter type, e.g. "int", or "typename" (in
/// TemplateParameters), might be None for macro parameters.
- llvm::Optional<std::string> Type;
+ llvm::Optional<PrintedType> Type;
/// None for unnamed parameters.
llvm::Optional<std::string> Name;
/// None if no default is provided.
@@ -62,11 +75,11 @@ struct HoverInfo {
/// Access specifier for declarations inside class/struct/unions, empty for
/// others.
std::string AccessSpecifier;
- /// Pretty-printed variable type.
+ /// Printable variable type.
/// Set only for variables.
- llvm::Optional<std::string> Type;
+ llvm::Optional<PrintedType> Type;
/// Set for functions and lambdas.
- llvm::Optional<std::string> ReturnType;
+ llvm::Optional<PrintedType> ReturnType;
/// Set for functions, lambdas and macros with parameters.
llvm::Optional<std::vector<Param>> Parameters;
/// Set for all templates(function, class, variable).
@@ -98,6 +111,11 @@ struct HoverInfo {
markup::Document present() const;
};
+inline bool operator==(const HoverInfo::PrintedType &LHS,
+ const HoverInfo::PrintedType &RHS) {
+ return std::tie(LHS.Type, LHS.AKA) == std::tie(RHS.Type, RHS.AKA);
+}
+
inline bool operator==(const HoverInfo::PassType &LHS,
const HoverInfo::PassType &RHS) {
return std::tie(LHS.PassBy, LHS.Converted) ==
@@ -108,6 +126,8 @@ inline bool operator==(const HoverInfo::PassType &LHS,
// FIXME: move to another file so CodeComplete doesn't depend on Hover.
void parseDocumentation(llvm::StringRef Input, markup::Document &Output);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+ const HoverInfo::PrintedType &);
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const HoverInfo::Param &);
inline bool operator==(const HoverInfo::Param &LHS,
const HoverInfo::Param &RHS) {
diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 5376750b25b49..0d7c227f04711 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -211,12 +211,13 @@ TEST(Hover, Structured) {
bool Q = false, class... Ts>
class Foo {})cpp";
HI.TemplateParameters = {
- {std::string("template <typename, bool...> class"),
- std::string("C"), llvm::None},
- {std::string("typename"), llvm::None, std::string("char")},
- {std::string("int"), llvm::None, std::string("0")},
- {std::string("bool"), std::string("Q"), std::string("false")},
- {std::string("class..."), std::string("Ts"), llvm::None},
+ {{"template <typename, bool...> class"},
+ std::string("C"),
+ llvm::None},
+ {{"typename"}, llvm::None, std::string("char")},
+ {{"int"}, llvm::None, std::string("0")},
+ {{"bool"}, std::string("Q"), std::string("false")},
+ {{"class..."}, std::string("Ts"), llvm::None},
};
}},
// Function template
@@ -258,8 +259,8 @@ class Foo {})cpp";
HI.ReturnType = "Foo<bool, true, false>";
HI.Type = "Foo<bool, true, false> (int, bool)";
HI.Parameters = {
- {std::string("int"), llvm::None, llvm::None},
- {std::string("bool"), std::string("T"), std::string("false")},
+ {{"int"}, llvm::None, llvm::None},
+ {{"bool"}, std::string("T"), std::string("false")},
};
}},
// Pointers to lambdas
@@ -279,8 +280,8 @@ class Foo {})cpp";
HI.Type = "(lambda) **";
HI.ReturnType = "bool";
HI.Parameters = {
- {std::string("int"), std::string("T"), llvm::None},
- {std::string("bool"), std::string("B"), llvm::None},
+ {{"int"}, std::string("T"), llvm::None},
+ {{"bool"}, std::string("B"), llvm::None},
};
return HI;
}},
@@ -297,11 +298,11 @@ class Foo {})cpp";
HI.Name = "bar";
HI.Kind = index::SymbolKind::Parameter;
HI.Definition = "decltype(lamb) &bar";
- HI.Type = "decltype(lamb) &";
+ HI.Type = {"decltype(lamb) &", "(lambda) &"};
HI.ReturnType = "bool";
HI.Parameters = {
- {std::string("int"), std::string("T"), llvm::None},
- {std::string("bool"), std::string("B"), llvm::None},
+ {{"int"}, std::string("T"), llvm::None},
+ {{"bool"}, std::string("B"), llvm::None},
};
return HI;
}},
@@ -321,8 +322,8 @@ class Foo {})cpp";
HI.Type = "class (lambda)";
HI.ReturnType = "bool";
HI.Parameters = {
- {std::string("int"), std::string("T"), llvm::None},
- {std::string("bool"), std::string("B"), llvm::None},
+ {{"int"}, std::string("T"), llvm::None},
+ {{"bool"}, std::string("B"), llvm::None},
};
HI.Value = "false";
return HI;
@@ -344,8 +345,8 @@ class Foo {})cpp";
HI.Type = "class (lambda)";
HI.ReturnType = "bool";
HI.Parameters = {
- {std::string("int"), std::string("T"), llvm::None},
- {std::string("bool"), std::string("B"), llvm::None},
+ {{"int"}, std::string("T"), llvm::None},
+ {{"bool"}, std::string("B"), llvm::None},
};
return HI;
}},
@@ -569,15 +570,16 @@ class Foo {})cpp";
HI.AccessSpecifier = "public";
}},
{R"cpp(
- constexpr int answer() { return 40 + 2; }
+ using my_int = int;
+ constexpr my_int answer() { return 40 + 2; }
int x = [[ans^wer]]();
)cpp",
[](HoverInfo &HI) {
HI.Name = "answer";
- HI.Definition = "constexpr int answer()";
+ HI.Definition = "constexpr my_int answer()";
HI.Kind = index::SymbolKind::Function;
- HI.Type = "int ()";
- HI.ReturnType = "int";
+ HI.Type = {"my_int ()", "int ()"};
+ HI.ReturnType = {"my_int", "int"};
HI.Parameters.emplace();
HI.NamespaceScope = "";
HI.Value = "42 (0x2a)";
@@ -930,6 +932,71 @@ class Foo {})cpp";
HI.Type = "m_int[4]";
HI.NamespaceScope = "";
HI.Definition = "m_int arr[4]";
+ }},
+ {// Canonical type
+ R"cpp(
+ template<typename T>
+ struct TestHover {
+ using Type = T;
+ };
+
+ void code() {
+ TestHover<int>::Type ^[[a]];
+ }
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "a";
+ HI.NamespaceScope = "";
+ HI.LocalScope = "code::";
+ HI.Definition = "TestHover<int>::Type a";
+ HI.Kind = index::SymbolKind::Variable;
+ HI.Type = {"TestHover<int>::Type", "int"};
+ }},
+ {// Canonical template type
+ R"cpp(
+ template<typename T>
+ void ^[[foo]](T arg) {}
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "foo";
+ HI.Kind = index::SymbolKind::Function;
+ HI.NamespaceScope = "";
+ HI.Definition = "template <typename T> void foo(T arg)";
+ HI.Type = "void (T)";
+ HI.ReturnType = "void";
+ HI.Parameters = {{{"T"}, std::string("arg"), llvm::None}};
+ HI.TemplateParameters = {{{"typename"}, std::string("T"), llvm::None}};
+ }},
+ {// TypeAlias Template
+ R"cpp(
+ template<typename T>
+ using ^[[alias]] = T;
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "alias";
+ HI.NamespaceScope = "";
+ HI.LocalScope = "";
+ HI.Kind = index::SymbolKind::TypeAlias;
+ HI.Definition = "template <typename T> using alias = T";
+ HI.Type = "T";
+ HI.TemplateParameters = {{{"typename"}, std::string("T"), llvm::None}};
+ }},
+ {// TypeAlias Template
+ R"cpp(
+ template<typename T>
+ using A = T;
+
+ template<typename T>
+ using ^[[AA]] = A<T>;
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "AA";
+ HI.NamespaceScope = "";
+ HI.LocalScope = "";
+ HI.Kind = index::SymbolKind::TypeAlias;
+ HI.Definition = "template <typename T> using AA = A<T>";
+ HI.Type = {"A<T>", "type-parameter-0-0"}; // FIXME: should be 'T'
+ HI.TemplateParameters = {{{"typename"}, std::string("T"), llvm::None}};
}}};
for (const auto &Case : Cases) {
SCOPED_TRACE(Case.Code);
@@ -1227,7 +1294,7 @@ TEST(Hover, All) {
HI.Documentation = "Function definition via pointer";
HI.ReturnType = "void";
HI.Parameters = {
- {std::string("int"), llvm::None, llvm::None},
+ {{"int"}, llvm::None, llvm::None},
};
}},
{
@@ -1246,7 +1313,7 @@ TEST(Hover, All) {
HI.Documentation = "Function declaration via call";
HI.ReturnType = "int";
HI.Parameters = {
- {std::string("int"), llvm::None, llvm::None},
+ {{"int"}, llvm::None, llvm::None},
};
}},
{
@@ -1390,8 +1457,8 @@ TEST(Hover, All) {
HI.Kind = index::SymbolKind::TypeAlias;
HI.NamespaceScope = "";
HI.Definition = "typedef int Foo";
+ HI.Type = "int";
HI.Documentation = "Typedef";
- // FIXME: Maybe put underlying type into HI.Type for aliases?
}},
{
R"cpp(// Typedef with embedded definition
@@ -1405,6 +1472,7 @@ TEST(Hover, All) {
HI.Kind = index::SymbolKind::TypeAlias;
HI.NamespaceScope = "";
HI.Definition = "typedef struct Bar Foo";
+ HI.Type = "struct Bar";
HI.Documentation = "Typedef with embedded definition";
}},
{
@@ -2053,7 +2121,7 @@ TEST(Hover, All) {
[](HoverInfo &HI) {
HI.Name = "auto";
HI.Kind = index::SymbolKind::TypeAlias;
- HI.Definition = "int_type";
+ HI.Definition = "int_type // aka: int";
}},
{
R"cpp(// auto on alias
@@ -2064,7 +2132,7 @@ TEST(Hover, All) {
[](HoverInfo &HI) {
HI.Name = "auto";
HI.Kind = index::SymbolKind::TypeAlias;
- HI.Definition = "cls_type";
+ HI.Definition = "cls_type // aka: cls";
HI.Documentation = "auto on alias";
}},
{
@@ -2215,10 +2283,10 @@ TEST(Hover, All) {
HI.Name = "foo";
// FIXME: Handle composite types with decltype with a printing
// policy.
- HI.Type = "auto (decltype(a)) -> decltype(a)";
+ HI.Type = {"auto (decltype(a)) -> decltype(a)",
+ "auto (int) -> int"};
HI.ReturnType = "int";
- HI.Parameters = {
- {std::string("int"), std::string("x"), llvm::None}};
+ HI.Parameters = {{{"int"}, std::string("x"), llvm::None}};
}},
{
R"cpp(// sizeof expr
@@ -2251,8 +2319,7 @@ TEST(Hover, All) {
HI.Kind = index::SymbolKind::Function;
HI.Type = "void (const int &)";
HI.ReturnType = "void";
- HI.Parameters = {
- {std::string("const int &"), llvm::None, std::string("T()")}};
+ HI.Parameters = {{{"const int &"}, llvm::None, std::string("T()")}};
HI.Definition = "template <> void foo<int>(const int &)";
HI.NamespaceScope = "";
}},
@@ -2609,9 +2676,8 @@ TEST(Hover, Present) {
HI.Kind = index::SymbolKind::Class;
HI.Size = 10;
HI.TemplateParameters = {
- {std::string("typename"), std::string("T"), llvm::None},
- {std::string("typename"), std::string("C"),
- std::string("bool")},
+ {{"typename"}, std::string("T"), llvm::None},
+ {{"typename"}, std::string("C"), std::string("bool")},
};
HI.Documentation = "documentation";
HI.Definition =
@@ -2630,12 +2696,12 @@ template <typename T, typename C = bool> class Foo {})",
[](HoverInfo &HI) {
HI.Kind = index::SymbolKind::Function;
HI.Name = "foo";
- HI.Type = "type";
- HI.ReturnType = "ret_type";
+ HI.Type = {"type", "c_type"};
+ HI.ReturnType = {"ret_type", "can_ret_type"};
HI.Parameters.emplace();
HoverInfo::Param P;
HI.Parameters->push_back(P);
- P.Type = "type";
+ P.Type = {"type", "can_type"};
HI.Parameters->push_back(P);
P.Name = "foo";
HI.Parameters->push_back(P);
@@ -2646,12 +2712,12 @@ template <typename T, typename C = bool> class Foo {})",
},
"function foo\n"
"\n"
- "→ ret_type\n"
+ "→ ret_type (aka can_ret_type)\n"
"Parameters:\n"
"- \n"
- "- type\n"
- "- type foo\n"
- "- type foo = default\n"
+ "- type (aka can_type)\n"
+ "- type foo (aka can_type)\n"
+ "- type foo = default (aka can_type)\n"
"\n"
"// In namespace ns\n"
"ret_type foo(params) {}",
@@ -2662,7 +2728,7 @@ template <typename T, typename C = bool> class Foo {})",
HI.LocalScope = "test::Bar::";
HI.Value = "value";
HI.Name = "foo";
- HI.Type = "type";
+ HI.Type = {"type", "can_type"};
HI.Definition = "def";
HI.Size = 4;
HI.Offset = 12;
@@ -2670,7 +2736,7 @@ template <typename T, typename C = bool> class Foo {})",
},
R"(field foo
-Type: type
+Type: type (aka can_type)
Value = value
Offset: 12 bytes
Size: 4 bytes (+4 padding)
@@ -2693,22 +2759,22 @@ public: def)",
},
{
[](HoverInfo &HI) {
- HI.Definition = "int method()";
+ HI.Definition = "size_t method()";
HI.AccessSpecifier = "protected";
HI.Kind = index::SymbolKind::InstanceMethod;
HI.NamespaceScope = "";
HI.LocalScope = "cls<int>::";
HI.Name = "method";
HI.Parameters.emplace();
- HI.ReturnType = "int";
- HI.Type = "int ()";
+ HI.ReturnType = {"size_t", "unsigned long"};
+ HI.Type = {"size_t ()", "unsigned long ()"};
},
R"(instance-method method
-→ int
+→ size_t (aka unsigned long)
// In cls<int>
-protected: int method())",
+protected: size_t method())",
},
{
[](HoverInfo &HI) {
@@ -2809,7 +2875,7 @@ int foo = 3)",
HI.Type = "int";
HI.CalleeArgInfo.emplace();
HI.CalleeArgInfo->Name = "arg_a";
- HI.CalleeArgInfo->Type = "int";
+ HI.CalleeArgInfo->Type = {"alias_int", "int"};
HI.CalleeArgInfo->Default = "7";
HI.CallPassType.emplace();
HI.CallPassType->PassBy = PassMode::Value;
@@ -2819,7 +2885,7 @@ int foo = 3)",
Type: int
Value = 3
-Passed as arg_a (converted to int)
+Passed as arg_a (converted to alias_int)
// In test::Bar
int foo = 3)",
diff --git a/clang/include/clang/AST/ASTDiagnostic.h b/clang/include/clang/AST/ASTDiagnostic.h
index d6549e12d92ac..4cd9097517258 100644
--- a/clang/include/clang/AST/ASTDiagnostic.h
+++ b/clang/include/clang/AST/ASTDiagnostic.h
@@ -9,6 +9,7 @@
#ifndef LLVM_CLANG_AST_ASTDIAGNOSTIC_H
#define LLVM_CLANG_AST_ASTDIAGNOSTIC_H
+#include "clang/AST/Type.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticAST.h"
@@ -31,6 +32,11 @@ namespace clang {
SmallVectorImpl<char> &Output,
void *Cookie,
ArrayRef<intptr_t> QualTypeVals);
+
+ /// Returns a desugared version of the QualType, and marks ShouldAKA as true
+ /// whenever we remove significant sugar from the type.
+ QualType desugarForDiagnostic(ASTContext &Context, QualType QT,
+ bool &ShouldAKA);
} // end namespace clang
#endif
diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp
index 7e435e8b35b80..e1b517db28ac9 100644
--- a/clang/lib/AST/ASTDiagnostic.cpp
+++ b/clang/lib/AST/ASTDiagnostic.cpp
@@ -26,7 +26,8 @@ using namespace clang;
// Returns a desugared version of the QualType, and marks ShouldAKA as true
// whenever we remove significant sugar from the type.
-static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
+QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
+ bool &ShouldAKA) {
QualifierCollector QC;
while (true) {
@@ -76,7 +77,7 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
if (const FunctionType *FT = dyn_cast<FunctionType>(Ty)) {
bool DesugarReturn = false;
QualType SugarRT = FT->getReturnType();
- QualType RT = Desugar(Context, SugarRT, DesugarReturn);
+ QualType RT = desugarForDiagnostic(Context, SugarRT, DesugarReturn);
if (auto nullability = AttributedType::stripOuterNullability(SugarRT)) {
RT = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*nullability), RT, RT);
@@ -87,7 +88,7 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT);
if (FPT) {
for (QualType SugarPT : FPT->param_types()) {
- QualType PT = Desugar(Context, SugarPT, DesugarArgument);
+ QualType PT = desugarForDiagnostic(Context, SugarPT, DesugarArgument);
if (auto nullability =
AttributedType::stripOuterNullability(SugarPT)) {
PT = Context.getAttributedType(
@@ -115,7 +116,8 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
for (unsigned I = 0, N = TST->getNumArgs(); I != N; ++I) {
const TemplateArgument &Arg = TST->getArg(I);
if (Arg.getKind() == TemplateArgument::Type)
- Args.push_back(Desugar(Context, Arg.getAsType(), DesugarArgument));
+ Args.push_back(desugarForDiagnostic(Context, Arg.getAsType(),
+ DesugarArgument));
else
Args.push_back(Arg);
}
@@ -181,24 +183,25 @@ break; \
// If we have a pointer-like type, desugar the pointee as well.
// FIXME: Handle other pointer-like types.
if (const PointerType *Ty = QT->getAs<PointerType>()) {
- QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(),
- ShouldAKA));
+ QT = Context.getPointerType(
+ desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA));
} else if (const auto *Ty = QT->getAs<ObjCObjectPointerType>()) {
- QT = Context.getObjCObjectPointerType(Desugar(Context, Ty->getPointeeType(),
- ShouldAKA));
+ QT = Context.getObjCObjectPointerType(
+ desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA));
} else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) {
- QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(),
- ShouldAKA));
+ QT = Context.getLValueReferenceType(
+ desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA));
} else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) {
- QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(),
- ShouldAKA));
+ QT = Context.getRValueReferenceType(
+ desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA));
} else if (const auto *Ty = QT->getAs<ObjCObjectType>()) {
if (Ty->getBaseType().getTypePtr() != Ty && !ShouldAKA) {
- QualType BaseType = Desugar(Context, Ty->getBaseType(), ShouldAKA);
- QT = Context.getObjCObjectType(BaseType, Ty->getTypeArgsAsWritten(),
- llvm::makeArrayRef(Ty->qual_begin(),
- Ty->getNumProtocols()),
- Ty->isKindOfTypeAsWritten());
+ QualType BaseType =
+ desugarForDiagnostic(Context, Ty->getBaseType(), ShouldAKA);
+ QT = Context.getObjCObjectType(
+ BaseType, Ty->getTypeArgsAsWritten(),
+ llvm::makeArrayRef(Ty->qual_begin(), Ty->getNumProtocols()),
+ Ty->isKindOfTypeAsWritten());
}
}
@@ -251,7 +254,8 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
continue; // Same canonical types
std::string CompareS = CompareTy.getAsString(Context.getPrintingPolicy());
bool ShouldAKA = false;
- QualType CompareDesugar = Desugar(Context, CompareTy, ShouldAKA);
+ QualType CompareDesugar =
+ desugarForDiagnostic(Context, CompareTy, ShouldAKA);
std::string CompareDesugarStr =
CompareDesugar.getAsString(Context.getPrintingPolicy());
if (CompareS != S && CompareDesugarStr != S)
@@ -286,7 +290,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
// sugar gives us something "significantly
diff erent".
if (!Repeated) {
bool ShouldAKA = false;
- QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA);
+ QualType DesugaredTy = desugarForDiagnostic(Context, Ty, ShouldAKA);
if (ShouldAKA || ForceAKA) {
if (DesugaredTy == Ty) {
DesugaredTy = Ty.getCanonicalType();
More information about the cfe-commits
mailing list