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
#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"
#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>
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
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>
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)) {
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.
}
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)) {
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) {
HoverInfo HI;
HI.Name = "this";
- HI.Definition = printType(PrettyThisType, PP);
+ HI.Definition = typeAsDefinition(printType(PrettyThisType, ASTCtx, PP));
return HI;
}
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);
// 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;
// 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();
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());
}
}
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;
}
/// 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.
/// 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).
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) ==
// 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) {
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
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
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;
}},
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;
}},
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;
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;
}},
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)";
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);
HI.Documentation = "Function definition via pointer";
HI.ReturnType = "void";
HI.Parameters = {
- {std::string("int"), llvm::None, llvm::None},
+ {{"int"}, llvm::None, llvm::None},
};
}},
{
HI.Documentation = "Function declaration via call";
HI.ReturnType = "int";
HI.Parameters = {
- {std::string("int"), llvm::None, llvm::None},
+ {{"int"}, llvm::None, llvm::None},
};
}},
{
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
HI.Kind = index::SymbolKind::TypeAlias;
HI.NamespaceScope = "";
HI.Definition = "typedef struct Bar Foo";
+ HI.Type = "struct Bar";
HI.Documentation = "Typedef with embedded definition";
}},
{
[](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
[](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";
}},
{
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
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 = "";
}},
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 =
[](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);
},
"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) {}",
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;
},
R"(field foo
-Type: type
+Type: type (aka can_type)
Value = value
Offset: 12 bytes
Size: 4 bytes (+4 padding)
},
{
[](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) {
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;
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)",
#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"
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
// 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) {
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);
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(
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);
}
// 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());
}
}
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)
// 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();