diff --git a/clang-tools-extra/clangd/Hover.h b/clang-tools-extra/clangd/Hover.h --- a/clang-tools-extra/clangd/Hover.h +++ b/clang-tools-extra/clangd/Hover.h @@ -22,15 +22,28 @@ /// 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 AKA; + }; + /// Represents parameters of a function, a template or a macro. /// For example: /// - void foo(ParamType Name = DefaultValue) /// - #define FOO(Name) /// - template 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 Type; + llvm::Optional Type; /// None for unnamed parameters. llvm::Optional Name; /// None if no default is provided. @@ -62,11 +75,11 @@ /// 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 Type; + llvm::Optional Type; /// Set for functions and lambdas. - llvm::Optional ReturnType; + llvm::Optional ReturnType; /// Set for functions, lambdas and macros with parameters. llvm::Optional> Parameters; /// Set for all templates(function, class, variable). @@ -98,6 +111,11 @@ 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 @@ // 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/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp --- 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 @@ -138,14 +140,15 @@ 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()->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 @@ if (auto *TT = llvm::dyn_cast(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(Param)) - OS << printType(TTP); + OS << printType(TTP).Type; else if (const auto *NTTP = dyn_cast(Param)) - OS << printType(NTTP, PP); + OS << printType(NTTP, PP).Type; else if (const auto *TTPD = dyn_cast(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 @@ -329,7 +343,7 @@ 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 @@ 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(D)) // Lambdas QT = VD->getType().getDesugaredType(D->getASTContext()); - HI.Type = printType(QT, PP); + HI.Type = printType(QT, D->getASTContext(), PP); // FIXME: handle variadics. } @@ -589,11 +603,16 @@ if (const FunctionDecl *FD = getUnderlyingFunction(D)) fillFunctionTypeAndParams(HI, D, FD, PP); else if (const auto *VD = dyn_cast(D)) - HI.Type = printType(VD->getType(), PP); + HI.Type = printType(VD->getType(), VD->getASTContext(), PP); else if (const auto *TTP = dyn_cast(D)) HI.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class"; else if (const auto *TTP = dyn_cast(D)) HI.Type = printType(TTP, PP); + else if (const auto *TN = dyn_cast(D)) + HI.Type = printType(TN->getUnderlyingType(), TN->getASTContext(), PP); + else if (const auto *TAT = dyn_cast(D)) + HI.Type = printType(TAT->getTemplatedDecl()->getUnderlyingType(), + TAT->getASTContext(), PP); // Fill in value with evaluated initializer if possible. if (const auto *Var = dyn_cast(D)) { @@ -604,7 +623,6 @@ if (!ECD->getType()->isDependentType()) HI.Value = toString(ECD->getInitVal(), 10); } - HI.Definition = printDefinition(D, PP); return HI; } @@ -644,6 +662,16 @@ 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 getThisExprHoverContents(const CXXThisExpr *CTE, ASTContext &ASTCtx, const PrintingPolicy &PP) { @@ -658,7 +686,7 @@ HoverInfo HI; HI.Name = "this"; - HI.Definition = printType(PrettyThisType, PP); + HI.Definition = typeAsDefinition(printType(PrettyThisType, ASTCtx, PP)); return HI; } @@ -675,7 +703,7 @@ 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); @@ -726,7 +754,7 @@ // 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; @@ -1057,24 +1085,22 @@ // 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(); @@ -1107,7 +1133,7 @@ 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()); } @@ -1216,13 +1242,19 @@ } 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 Output; if (P.Type) - Output.push_back(*P.Type); + OS << llvm::to_string(*P.Type); if (P.Name) - Output.push_back(*P.Name); - OS << llvm::join(Output, " "); + OS << " " << *P.Name; if (P.Default) OS << " = " << *P.Default; return OS; 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 @@ -211,12 +211,13 @@ bool Q = false, class... Ts> class Foo {})cpp"; HI.TemplateParameters = { - {std::string("template 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 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 @@ HI.ReturnType = "Foo"; HI.Type = "Foo (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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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)"; @@ -901,6 +903,71 @@ HI.Kind = index::SymbolKind::Unknown; HI.Type = "int[10]"; HI.Value = "{1}"; + }}, + {// Canonical type + R"cpp( + template + struct TestHover { + using Type = T; + }; + + void code() { + TestHover::Type ^[[a]]; + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "a"; + HI.NamespaceScope = ""; + HI.LocalScope = "code::"; + HI.Definition = "TestHover::Type a"; + HI.Kind = index::SymbolKind::Variable; + HI.Type = {"TestHover::Type", "int"}; + }}, + {// Canonical template type + R"cpp( + template + void ^[[foo]](T arg) {} + )cpp", + [](HoverInfo &HI) { + HI.Name = "foo"; + HI.Kind = index::SymbolKind::Function; + HI.NamespaceScope = ""; + HI.Definition = "template 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 + using ^[[alias]] = T; + )cpp", + [](HoverInfo &HI) { + HI.Name = "alias"; + HI.NamespaceScope = ""; + HI.LocalScope = ""; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "template using alias = T"; + HI.Type = "T"; + HI.TemplateParameters = {{{"typename"}, std::string("T"), llvm::None}}; + }}, + {// TypeAlias Template + R"cpp( + template + using A = T; + + template + using ^[[AA]] = A; + )cpp", + [](HoverInfo &HI) { + HI.Name = "AA"; + HI.NamespaceScope = ""; + HI.LocalScope = ""; + HI.Kind = index::SymbolKind::TypeAlias; + HI.Definition = "template using AA = A"; + HI.Type = {"A", "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); @@ -1198,7 +1265,7 @@ HI.Documentation = "Function definition via pointer"; HI.ReturnType = "void"; HI.Parameters = { - {std::string("int"), llvm::None, llvm::None}, + {{"int"}, llvm::None, llvm::None}, }; }}, { @@ -1217,7 +1284,7 @@ HI.Documentation = "Function declaration via call"; HI.ReturnType = "int"; HI.Parameters = { - {std::string("int"), llvm::None, llvm::None}, + {{"int"}, llvm::None, llvm::None}, }; }}, { @@ -1361,8 +1428,8 @@ 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 @@ -1376,6 +1443,7 @@ HI.Kind = index::SymbolKind::TypeAlias; HI.NamespaceScope = ""; HI.Definition = "typedef struct Bar Foo"; + HI.Type = "struct Bar"; HI.Documentation = "Typedef with embedded definition"; }}, { @@ -2024,7 +2092,7 @@ [](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 @@ -2035,7 +2103,7 @@ [](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"; }}, { @@ -2186,10 +2254,10 @@ 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 @@ -2222,8 +2290,7 @@ 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(const int &)"; HI.NamespaceScope = ""; }}, @@ -2580,9 +2647,8 @@ 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 = @@ -2601,12 +2667,12 @@ [](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); @@ -2617,12 +2683,12 @@ }, "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 (aka can_type) foo\n" + "- type (aka can_type) foo = default\n" "\n" "// In namespace ns\n" "ret_type foo(params) {}", @@ -2633,7 +2699,7 @@ 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; @@ -2641,7 +2707,7 @@ }, R"(field foo -Type: type +Type: type (aka can_type) Value = value Offset: 12 bytes Size: 4 bytes (+4 padding) @@ -2664,22 +2730,22 @@ }, { [](HoverInfo &HI) { - HI.Definition = "int method()"; + HI.Definition = "size_t method()"; HI.AccessSpecifier = "protected"; HI.Kind = index::SymbolKind::InstanceMethod; HI.NamespaceScope = ""; HI.LocalScope = "cls::"; 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 -protected: int method())", +protected: size_t method())", }, { [](HoverInfo &HI) { @@ -2780,7 +2846,7 @@ 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; @@ -2790,7 +2856,7 @@ 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 --- 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 @@ SmallVectorImpl &Output, void *Cookie, ArrayRef 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 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -26,7 +26,8 @@ // 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 @@ if (const FunctionType *FT = dyn_cast(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 @@ const FunctionProtoType *FPT = dyn_cast(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 @@ 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 @@ // If we have a pointer-like type, desugar the pointee as well. // FIXME: Handle other pointer-like types. if (const PointerType *Ty = QT->getAs()) { - QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(), - ShouldAKA)); + QT = Context.getPointerType( + desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA)); } else if (const auto *Ty = QT->getAs()) { - QT = Context.getObjCObjectPointerType(Desugar(Context, Ty->getPointeeType(), - ShouldAKA)); + QT = Context.getObjCObjectPointerType( + desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA)); } else if (const LValueReferenceType *Ty = QT->getAs()) { - QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(), - ShouldAKA)); + QT = Context.getLValueReferenceType( + desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA)); } else if (const RValueReferenceType *Ty = QT->getAs()) { - QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(), - ShouldAKA)); + QT = Context.getRValueReferenceType( + desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA)); } else if (const auto *Ty = QT->getAs()) { 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 @@ 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 @@ // sugar gives us something "significantly different". 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();