You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2042 lines
74 KiB
2042 lines
74 KiB
//===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for AST Nodes ------===// |
|
// |
|
// The LLVM Compiler Infrastructure |
|
// |
|
// This file is distributed under the University of Illinois Open Source |
|
// License. See LICENSE.TXT for details. |
|
// |
|
//===----------------------------------------------------------------------===// |
|
// |
|
// This file implements a diagnostic formatting hook for AST elements. |
|
// |
|
//===----------------------------------------------------------------------===// |
|
|
|
#include "clang/AST/ASTDiagnostic.h" |
|
#include "clang/AST/ASTContext.h" |
|
#include "clang/AST/ASTLambda.h" |
|
#include "clang/AST/Attr.h" |
|
#include "clang/AST/DeclObjC.h" |
|
#include "clang/AST/DeclTemplate.h" |
|
#include "clang/AST/ExprCXX.h" |
|
#include "clang/AST/TemplateBase.h" |
|
#include "clang/AST/Type.h" |
|
#include "llvm/ADT/SmallString.h" |
|
#include "llvm/Support/raw_ostream.h" |
|
|
|
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) { |
|
QualifierCollector QC; |
|
|
|
while (true) { |
|
const Type *Ty = QC.strip(QT); |
|
|
|
// Don't aka just because we saw an elaborated type... |
|
if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Ty)) { |
|
QT = ET->desugar(); |
|
continue; |
|
} |
|
// ... or a paren type ... |
|
if (const ParenType *PT = dyn_cast<ParenType>(Ty)) { |
|
QT = PT->desugar(); |
|
continue; |
|
} |
|
// ...or a substituted template type parameter ... |
|
if (const SubstTemplateTypeParmType *ST = |
|
dyn_cast<SubstTemplateTypeParmType>(Ty)) { |
|
QT = ST->desugar(); |
|
continue; |
|
} |
|
// ...or an attributed type... |
|
if (const AttributedType *AT = dyn_cast<AttributedType>(Ty)) { |
|
QT = AT->desugar(); |
|
continue; |
|
} |
|
// ...or an adjusted type... |
|
if (const AdjustedType *AT = dyn_cast<AdjustedType>(Ty)) { |
|
QT = AT->desugar(); |
|
continue; |
|
} |
|
// ... or an auto type. |
|
if (const AutoType *AT = dyn_cast<AutoType>(Ty)) { |
|
if (!AT->isSugared()) |
|
break; |
|
QT = AT->desugar(); |
|
continue; |
|
} |
|
|
|
// Desugar FunctionType if return type or any parameter type should be |
|
// desugared. Preserve nullability attribute on desugared types. |
|
if (const FunctionType *FT = dyn_cast<FunctionType>(Ty)) { |
|
bool DesugarReturn = false; |
|
QualType SugarRT = FT->getReturnType(); |
|
QualType RT = Desugar(Context, SugarRT, DesugarReturn); |
|
if (auto nullability = AttributedType::stripOuterNullability(SugarRT)) { |
|
RT = Context.getAttributedType( |
|
AttributedType::getNullabilityAttrKind(*nullability), RT, RT); |
|
} |
|
|
|
bool DesugarArgument = false; |
|
SmallVector<QualType, 4> Args; |
|
const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT); |
|
if (FPT) { |
|
for (QualType SugarPT : FPT->param_types()) { |
|
QualType PT = Desugar(Context, SugarPT, DesugarArgument); |
|
if (auto nullability = |
|
AttributedType::stripOuterNullability(SugarPT)) { |
|
PT = Context.getAttributedType( |
|
AttributedType::getNullabilityAttrKind(*nullability), PT, PT); |
|
} |
|
Args.push_back(PT); |
|
} |
|
} |
|
|
|
if (DesugarReturn || DesugarArgument) { |
|
ShouldAKA = true; |
|
QT = FPT ? Context.getFunctionType(RT, Args, FPT->getExtProtoInfo()) |
|
: Context.getFunctionNoProtoType(RT, FT->getExtInfo()); |
|
break; |
|
} |
|
} |
|
|
|
// Desugar template specializations if any template argument should be |
|
// desugared. |
|
if (const TemplateSpecializationType *TST = |
|
dyn_cast<TemplateSpecializationType>(Ty)) { |
|
if (!TST->isTypeAlias()) { |
|
bool DesugarArgument = false; |
|
SmallVector<TemplateArgument, 4> Args; |
|
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)); |
|
else |
|
Args.push_back(Arg); |
|
} |
|
|
|
if (DesugarArgument) { |
|
ShouldAKA = true; |
|
QT = Context.getTemplateSpecializationType( |
|
TST->getTemplateName(), Args, QT); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
// Don't desugar magic Objective-C types. |
|
if (QualType(Ty,0) == Context.getObjCIdType() || |
|
QualType(Ty,0) == Context.getObjCClassType() || |
|
QualType(Ty,0) == Context.getObjCSelType() || |
|
QualType(Ty,0) == Context.getObjCProtoType()) |
|
break; |
|
|
|
// Don't desugar va_list. |
|
if (QualType(Ty, 0) == Context.getBuiltinVaListType() || |
|
QualType(Ty, 0) == Context.getBuiltinMSVaListType()) |
|
break; |
|
|
|
// Otherwise, do a single-step desugar. |
|
QualType Underlying; |
|
bool IsSugar = false; |
|
switch (Ty->getTypeClass()) { |
|
#define ABSTRACT_TYPE(Class, Base) |
|
#define TYPE(Class, Base) \ |
|
case Type::Class: { \ |
|
const Class##Type *CTy = cast<Class##Type>(Ty); \ |
|
if (CTy->isSugared()) { \ |
|
IsSugar = true; \ |
|
Underlying = CTy->desugar(); \ |
|
} \ |
|
break; \ |
|
} |
|
#include "clang/AST/TypeNodes.def" |
|
} |
|
|
|
// If it wasn't sugared, we're done. |
|
if (!IsSugar) |
|
break; |
|
|
|
// If the desugared type is a vector type, we don't want to expand |
|
// it, it will turn into an attribute mess. People want their "vec4". |
|
if (isa<VectorType>(Underlying)) |
|
break; |
|
|
|
// Don't desugar through the primary typedef of an anonymous type. |
|
if (const TagType *UTT = Underlying->getAs<TagType>()) |
|
if (const TypedefType *QTT = dyn_cast<TypedefType>(QT)) |
|
if (UTT->getDecl()->getTypedefNameForAnonDecl() == QTT->getDecl()) |
|
break; |
|
|
|
// Record that we actually looked through an opaque type here. |
|
ShouldAKA = true; |
|
QT = Underlying; |
|
} |
|
|
|
// 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)); |
|
} else if (const auto *Ty = QT->getAs<ObjCObjectPointerType>()) { |
|
QT = Context.getObjCObjectPointerType(Desugar(Context, Ty->getPointeeType(), |
|
ShouldAKA)); |
|
} else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) { |
|
QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(), |
|
ShouldAKA)); |
|
} else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) { |
|
QT = Context.getRValueReferenceType(Desugar(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()); |
|
} |
|
} |
|
|
|
return QC.apply(Context, QT); |
|
} |
|
|
|
/// \brief Convert the given type to a string suitable for printing as part of |
|
/// a diagnostic. |
|
/// |
|
/// There are four main criteria when determining whether we should have an |
|
/// a.k.a. clause when pretty-printing a type: |
|
/// |
|
/// 1) Some types provide very minimal sugar that doesn't impede the |
|
/// user's understanding --- for example, elaborated type |
|
/// specifiers. If this is all the sugar we see, we don't want an |
|
/// a.k.a. clause. |
|
/// 2) Some types are technically sugared but are much more familiar |
|
/// when seen in their sugared form --- for example, va_list, |
|
/// vector types, and the magic Objective C types. We don't |
|
/// want to desugar these, even if we do produce an a.k.a. clause. |
|
/// 3) Some types may have already been desugared previously in this diagnostic. |
|
/// if this is the case, doing another "aka" would just be clutter. |
|
/// 4) Two different types within the same diagnostic have the same output |
|
/// string. In this case, force an a.k.a with the desugared type when |
|
/// doing so will provide additional information. |
|
/// |
|
/// \param Context the context in which the type was allocated |
|
/// \param Ty the type to print |
|
/// \param QualTypeVals pointer values to QualTypes which are used in the |
|
/// diagnostic message |
|
static std::string |
|
ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, |
|
ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs, |
|
ArrayRef<intptr_t> QualTypeVals) { |
|
// FIXME: Playing with std::string is really slow. |
|
bool ForceAKA = false; |
|
QualType CanTy = Ty.getCanonicalType(); |
|
std::string S = Ty.getAsString(Context.getPrintingPolicy()); |
|
std::string CanS = CanTy.getAsString(Context.getPrintingPolicy()); |
|
|
|
for (unsigned I = 0, E = QualTypeVals.size(); I != E; ++I) { |
|
QualType CompareTy = |
|
QualType::getFromOpaquePtr(reinterpret_cast<void*>(QualTypeVals[I])); |
|
if (CompareTy.isNull()) |
|
continue; |
|
if (CompareTy == Ty) |
|
continue; // Same types |
|
QualType CompareCanTy = CompareTy.getCanonicalType(); |
|
if (CompareCanTy == CanTy) |
|
continue; // Same canonical types |
|
std::string CompareS = CompareTy.getAsString(Context.getPrintingPolicy()); |
|
bool ShouldAKA = false; |
|
QualType CompareDesugar = Desugar(Context, CompareTy, ShouldAKA); |
|
std::string CompareDesugarStr = |
|
CompareDesugar.getAsString(Context.getPrintingPolicy()); |
|
if (CompareS != S && CompareDesugarStr != S) |
|
continue; // The type string is different than the comparison string |
|
// and the desugared comparison string. |
|
std::string CompareCanS = |
|
CompareCanTy.getAsString(Context.getPrintingPolicy()); |
|
|
|
if (CompareCanS == CanS) |
|
continue; // No new info from canonical type |
|
|
|
ForceAKA = true; |
|
break; |
|
} |
|
|
|
// Check to see if we already desugared this type in this |
|
// diagnostic. If so, don't do it again. |
|
bool Repeated = false; |
|
for (unsigned i = 0, e = PrevArgs.size(); i != e; ++i) { |
|
// TODO: Handle ak_declcontext case. |
|
if (PrevArgs[i].first == DiagnosticsEngine::ak_qualtype) { |
|
void *Ptr = (void*)PrevArgs[i].second; |
|
QualType PrevTy(QualType::getFromOpaquePtr(Ptr)); |
|
if (PrevTy == Ty) { |
|
Repeated = true; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
// Consider producing an a.k.a. clause if removing all the direct |
|
// sugar gives us something "significantly different". |
|
if (!Repeated) { |
|
bool ShouldAKA = false; |
|
QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA); |
|
if (ShouldAKA || ForceAKA) { |
|
if (DesugaredTy == Ty) { |
|
DesugaredTy = Ty.getCanonicalType(); |
|
} |
|
std::string akaStr = DesugaredTy.getAsString(Context.getPrintingPolicy()); |
|
if (akaStr != S) { |
|
S = "'" + S + "' (aka '" + akaStr + "')"; |
|
return S; |
|
} |
|
} |
|
|
|
// Give some additional info on vector types. These are either not desugared |
|
// or displaying complex __attribute__ expressions so add details of the |
|
// type and element count. |
|
if (Ty->isVectorType()) { |
|
const VectorType *VTy = Ty->getAs<VectorType>(); |
|
std::string DecoratedString; |
|
llvm::raw_string_ostream OS(DecoratedString); |
|
const char *Values = VTy->getNumElements() > 1 ? "values" : "value"; |
|
OS << "'" << S << "' (vector of " << VTy->getNumElements() << " '" |
|
<< VTy->getElementType().getAsString(Context.getPrintingPolicy()) |
|
<< "' " << Values << ")"; |
|
return OS.str(); |
|
} |
|
} |
|
|
|
S = "'" + S + "'"; |
|
return S; |
|
} |
|
|
|
static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType, |
|
QualType ToType, bool PrintTree, |
|
bool PrintFromType, bool ElideType, |
|
bool ShowColors, raw_ostream &OS); |
|
|
|
void clang::FormatASTNodeDiagnosticArgument( |
|
DiagnosticsEngine::ArgumentKind Kind, |
|
intptr_t Val, |
|
StringRef Modifier, |
|
StringRef Argument, |
|
ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs, |
|
SmallVectorImpl<char> &Output, |
|
void *Cookie, |
|
ArrayRef<intptr_t> QualTypeVals) { |
|
ASTContext &Context = *static_cast<ASTContext*>(Cookie); |
|
|
|
size_t OldEnd = Output.size(); |
|
llvm::raw_svector_ostream OS(Output); |
|
bool NeedQuotes = true; |
|
|
|
switch (Kind) { |
|
default: llvm_unreachable("unknown ArgumentKind"); |
|
case DiagnosticsEngine::ak_qualtype_pair: { |
|
TemplateDiffTypes &TDT = *reinterpret_cast<TemplateDiffTypes*>(Val); |
|
QualType FromType = |
|
QualType::getFromOpaquePtr(reinterpret_cast<void*>(TDT.FromType)); |
|
QualType ToType = |
|
QualType::getFromOpaquePtr(reinterpret_cast<void*>(TDT.ToType)); |
|
|
|
if (FormatTemplateTypeDiff(Context, FromType, ToType, TDT.PrintTree, |
|
TDT.PrintFromType, TDT.ElideType, |
|
TDT.ShowColors, OS)) { |
|
NeedQuotes = !TDT.PrintTree; |
|
TDT.TemplateDiffUsed = true; |
|
break; |
|
} |
|
|
|
// Don't fall-back during tree printing. The caller will handle |
|
// this case. |
|
if (TDT.PrintTree) |
|
return; |
|
|
|
// Attempting to do a template diff on non-templates. Set the variables |
|
// and continue with regular type printing of the appropriate type. |
|
Val = TDT.PrintFromType ? TDT.FromType : TDT.ToType; |
|
Modifier = StringRef(); |
|
Argument = StringRef(); |
|
// Fall through |
|
} |
|
case DiagnosticsEngine::ak_qualtype: { |
|
assert(Modifier.empty() && Argument.empty() && |
|
"Invalid modifier for QualType argument"); |
|
|
|
QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val))); |
|
OS << ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, QualTypeVals); |
|
NeedQuotes = false; |
|
break; |
|
} |
|
case DiagnosticsEngine::ak_declarationname: { |
|
if (Modifier == "objcclass" && Argument.empty()) |
|
OS << '+'; |
|
else if (Modifier == "objcinstance" && Argument.empty()) |
|
OS << '-'; |
|
else |
|
assert(Modifier.empty() && Argument.empty() && |
|
"Invalid modifier for DeclarationName argument"); |
|
|
|
OS << DeclarationName::getFromOpaqueInteger(Val); |
|
break; |
|
} |
|
case DiagnosticsEngine::ak_nameddecl: { |
|
bool Qualified; |
|
if (Modifier == "q" && Argument.empty()) |
|
Qualified = true; |
|
else { |
|
assert(Modifier.empty() && Argument.empty() && |
|
"Invalid modifier for NamedDecl* argument"); |
|
Qualified = false; |
|
} |
|
const NamedDecl *ND = reinterpret_cast<const NamedDecl*>(Val); |
|
ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), Qualified); |
|
break; |
|
} |
|
case DiagnosticsEngine::ak_nestednamespec: { |
|
NestedNameSpecifier *NNS = reinterpret_cast<NestedNameSpecifier*>(Val); |
|
NNS->print(OS, Context.getPrintingPolicy()); |
|
NeedQuotes = false; |
|
break; |
|
} |
|
case DiagnosticsEngine::ak_declcontext: { |
|
DeclContext *DC = reinterpret_cast<DeclContext *> (Val); |
|
assert(DC && "Should never have a null declaration context"); |
|
NeedQuotes = false; |
|
|
|
// FIXME: Get the strings for DeclContext from some localized place |
|
if (DC->isTranslationUnit()) { |
|
if (Context.getLangOpts().CPlusPlus) |
|
OS << "the global namespace"; |
|
else |
|
OS << "the global scope"; |
|
} else if (DC->isClosure()) { |
|
OS << "block literal"; |
|
} else if (isLambdaCallOperator(DC)) { |
|
OS << "lambda expression"; |
|
} else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) { |
|
OS << ConvertTypeToDiagnosticString(Context, |
|
Context.getTypeDeclType(Type), |
|
PrevArgs, QualTypeVals); |
|
} else { |
|
assert(isa<NamedDecl>(DC) && "Expected a NamedDecl"); |
|
NamedDecl *ND = cast<NamedDecl>(DC); |
|
if (isa<NamespaceDecl>(ND)) |
|
OS << "namespace "; |
|
else if (isa<ObjCMethodDecl>(ND)) |
|
OS << "method "; |
|
else if (isa<FunctionDecl>(ND)) |
|
OS << "function "; |
|
|
|
OS << '\''; |
|
ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), true); |
|
OS << '\''; |
|
} |
|
break; |
|
} |
|
case DiagnosticsEngine::ak_attr: { |
|
const Attr *At = reinterpret_cast<Attr *>(Val); |
|
assert(At && "Received null Attr object!"); |
|
OS << '\'' << At->getSpelling() << '\''; |
|
NeedQuotes = false; |
|
break; |
|
} |
|
} |
|
|
|
if (NeedQuotes) { |
|
Output.insert(Output.begin()+OldEnd, '\''); |
|
Output.push_back('\''); |
|
} |
|
} |
|
|
|
/// TemplateDiff - A class that constructs a pretty string for a pair of |
|
/// QualTypes. For the pair of types, a diff tree will be created containing |
|
/// all the information about the templates and template arguments. Afterwards, |
|
/// the tree is transformed to a string according to the options passed in. |
|
namespace { |
|
class TemplateDiff { |
|
/// Context - The ASTContext which is used for comparing template arguments. |
|
ASTContext &Context; |
|
|
|
/// Policy - Used during expression printing. |
|
PrintingPolicy Policy; |
|
|
|
/// ElideType - Option to elide identical types. |
|
bool ElideType; |
|
|
|
/// PrintTree - Format output string as a tree. |
|
bool PrintTree; |
|
|
|
/// ShowColor - Diagnostics support color, so bolding will be used. |
|
bool ShowColor; |
|
|
|
/// FromTemplateType - When single type printing is selected, this is the |
|
/// type to be be printed. When tree printing is selected, this type will |
|
/// show up first in the tree. |
|
QualType FromTemplateType; |
|
|
|
/// ToTemplateType - The type that FromType is compared to. Only in tree |
|
/// printing will this type be outputed. |
|
QualType ToTemplateType; |
|
|
|
/// OS - The stream used to construct the output strings. |
|
raw_ostream &OS; |
|
|
|
/// IsBold - Keeps track of the bold formatting for the output string. |
|
bool IsBold; |
|
|
|
/// DiffTree - A tree representation the differences between two types. |
|
class DiffTree { |
|
public: |
|
/// DiffKind - The difference in a DiffNode. Fields of |
|
/// TemplateArgumentInfo needed by each difference can be found in the |
|
/// Set* and Get* functions. |
|
enum DiffKind { |
|
/// Incomplete or invalid node. |
|
Invalid, |
|
/// Another level of templates |
|
Template, |
|
/// Type difference, all type differences except those falling under |
|
/// the Template difference. |
|
Type, |
|
/// Expression difference, this is only when both arguments are |
|
/// expressions. If one argument is an expression and the other is |
|
/// Integer or Declaration, then use that diff type instead. |
|
Expression, |
|
/// Template argument difference |
|
TemplateTemplate, |
|
/// Integer difference |
|
Integer, |
|
/// Declaration difference, nullptr arguments are included here |
|
Declaration, |
|
/// One argument being integer and the other being declaration |
|
FromIntegerAndToDeclaration, |
|
FromDeclarationAndToInteger |
|
}; |
|
|
|
private: |
|
/// TemplateArgumentInfo - All the information needed to pretty print |
|
/// a template argument. See the Set* and Get* functions to see which |
|
/// fields are used for each DiffKind. |
|
struct TemplateArgumentInfo { |
|
QualType ArgType; |
|
Qualifiers Qual; |
|
llvm::APSInt Val; |
|
bool IsValidInt = false; |
|
Expr *ArgExpr = nullptr; |
|
TemplateDecl *TD = nullptr; |
|
ValueDecl *VD = nullptr; |
|
bool NeedAddressOf = false; |
|
bool IsNullPtr = false; |
|
bool IsDefault = false; |
|
}; |
|
|
|
/// DiffNode - The root node stores the original type. Each child node |
|
/// stores template arguments of their parents. For templated types, the |
|
/// template decl is also stored. |
|
struct DiffNode { |
|
DiffKind Kind = Invalid; |
|
|
|
/// NextNode - The index of the next sibling node or 0. |
|
unsigned NextNode = 0; |
|
|
|
/// ChildNode - The index of the first child node or 0. |
|
unsigned ChildNode = 0; |
|
|
|
/// ParentNode - The index of the parent node. |
|
unsigned ParentNode = 0; |
|
|
|
TemplateArgumentInfo FromArgInfo, ToArgInfo; |
|
|
|
/// Same - Whether the two arguments evaluate to the same value. |
|
bool Same = false; |
|
|
|
DiffNode(unsigned ParentNode = 0) : ParentNode(ParentNode) {} |
|
}; |
|
|
|
/// FlatTree - A flattened tree used to store the DiffNodes. |
|
SmallVector<DiffNode, 16> FlatTree; |
|
|
|
/// CurrentNode - The index of the current node being used. |
|
unsigned CurrentNode; |
|
|
|
/// NextFreeNode - The index of the next unused node. Used when creating |
|
/// child nodes. |
|
unsigned NextFreeNode; |
|
|
|
/// ReadNode - The index of the current node being read. |
|
unsigned ReadNode; |
|
|
|
public: |
|
DiffTree() : |
|
CurrentNode(0), NextFreeNode(1) { |
|
FlatTree.push_back(DiffNode()); |
|
} |
|
|
|
// Node writing functions, one for each valid DiffKind element. |
|
void SetTemplateDiff(TemplateDecl *FromTD, TemplateDecl *ToTD, |
|
Qualifiers FromQual, Qualifiers ToQual, |
|
bool FromDefault, bool ToDefault) { |
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
|
FlatTree[CurrentNode].Kind = Template; |
|
FlatTree[CurrentNode].FromArgInfo.TD = FromTD; |
|
FlatTree[CurrentNode].ToArgInfo.TD = ToTD; |
|
FlatTree[CurrentNode].FromArgInfo.Qual = FromQual; |
|
FlatTree[CurrentNode].ToArgInfo.Qual = ToQual; |
|
SetDefault(FromDefault, ToDefault); |
|
} |
|
|
|
void SetTypeDiff(QualType FromType, QualType ToType, bool FromDefault, |
|
bool ToDefault) { |
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
|
FlatTree[CurrentNode].Kind = Type; |
|
FlatTree[CurrentNode].FromArgInfo.ArgType = FromType; |
|
FlatTree[CurrentNode].ToArgInfo.ArgType = ToType; |
|
SetDefault(FromDefault, ToDefault); |
|
} |
|
|
|
void SetExpressionDiff(Expr *FromExpr, Expr *ToExpr, bool FromDefault, |
|
bool ToDefault) { |
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
|
FlatTree[CurrentNode].Kind = Expression; |
|
FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
|
FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
|
SetDefault(FromDefault, ToDefault); |
|
} |
|
|
|
void SetTemplateTemplateDiff(TemplateDecl *FromTD, TemplateDecl *ToTD, |
|
bool FromDefault, bool ToDefault) { |
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
|
FlatTree[CurrentNode].Kind = TemplateTemplate; |
|
FlatTree[CurrentNode].FromArgInfo.TD = FromTD; |
|
FlatTree[CurrentNode].ToArgInfo.TD = ToTD; |
|
SetDefault(FromDefault, ToDefault); |
|
} |
|
|
|
void SetIntegerDiff(const llvm::APSInt &FromInt, const llvm::APSInt &ToInt, |
|
bool IsValidFromInt, bool IsValidToInt, |
|
QualType FromIntType, QualType ToIntType, |
|
Expr *FromExpr, Expr *ToExpr, bool FromDefault, |
|
bool ToDefault) { |
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
|
FlatTree[CurrentNode].Kind = Integer; |
|
FlatTree[CurrentNode].FromArgInfo.Val = FromInt; |
|
FlatTree[CurrentNode].ToArgInfo.Val = ToInt; |
|
FlatTree[CurrentNode].FromArgInfo.IsValidInt = IsValidFromInt; |
|
FlatTree[CurrentNode].ToArgInfo.IsValidInt = IsValidToInt; |
|
FlatTree[CurrentNode].FromArgInfo.ArgType = FromIntType; |
|
FlatTree[CurrentNode].ToArgInfo.ArgType = ToIntType; |
|
FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
|
FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
|
SetDefault(FromDefault, ToDefault); |
|
} |
|
|
|
void SetDeclarationDiff(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl, |
|
bool FromAddressOf, bool ToAddressOf, |
|
bool FromNullPtr, bool ToNullPtr, Expr *FromExpr, |
|
Expr *ToExpr, bool FromDefault, bool ToDefault) { |
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
|
FlatTree[CurrentNode].Kind = Declaration; |
|
FlatTree[CurrentNode].FromArgInfo.VD = FromValueDecl; |
|
FlatTree[CurrentNode].ToArgInfo.VD = ToValueDecl; |
|
FlatTree[CurrentNode].FromArgInfo.NeedAddressOf = FromAddressOf; |
|
FlatTree[CurrentNode].ToArgInfo.NeedAddressOf = ToAddressOf; |
|
FlatTree[CurrentNode].FromArgInfo.IsNullPtr = FromNullPtr; |
|
FlatTree[CurrentNode].ToArgInfo.IsNullPtr = ToNullPtr; |
|
FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
|
FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
|
SetDefault(FromDefault, ToDefault); |
|
} |
|
|
|
void SetFromDeclarationAndToIntegerDiff( |
|
ValueDecl *FromValueDecl, bool FromAddressOf, bool FromNullPtr, |
|
Expr *FromExpr, const llvm::APSInt &ToInt, bool IsValidToInt, |
|
QualType ToIntType, Expr *ToExpr, bool FromDefault, bool ToDefault) { |
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
|
FlatTree[CurrentNode].Kind = FromDeclarationAndToInteger; |
|
FlatTree[CurrentNode].FromArgInfo.VD = FromValueDecl; |
|
FlatTree[CurrentNode].FromArgInfo.NeedAddressOf = FromAddressOf; |
|
FlatTree[CurrentNode].FromArgInfo.IsNullPtr = FromNullPtr; |
|
FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
|
FlatTree[CurrentNode].ToArgInfo.Val = ToInt; |
|
FlatTree[CurrentNode].ToArgInfo.IsValidInt = IsValidToInt; |
|
FlatTree[CurrentNode].ToArgInfo.ArgType = ToIntType; |
|
FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
|
SetDefault(FromDefault, ToDefault); |
|
} |
|
|
|
void SetFromIntegerAndToDeclarationDiff( |
|
const llvm::APSInt &FromInt, bool IsValidFromInt, QualType FromIntType, |
|
Expr *FromExpr, ValueDecl *ToValueDecl, bool ToAddressOf, |
|
bool ToNullPtr, Expr *ToExpr, bool FromDefault, bool ToDefault) { |
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
|
FlatTree[CurrentNode].Kind = FromIntegerAndToDeclaration; |
|
FlatTree[CurrentNode].FromArgInfo.Val = FromInt; |
|
FlatTree[CurrentNode].FromArgInfo.IsValidInt = IsValidFromInt; |
|
FlatTree[CurrentNode].FromArgInfo.ArgType = FromIntType; |
|
FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
|
FlatTree[CurrentNode].ToArgInfo.VD = ToValueDecl; |
|
FlatTree[CurrentNode].ToArgInfo.NeedAddressOf = ToAddressOf; |
|
FlatTree[CurrentNode].ToArgInfo.IsNullPtr = ToNullPtr; |
|
FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
|
SetDefault(FromDefault, ToDefault); |
|
} |
|
|
|
/// SetDefault - Sets FromDefault and ToDefault flags of the current node. |
|
void SetDefault(bool FromDefault, bool ToDefault) { |
|
assert((!FromDefault || !ToDefault) && "Both arguments cannot be default."); |
|
FlatTree[CurrentNode].FromArgInfo.IsDefault = FromDefault; |
|
FlatTree[CurrentNode].ToArgInfo.IsDefault = ToDefault; |
|
} |
|
|
|
/// SetSame - Sets the same flag of the current node. |
|
void SetSame(bool Same) { |
|
FlatTree[CurrentNode].Same = Same; |
|
} |
|
|
|
/// SetKind - Sets the current node's type. |
|
void SetKind(DiffKind Kind) { |
|
FlatTree[CurrentNode].Kind = Kind; |
|
} |
|
|
|
/// Up - Changes the node to the parent of the current node. |
|
void Up() { |
|
assert(FlatTree[CurrentNode].Kind != Invalid && |
|
"Cannot exit node before setting node information."); |
|
CurrentNode = FlatTree[CurrentNode].ParentNode; |
|
} |
|
|
|
/// AddNode - Adds a child node to the current node, then sets that node |
|
/// node as the current node. |
|
void AddNode() { |
|
assert(FlatTree[CurrentNode].Kind == Template && |
|
"Only Template nodes can have children nodes."); |
|
FlatTree.push_back(DiffNode(CurrentNode)); |
|
DiffNode &Node = FlatTree[CurrentNode]; |
|
if (Node.ChildNode == 0) { |
|
// If a child node doesn't exist, add one. |
|
Node.ChildNode = NextFreeNode; |
|
} else { |
|
// If a child node exists, find the last child node and add a |
|
// next node to it. |
|
unsigned i; |
|
for (i = Node.ChildNode; FlatTree[i].NextNode != 0; |
|
i = FlatTree[i].NextNode) { |
|
} |
|
FlatTree[i].NextNode = NextFreeNode; |
|
} |
|
CurrentNode = NextFreeNode; |
|
++NextFreeNode; |
|
} |
|
|
|
// Node reading functions. |
|
/// StartTraverse - Prepares the tree for recursive traversal. |
|
void StartTraverse() { |
|
ReadNode = 0; |
|
CurrentNode = NextFreeNode; |
|
NextFreeNode = 0; |
|
} |
|
|
|
/// Parent - Move the current read node to its parent. |
|
void Parent() { |
|
ReadNode = FlatTree[ReadNode].ParentNode; |
|
} |
|
|
|
void GetTemplateDiff(TemplateDecl *&FromTD, TemplateDecl *&ToTD, |
|
Qualifiers &FromQual, Qualifiers &ToQual) { |
|
assert(FlatTree[ReadNode].Kind == Template && "Unexpected kind."); |
|
FromTD = FlatTree[ReadNode].FromArgInfo.TD; |
|
ToTD = FlatTree[ReadNode].ToArgInfo.TD; |
|
FromQual = FlatTree[ReadNode].FromArgInfo.Qual; |
|
ToQual = FlatTree[ReadNode].ToArgInfo.Qual; |
|
} |
|
|
|
void GetTypeDiff(QualType &FromType, QualType &ToType) { |
|
assert(FlatTree[ReadNode].Kind == Type && "Unexpected kind"); |
|
FromType = FlatTree[ReadNode].FromArgInfo.ArgType; |
|
ToType = FlatTree[ReadNode].ToArgInfo.ArgType; |
|
} |
|
|
|
void GetExpressionDiff(Expr *&FromExpr, Expr *&ToExpr) { |
|
assert(FlatTree[ReadNode].Kind == Expression && "Unexpected kind"); |
|
FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
|
ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
|
} |
|
|
|
void GetTemplateTemplateDiff(TemplateDecl *&FromTD, TemplateDecl *&ToTD) { |
|
assert(FlatTree[ReadNode].Kind == TemplateTemplate && "Unexpected kind."); |
|
FromTD = FlatTree[ReadNode].FromArgInfo.TD; |
|
ToTD = FlatTree[ReadNode].ToArgInfo.TD; |
|
} |
|
|
|
void GetIntegerDiff(llvm::APSInt &FromInt, llvm::APSInt &ToInt, |
|
bool &IsValidFromInt, bool &IsValidToInt, |
|
QualType &FromIntType, QualType &ToIntType, |
|
Expr *&FromExpr, Expr *&ToExpr) { |
|
assert(FlatTree[ReadNode].Kind == Integer && "Unexpected kind."); |
|
FromInt = FlatTree[ReadNode].FromArgInfo.Val; |
|
ToInt = FlatTree[ReadNode].ToArgInfo.Val; |
|
IsValidFromInt = FlatTree[ReadNode].FromArgInfo.IsValidInt; |
|
IsValidToInt = FlatTree[ReadNode].ToArgInfo.IsValidInt; |
|
FromIntType = FlatTree[ReadNode].FromArgInfo.ArgType; |
|
ToIntType = FlatTree[ReadNode].ToArgInfo.ArgType; |
|
FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
|
ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
|
} |
|
|
|
void GetDeclarationDiff(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl, |
|
bool &FromAddressOf, bool &ToAddressOf, |
|
bool &FromNullPtr, bool &ToNullPtr, Expr *&FromExpr, |
|
Expr *&ToExpr) { |
|
assert(FlatTree[ReadNode].Kind == Declaration && "Unexpected kind."); |
|
FromValueDecl = FlatTree[ReadNode].FromArgInfo.VD; |
|
ToValueDecl = FlatTree[ReadNode].ToArgInfo.VD; |
|
FromAddressOf = FlatTree[ReadNode].FromArgInfo.NeedAddressOf; |
|
ToAddressOf = FlatTree[ReadNode].ToArgInfo.NeedAddressOf; |
|
FromNullPtr = FlatTree[ReadNode].FromArgInfo.IsNullPtr; |
|
ToNullPtr = FlatTree[ReadNode].ToArgInfo.IsNullPtr; |
|
FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
|
ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
|
} |
|
|
|
void GetFromDeclarationAndToIntegerDiff( |
|
ValueDecl *&FromValueDecl, bool &FromAddressOf, bool &FromNullPtr, |
|
Expr *&FromExpr, llvm::APSInt &ToInt, bool &IsValidToInt, |
|
QualType &ToIntType, Expr *&ToExpr) { |
|
assert(FlatTree[ReadNode].Kind == FromDeclarationAndToInteger && |
|
"Unexpected kind."); |
|
FromValueDecl = FlatTree[ReadNode].FromArgInfo.VD; |
|
FromAddressOf = FlatTree[ReadNode].FromArgInfo.NeedAddressOf; |
|
FromNullPtr = FlatTree[ReadNode].FromArgInfo.IsNullPtr; |
|
FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
|
ToInt = FlatTree[ReadNode].ToArgInfo.Val; |
|
IsValidToInt = FlatTree[ReadNode].ToArgInfo.IsValidInt; |
|
ToIntType = FlatTree[ReadNode].ToArgInfo.ArgType; |
|
ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
|
} |
|
|
|
void GetFromIntegerAndToDeclarationDiff( |
|
llvm::APSInt &FromInt, bool &IsValidFromInt, QualType &FromIntType, |
|
Expr *&FromExpr, ValueDecl *&ToValueDecl, bool &ToAddressOf, |
|
bool &ToNullPtr, Expr *&ToExpr) { |
|
assert(FlatTree[ReadNode].Kind == FromIntegerAndToDeclaration && |
|
"Unexpected kind."); |
|
FromInt = FlatTree[ReadNode].FromArgInfo.Val; |
|
IsValidFromInt = FlatTree[ReadNode].FromArgInfo.IsValidInt; |
|
FromIntType = FlatTree[ReadNode].FromArgInfo.ArgType; |
|
FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
|
ToValueDecl = FlatTree[ReadNode].ToArgInfo.VD; |
|
ToAddressOf = FlatTree[ReadNode].ToArgInfo.NeedAddressOf; |
|
ToNullPtr = FlatTree[ReadNode].ToArgInfo.IsNullPtr; |
|
ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
|
} |
|
|
|
/// FromDefault - Return true if the from argument is the default. |
|
bool FromDefault() { |
|
return FlatTree[ReadNode].FromArgInfo.IsDefault; |
|
} |
|
|
|
/// ToDefault - Return true if the to argument is the default. |
|
bool ToDefault() { |
|
return FlatTree[ReadNode].ToArgInfo.IsDefault; |
|
} |
|
|
|
/// NodeIsSame - Returns true the arguments are the same. |
|
bool NodeIsSame() { |
|
return FlatTree[ReadNode].Same; |
|
} |
|
|
|
/// HasChildrend - Returns true if the node has children. |
|
bool HasChildren() { |
|
return FlatTree[ReadNode].ChildNode != 0; |
|
} |
|
|
|
/// MoveToChild - Moves from the current node to its child. |
|
void MoveToChild() { |
|
ReadNode = FlatTree[ReadNode].ChildNode; |
|
} |
|
|
|
/// AdvanceSibling - If there is a next sibling, advance to it and return |
|
/// true. Otherwise, return false. |
|
bool AdvanceSibling() { |
|
if (FlatTree[ReadNode].NextNode == 0) |
|
return false; |
|
|
|
ReadNode = FlatTree[ReadNode].NextNode; |
|
return true; |
|
} |
|
|
|
/// HasNextSibling - Return true if the node has a next sibling. |
|
bool HasNextSibling() { |
|
return FlatTree[ReadNode].NextNode != 0; |
|
} |
|
|
|
/// Empty - Returns true if the tree has no information. |
|
bool Empty() { |
|
return GetKind() == Invalid; |
|
} |
|
|
|
/// GetKind - Returns the current node's type. |
|
DiffKind GetKind() { |
|
return FlatTree[ReadNode].Kind; |
|
} |
|
}; |
|
|
|
DiffTree Tree; |
|
|
|
/// TSTiterator - a pair of iterators that walks the |
|
/// TemplateSpecializationType and the desugared TemplateSpecializationType. |
|
/// The deseguared TemplateArgument should provide the canonical argument |
|
/// for comparisons. |
|
class TSTiterator { |
|
typedef const TemplateArgument& reference; |
|
typedef const TemplateArgument* pointer; |
|
|
|
/// InternalIterator - an iterator that is used to enter a |
|
/// TemplateSpecializationType and read TemplateArguments inside template |
|
/// parameter packs in order with the rest of the TemplateArguments. |
|
struct InternalIterator { |
|
/// TST - the template specialization whose arguments this iterator |
|
/// traverse over. |
|
const TemplateSpecializationType *TST; |
|
|
|
/// Index - the index of the template argument in TST. |
|
unsigned Index; |
|
|
|
/// CurrentTA - if CurrentTA is not the same as EndTA, then CurrentTA |
|
/// points to a TemplateArgument within a parameter pack. |
|
TemplateArgument::pack_iterator CurrentTA; |
|
|
|
/// EndTA - the end iterator of a parameter pack |
|
TemplateArgument::pack_iterator EndTA; |
|
|
|
/// InternalIterator - Constructs an iterator and sets it to the first |
|
/// template argument. |
|
InternalIterator(const TemplateSpecializationType *TST) |
|
: TST(TST), Index(0), CurrentTA(nullptr), EndTA(nullptr) { |
|
if (isEnd()) return; |
|
|
|
// Set to first template argument. If not a parameter pack, done. |
|
TemplateArgument TA = TST->getArg(0); |
|
if (TA.getKind() != TemplateArgument::Pack) return; |
|
|
|
// Start looking into the parameter pack. |
|
CurrentTA = TA.pack_begin(); |
|
EndTA = TA.pack_end(); |
|
|
|
// Found a valid template argument. |
|
if (CurrentTA != EndTA) return; |
|
|
|
// Parameter pack is empty, use the increment to get to a valid |
|
// template argument. |
|
++(*this); |
|
} |
|
|
|
/// isEnd - Returns true if the iterator is one past the end. |
|
bool isEnd() const { |
|
return Index >= TST->getNumArgs(); |
|
} |
|
|
|
/// &operator++ - Increment the iterator to the next template argument. |
|
InternalIterator &operator++() { |
|
if (isEnd()) { |
|
return *this; |
|
} |
|
|
|
// If in a parameter pack, advance in the parameter pack. |
|
if (CurrentTA != EndTA) { |
|
++CurrentTA; |
|
if (CurrentTA != EndTA) |
|
return *this; |
|
} |
|
|
|
// Loop until a template argument is found, or the end is reached. |
|
while (true) { |
|
// Advance to the next template argument. Break if reached the end. |
|
if (++Index == TST->getNumArgs()) |
|
break; |
|
|
|
// If the TemplateArgument is not a parameter pack, done. |
|
TemplateArgument TA = TST->getArg(Index); |
|
if (TA.getKind() != TemplateArgument::Pack) |
|
break; |
|
|
|
// Handle parameter packs. |
|
CurrentTA = TA.pack_begin(); |
|
EndTA = TA.pack_end(); |
|
|
|
// If the parameter pack is empty, try to advance again. |
|
if (CurrentTA != EndTA) |
|
break; |
|
} |
|
return *this; |
|
} |
|
|
|
/// operator* - Returns the appropriate TemplateArgument. |
|
reference operator*() const { |
|
assert(!isEnd() && "Index exceeds number of arguments."); |
|
if (CurrentTA == EndTA) |
|
return TST->getArg(Index); |
|
else |
|
return *CurrentTA; |
|
} |
|
|
|
/// operator-> - Allow access to the underlying TemplateArgument. |
|
pointer operator->() const { |
|
return &operator*(); |
|
} |
|
}; |
|
|
|
bool UseDesugaredIterator; |
|
InternalIterator SugaredIterator; |
|
InternalIterator DesugaredIterator; |
|
|
|
public: |
|
TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST) |
|
: UseDesugaredIterator(TST->isSugared() && !TST->isTypeAlias()), |
|
SugaredIterator(TST), |
|
DesugaredIterator( |
|
GetTemplateSpecializationType(Context, TST->desugar())) {} |
|
|
|
/// &operator++ - Increment the iterator to the next template argument. |
|
TSTiterator &operator++() { |
|
++SugaredIterator; |
|
if (UseDesugaredIterator) |
|
++DesugaredIterator; |
|
return *this; |
|
} |
|
|
|
/// operator* - Returns the appropriate TemplateArgument. |
|
reference operator*() const { |
|
return *SugaredIterator; |
|
} |
|
|
|
/// operator-> - Allow access to the underlying TemplateArgument. |
|
pointer operator->() const { |
|
return &operator*(); |
|
} |
|
|
|
/// isEnd - Returns true if no more TemplateArguments are available. |
|
bool isEnd() const { |
|
return SugaredIterator.isEnd(); |
|
} |
|
|
|
/// hasDesugaredTA - Returns true if there is another TemplateArgument |
|
/// available. |
|
bool hasDesugaredTA() const { |
|
return UseDesugaredIterator && !DesugaredIterator.isEnd(); |
|
} |
|
|
|
/// getDesugaredTA - Returns the desugared TemplateArgument. |
|
reference getDesugaredTA() const { |
|
assert(UseDesugaredIterator && |
|
"Desugared TemplateArgument should not be used."); |
|
return *DesugaredIterator; |
|
} |
|
}; |
|
|
|
// These functions build up the template diff tree, including functions to |
|
// retrieve and compare template arguments. |
|
|
|
static const TemplateSpecializationType *GetTemplateSpecializationType( |
|
ASTContext &Context, QualType Ty) { |
|
if (const TemplateSpecializationType *TST = |
|
Ty->getAs<TemplateSpecializationType>()) |
|
return TST; |
|
|
|
const RecordType *RT = Ty->getAs<RecordType>(); |
|
|
|
if (!RT) |
|
return nullptr; |
|
|
|
const ClassTemplateSpecializationDecl *CTSD = |
|
dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()); |
|
|
|
if (!CTSD) |
|
return nullptr; |
|
|
|
Ty = Context.getTemplateSpecializationType( |
|
TemplateName(CTSD->getSpecializedTemplate()), |
|
CTSD->getTemplateArgs().asArray(), |
|
Ty.getLocalUnqualifiedType().getCanonicalType()); |
|
|
|
return Ty->getAs<TemplateSpecializationType>(); |
|
} |
|
|
|
/// Returns true if the DiffType is Type and false for Template. |
|
static bool OnlyPerformTypeDiff(ASTContext &Context, QualType FromType, |
|
QualType ToType, |
|
const TemplateSpecializationType *&FromArgTST, |
|
const TemplateSpecializationType *&ToArgTST) { |
|
if (FromType.isNull() || ToType.isNull()) |
|
return true; |
|
|
|
if (Context.hasSameType(FromType, ToType)) |
|
return true; |
|
|
|
FromArgTST = GetTemplateSpecializationType(Context, FromType); |
|
ToArgTST = GetTemplateSpecializationType(Context, ToType); |
|
|
|
if (!FromArgTST || !ToArgTST) |
|
return true; |
|
|
|
if (!hasSameTemplate(FromArgTST, ToArgTST)) |
|
return true; |
|
|
|
return false; |
|
} |
|
|
|
/// DiffTypes - Fills a DiffNode with information about a type difference. |
|
void DiffTypes(const TSTiterator &FromIter, const TSTiterator &ToIter) { |
|
QualType FromType = GetType(FromIter); |
|
QualType ToType = GetType(ToIter); |
|
|
|
bool FromDefault = FromIter.isEnd() && !FromType.isNull(); |
|
bool ToDefault = ToIter.isEnd() && !ToType.isNull(); |
|
|
|
const TemplateSpecializationType *FromArgTST = nullptr; |
|
const TemplateSpecializationType *ToArgTST = nullptr; |
|
if (OnlyPerformTypeDiff(Context, FromType, ToType, FromArgTST, ToArgTST)) { |
|
Tree.SetTypeDiff(FromType, ToType, FromDefault, ToDefault); |
|
Tree.SetSame(!FromType.isNull() && !ToType.isNull() && |
|
Context.hasSameType(FromType, ToType)); |
|
} else { |
|
assert(FromArgTST && ToArgTST && |
|
"Both template specializations need to be valid."); |
|
Qualifiers FromQual = FromType.getQualifiers(), |
|
ToQual = ToType.getQualifiers(); |
|
FromQual -= QualType(FromArgTST, 0).getQualifiers(); |
|
ToQual -= QualType(ToArgTST, 0).getQualifiers(); |
|
Tree.SetTemplateDiff(FromArgTST->getTemplateName().getAsTemplateDecl(), |
|
ToArgTST->getTemplateName().getAsTemplateDecl(), |
|
FromQual, ToQual, FromDefault, ToDefault); |
|
DiffTemplate(FromArgTST, ToArgTST); |
|
} |
|
} |
|
|
|
/// DiffTemplateTemplates - Fills a DiffNode with information about a |
|
/// template template difference. |
|
void DiffTemplateTemplates(const TSTiterator &FromIter, |
|
const TSTiterator &ToIter) { |
|
TemplateDecl *FromDecl = GetTemplateDecl(FromIter); |
|
TemplateDecl *ToDecl = GetTemplateDecl(ToIter); |
|
Tree.SetTemplateTemplateDiff(FromDecl, ToDecl, FromIter.isEnd() && FromDecl, |
|
ToIter.isEnd() && ToDecl); |
|
Tree.SetSame(FromDecl && ToDecl && |
|
FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl()); |
|
} |
|
|
|
/// InitializeNonTypeDiffVariables - Helper function for DiffNonTypes |
|
static void InitializeNonTypeDiffVariables(ASTContext &Context, |
|
const TSTiterator &Iter, |
|
NonTypeTemplateParmDecl *Default, |
|
llvm::APSInt &Value, bool &HasInt, |
|
QualType &IntType, bool &IsNullPtr, |
|
Expr *&E, ValueDecl *&VD, |
|
bool &NeedAddressOf) { |
|
if (!Iter.isEnd()) { |
|
switch (Iter->getKind()) { |
|
default: |
|
llvm_unreachable("unknown ArgumentKind"); |
|
case TemplateArgument::Integral: |
|
Value = Iter->getAsIntegral(); |
|
HasInt = true; |
|
IntType = Iter->getIntegralType(); |
|
return; |
|
case TemplateArgument::Declaration: { |
|
VD = Iter->getAsDecl(); |
|
QualType ArgType = Iter->getParamTypeForDecl(); |
|
QualType VDType = VD->getType(); |
|
if (ArgType->isPointerType() && |
|
Context.hasSameType(ArgType->getPointeeType(), VDType)) |
|
NeedAddressOf = true; |
|
return; |
|
} |
|
case TemplateArgument::NullPtr: |
|
IsNullPtr = true; |
|
return; |
|
case TemplateArgument::Expression: |
|
E = Iter->getAsExpr(); |
|
} |
|
} else if (!Default->isParameterPack()) { |
|
E = Default->getDefaultArgument(); |
|
} |
|
|
|
if (!Iter.hasDesugaredTA()) return; |
|
|
|
const TemplateArgument& TA = Iter.getDesugaredTA(); |
|
switch (TA.getKind()) { |
|
default: |
|
llvm_unreachable("unknown ArgumentKind"); |
|
case TemplateArgument::Integral: |
|
Value = TA.getAsIntegral(); |
|
HasInt = true; |
|
IntType = TA.getIntegralType(); |
|
return; |
|
case TemplateArgument::Declaration: { |
|
VD = TA.getAsDecl(); |
|
QualType ArgType = TA.getParamTypeForDecl(); |
|
QualType VDType = VD->getType(); |
|
if (ArgType->isPointerType() && |
|
Context.hasSameType(ArgType->getPointeeType(), VDType)) |
|
NeedAddressOf = true; |
|
return; |
|
} |
|
case TemplateArgument::NullPtr: |
|
IsNullPtr = true; |
|
return; |
|
case TemplateArgument::Expression: |
|
// TODO: Sometimes, the desugared template argument Expr differs from |
|
// the sugared template argument Expr. It may be useful in the future |
|
// but for now, it is just discarded. |
|
if (!E) |
|
E = TA.getAsExpr(); |
|
return; |
|
} |
|
} |
|
|
|
/// DiffNonTypes - Handles any template parameters not handled by DiffTypes |
|
/// of DiffTemplatesTemplates, such as integer and declaration parameters. |
|
void DiffNonTypes(const TSTiterator &FromIter, const TSTiterator &ToIter, |
|
NonTypeTemplateParmDecl *FromDefaultNonTypeDecl, |
|
NonTypeTemplateParmDecl *ToDefaultNonTypeDecl) { |
|
Expr *FromExpr = nullptr, *ToExpr = nullptr; |
|
llvm::APSInt FromInt, ToInt; |
|
QualType FromIntType, ToIntType; |
|
ValueDecl *FromValueDecl = nullptr, *ToValueDecl = nullptr; |
|
bool HasFromInt = false, HasToInt = false, FromNullPtr = false, |
|
ToNullPtr = false, NeedFromAddressOf = false, NeedToAddressOf = false; |
|
InitializeNonTypeDiffVariables( |
|
Context, FromIter, FromDefaultNonTypeDecl, FromInt, HasFromInt, |
|
FromIntType, FromNullPtr, FromExpr, FromValueDecl, NeedFromAddressOf); |
|
InitializeNonTypeDiffVariables(Context, ToIter, ToDefaultNonTypeDecl, ToInt, |
|
HasToInt, ToIntType, ToNullPtr, ToExpr, |
|
ToValueDecl, NeedToAddressOf); |
|
|
|
bool FromDefault = FromIter.isEnd() && |
|
(FromExpr || FromValueDecl || HasFromInt || FromNullPtr); |
|
bool ToDefault = ToIter.isEnd() && |
|
(ToExpr || ToValueDecl || HasToInt || ToNullPtr); |
|
|
|
bool FromDeclaration = FromValueDecl || FromNullPtr; |
|
bool ToDeclaration = ToValueDecl || ToNullPtr; |
|
|
|
if (FromDeclaration && HasToInt) { |
|
Tree.SetFromDeclarationAndToIntegerDiff( |
|
FromValueDecl, NeedFromAddressOf, FromNullPtr, FromExpr, ToInt, |
|
HasToInt, ToIntType, ToExpr, FromDefault, ToDefault); |
|
Tree.SetSame(false); |
|
return; |
|
|
|
} |
|
|
|
if (HasFromInt && ToDeclaration) { |
|
Tree.SetFromIntegerAndToDeclarationDiff( |
|
FromInt, HasFromInt, FromIntType, FromExpr, ToValueDecl, |
|
NeedToAddressOf, ToNullPtr, ToExpr, FromDefault, ToDefault); |
|
Tree.SetSame(false); |
|
return; |
|
} |
|
|
|
if (HasFromInt || HasToInt) { |
|
Tree.SetIntegerDiff(FromInt, ToInt, HasFromInt, HasToInt, FromIntType, |
|
ToIntType, FromExpr, ToExpr, FromDefault, ToDefault); |
|
if (HasFromInt && HasToInt) { |
|
Tree.SetSame(Context.hasSameType(FromIntType, ToIntType) && |
|
FromInt == ToInt); |
|
} |
|
return; |
|
} |
|
|
|
if (FromDeclaration || ToDeclaration) { |
|
Tree.SetDeclarationDiff(FromValueDecl, ToValueDecl, NeedFromAddressOf, |
|
NeedToAddressOf, FromNullPtr, ToNullPtr, FromExpr, |
|
ToExpr, FromDefault, ToDefault); |
|
bool BothNull = FromNullPtr && ToNullPtr; |
|
bool SameValueDecl = |
|
FromValueDecl && ToValueDecl && |
|
NeedFromAddressOf == NeedToAddressOf && |
|
FromValueDecl->getCanonicalDecl() == ToValueDecl->getCanonicalDecl(); |
|
Tree.SetSame(BothNull || SameValueDecl); |
|
return; |
|
} |
|
|
|
assert((FromExpr || ToExpr) && "Both template arguments cannot be empty."); |
|
Tree.SetExpressionDiff(FromExpr, ToExpr, FromDefault, ToDefault); |
|
Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr)); |
|
} |
|
|
|
/// DiffTemplate - recursively visits template arguments and stores the |
|
/// argument info into a tree. |
|
void DiffTemplate(const TemplateSpecializationType *FromTST, |
|
const TemplateSpecializationType *ToTST) { |
|
// Begin descent into diffing template tree. |
|
TemplateParameterList *ParamsFrom = |
|
FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters(); |
|
TemplateParameterList *ParamsTo = |
|
ToTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters(); |
|
unsigned TotalArgs = 0; |
|
for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST); |
|
!FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) { |
|
Tree.AddNode(); |
|
|
|
// Get the parameter at index TotalArgs. If index is larger |
|
// than the total number of parameters, then there is an |
|
// argument pack, so re-use the last parameter. |
|
unsigned FromParamIndex = std::min(TotalArgs, ParamsFrom->size() - 1); |
|
unsigned ToParamIndex = std::min(TotalArgs, ParamsTo->size() - 1); |
|
NamedDecl *FromParamND = ParamsFrom->getParam(FromParamIndex); |
|
NamedDecl *ToParamND = ParamsTo->getParam(ToParamIndex); |
|
|
|
assert(FromParamND->getKind() == ToParamND->getKind() && |
|
"Parameter Decl are not the same kind."); |
|
|
|
if (isa<TemplateTypeParmDecl>(FromParamND)) { |
|
DiffTypes(FromIter, ToIter); |
|
} else if (isa<TemplateTemplateParmDecl>(FromParamND)) { |
|
DiffTemplateTemplates(FromIter, ToIter); |
|
} else if (isa<NonTypeTemplateParmDecl>(FromParamND)) { |
|
NonTypeTemplateParmDecl *FromDefaultNonTypeDecl = |
|
cast<NonTypeTemplateParmDecl>(FromParamND); |
|
NonTypeTemplateParmDecl *ToDefaultNonTypeDecl = |
|
cast<NonTypeTemplateParmDecl>(ToParamND); |
|
DiffNonTypes(FromIter, ToIter, FromDefaultNonTypeDecl, |
|
ToDefaultNonTypeDecl); |
|
} else { |
|
llvm_unreachable("Unexpected Decl type."); |
|
} |
|
|
|
++FromIter; |
|
++ToIter; |
|
Tree.Up(); |
|
} |
|
} |
|
|
|
/// makeTemplateList - Dump every template alias into the vector. |
|
static void makeTemplateList( |
|
SmallVectorImpl<const TemplateSpecializationType *> &TemplateList, |
|
const TemplateSpecializationType *TST) { |
|
while (TST) { |
|
TemplateList.push_back(TST); |
|
if (!TST->isTypeAlias()) |
|
return; |
|
TST = TST->getAliasedType()->getAs<TemplateSpecializationType>(); |
|
} |
|
} |
|
|
|
/// hasSameBaseTemplate - Returns true when the base templates are the same, |
|
/// even if the template arguments are not. |
|
static bool hasSameBaseTemplate(const TemplateSpecializationType *FromTST, |
|
const TemplateSpecializationType *ToTST) { |
|
return FromTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl() == |
|
ToTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl(); |
|
} |
|
|
|
/// hasSameTemplate - Returns true if both types are specialized from the |
|
/// same template declaration. If they come from different template aliases, |
|
/// do a parallel ascension search to determine the highest template alias in |
|
/// common and set the arguments to them. |
|
static bool hasSameTemplate(const TemplateSpecializationType *&FromTST, |
|
const TemplateSpecializationType *&ToTST) { |
|
// Check the top templates if they are the same. |
|
if (hasSameBaseTemplate(FromTST, ToTST)) |
|
return true; |
|
|
|
// Create vectors of template aliases. |
|
SmallVector<const TemplateSpecializationType*, 1> FromTemplateList, |
|
ToTemplateList; |
|
|
|
makeTemplateList(FromTemplateList, FromTST); |
|
makeTemplateList(ToTemplateList, ToTST); |
|
|
|
SmallVectorImpl<const TemplateSpecializationType *>::reverse_iterator |
|
FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(), |
|
ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend(); |
|
|
|
// Check if the lowest template types are the same. If not, return. |
|
if (!hasSameBaseTemplate(*FromIter, *ToIter)) |
|
return false; |
|
|
|
// Begin searching up the template aliases. The bottom most template |
|
// matches so move up until one pair does not match. Use the template |
|
// right before that one. |
|
for (; FromIter != FromEnd && ToIter != ToEnd; ++FromIter, ++ToIter) { |
|
if (!hasSameBaseTemplate(*FromIter, *ToIter)) |
|
break; |
|
} |
|
|
|
FromTST = FromIter[-1]; |
|
ToTST = ToIter[-1]; |
|
|
|
return true; |
|
} |
|
|
|
/// GetType - Retrieves the template type arguments, including default |
|
/// arguments. |
|
static QualType GetType(const TSTiterator &Iter) { |
|
if (!Iter.isEnd()) |
|
return Iter->getAsType(); |
|
if (Iter.hasDesugaredTA()) |
|
return Iter.getDesugaredTA().getAsType(); |
|
return QualType(); |
|
} |
|
|
|
/// GetTemplateDecl - Retrieves the template template arguments, including |
|
/// default arguments. |
|
static TemplateDecl *GetTemplateDecl(const TSTiterator &Iter) { |
|
if (!Iter.isEnd()) |
|
return Iter->getAsTemplate().getAsTemplateDecl(); |
|
if (Iter.hasDesugaredTA()) |
|
return Iter.getDesugaredTA().getAsTemplate().getAsTemplateDecl(); |
|
return nullptr; |
|
} |
|
|
|
/// IsEqualExpr - Returns true if the expressions are the same in regards to |
|
/// template arguments. These expressions are dependent, so profile them |
|
/// instead of trying to evaluate them. |
|
static bool IsEqualExpr(ASTContext &Context, Expr *FromExpr, Expr *ToExpr) { |
|
if (FromExpr == ToExpr) |
|
return true; |
|
|
|
if (!FromExpr || !ToExpr) |
|
return false; |
|
|
|
llvm::FoldingSetNodeID FromID, ToID; |
|
FromExpr->Profile(FromID, Context, true); |
|
ToExpr->Profile(ToID, Context, true); |
|
return FromID == ToID; |
|
} |
|
|
|
// These functions converts the tree representation of the template |
|
// differences into the internal character vector. |
|
|
|
/// TreeToString - Converts the Tree object into a character stream which |
|
/// will later be turned into the output string. |
|
void TreeToString(int Indent = 1) { |
|
if (PrintTree) { |
|
OS << '\n'; |
|
OS.indent(2 * Indent); |
|
++Indent; |
|
} |
|
|
|
// Handle cases where the difference is not templates with different |
|
// arguments. |
|
switch (Tree.GetKind()) { |
|
case DiffTree::Invalid: |
|
llvm_unreachable("Template diffing failed with bad DiffNode"); |
|
case DiffTree::Type: { |
|
QualType FromType, ToType; |
|
Tree.GetTypeDiff(FromType, ToType); |
|
PrintTypeNames(FromType, ToType, Tree.FromDefault(), Tree.ToDefault(), |
|
Tree.NodeIsSame()); |
|
return; |
|
} |
|
case DiffTree::Expression: { |
|
Expr *FromExpr, *ToExpr; |
|
Tree.GetExpressionDiff(FromExpr, ToExpr); |
|
PrintExpr(FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(), |
|
Tree.NodeIsSame()); |
|
return; |
|
} |
|
case DiffTree::TemplateTemplate: { |
|
TemplateDecl *FromTD, *ToTD; |
|
Tree.GetTemplateTemplateDiff(FromTD, ToTD); |
|
PrintTemplateTemplate(FromTD, ToTD, Tree.FromDefault(), |
|
Tree.ToDefault(), Tree.NodeIsSame()); |
|
return; |
|
} |
|
case DiffTree::Integer: { |
|
llvm::APSInt FromInt, ToInt; |
|
Expr *FromExpr, *ToExpr; |
|
bool IsValidFromInt, IsValidToInt; |
|
QualType FromIntType, ToIntType; |
|
Tree.GetIntegerDiff(FromInt, ToInt, IsValidFromInt, IsValidToInt, |
|
FromIntType, ToIntType, FromExpr, ToExpr); |
|
PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt, FromIntType, |
|
ToIntType, FromExpr, ToExpr, Tree.FromDefault(), |
|
Tree.ToDefault(), Tree.NodeIsSame()); |
|
return; |
|
} |
|
case DiffTree::Declaration: { |
|
ValueDecl *FromValueDecl, *ToValueDecl; |
|
bool FromAddressOf, ToAddressOf; |
|
bool FromNullPtr, ToNullPtr; |
|
Expr *FromExpr, *ToExpr; |
|
Tree.GetDeclarationDiff(FromValueDecl, ToValueDecl, FromAddressOf, |
|
ToAddressOf, FromNullPtr, ToNullPtr, FromExpr, |
|
ToExpr); |
|
PrintValueDecl(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf, |
|
FromNullPtr, ToNullPtr, FromExpr, ToExpr, |
|
Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); |
|
return; |
|
} |
|
case DiffTree::FromDeclarationAndToInteger: { |
|
ValueDecl *FromValueDecl; |
|
bool FromAddressOf; |
|
bool FromNullPtr; |
|
Expr *FromExpr; |
|
llvm::APSInt ToInt; |
|
bool IsValidToInt; |
|
QualType ToIntType; |
|
Expr *ToExpr; |
|
Tree.GetFromDeclarationAndToIntegerDiff( |
|
FromValueDecl, FromAddressOf, FromNullPtr, FromExpr, ToInt, |
|
IsValidToInt, ToIntType, ToExpr); |
|
assert((FromValueDecl || FromNullPtr) && IsValidToInt); |
|
PrintValueDeclAndInteger(FromValueDecl, FromAddressOf, FromNullPtr, |
|
FromExpr, Tree.FromDefault(), ToInt, ToIntType, |
|
ToExpr, Tree.ToDefault()); |
|
return; |
|
} |
|
case DiffTree::FromIntegerAndToDeclaration: { |
|
llvm::APSInt FromInt; |
|
bool IsValidFromInt; |
|
QualType FromIntType; |
|
Expr *FromExpr; |
|
ValueDecl *ToValueDecl; |
|
bool ToAddressOf; |
|
bool ToNullPtr; |
|
Expr *ToExpr; |
|
Tree.GetFromIntegerAndToDeclarationDiff( |
|
FromInt, IsValidFromInt, FromIntType, FromExpr, ToValueDecl, |
|
ToAddressOf, ToNullPtr, ToExpr); |
|
assert(IsValidFromInt && (ToValueDecl || ToNullPtr)); |
|
PrintIntegerAndValueDecl(FromInt, FromIntType, FromExpr, |
|
Tree.FromDefault(), ToValueDecl, ToAddressOf, |
|
ToNullPtr, ToExpr, Tree.ToDefault()); |
|
return; |
|
} |
|
case DiffTree::Template: { |
|
// Node is root of template. Recurse on children. |
|
TemplateDecl *FromTD, *ToTD; |
|
Qualifiers FromQual, ToQual; |
|
Tree.GetTemplateDiff(FromTD, ToTD, FromQual, ToQual); |
|
|
|
PrintQualifiers(FromQual, ToQual); |
|
|
|
if (!Tree.HasChildren()) { |
|
// If we're dealing with a template specialization with zero |
|
// arguments, there are no children; special-case this. |
|
OS << FromTD->getNameAsString() << "<>"; |
|
return; |
|
} |
|
|
|
OS << FromTD->getNameAsString() << '<'; |
|
Tree.MoveToChild(); |
|
unsigned NumElideArgs = 0; |
|
bool AllArgsElided = true; |
|
do { |
|
if (ElideType) { |
|
if (Tree.NodeIsSame()) { |
|
++NumElideArgs; |
|
continue; |
|
} |
|
AllArgsElided = false; |
|
if (NumElideArgs > 0) { |
|
PrintElideArgs(NumElideArgs, Indent); |
|
NumElideArgs = 0; |
|
OS << ", "; |
|
} |
|
} |
|
TreeToString(Indent); |
|
if (Tree.HasNextSibling()) |
|
OS << ", "; |
|
} while (Tree.AdvanceSibling()); |
|
if (NumElideArgs > 0) { |
|
if (AllArgsElided) |
|
OS << "..."; |
|
else |
|
PrintElideArgs(NumElideArgs, Indent); |
|
} |
|
|
|
Tree.Parent(); |
|
OS << ">"; |
|
return; |
|
} |
|
} |
|
} |
|
|
|
// To signal to the text printer that a certain text needs to be bolded, |
|
// a special character is injected into the character stream which the |
|
// text printer will later strip out. |
|
|
|
/// Bold - Start bolding text. |
|
void Bold() { |
|
assert(!IsBold && "Attempting to bold text that is already bold."); |
|
IsBold = true; |
|
if (ShowColor) |
|
OS << ToggleHighlight; |
|
} |
|
|
|
/// Unbold - Stop bolding text. |
|
void Unbold() { |
|
assert(IsBold && "Attempting to remove bold from unbold text."); |
|
IsBold = false; |
|
if (ShowColor) |
|
OS << ToggleHighlight; |
|
} |
|
|
|
// Functions to print out the arguments and highlighting the difference. |
|
|
|
/// PrintTypeNames - prints the typenames, bolding differences. Will detect |
|
/// typenames that are the same and attempt to disambiguate them by using |
|
/// canonical typenames. |
|
void PrintTypeNames(QualType FromType, QualType ToType, |
|
bool FromDefault, bool ToDefault, bool Same) { |
|
assert((!FromType.isNull() || !ToType.isNull()) && |
|
"Only one template argument may be missing."); |
|
|
|
if (Same) { |
|
OS << FromType.getAsString(Policy); |
|
return; |
|
} |
|
|
|
if (!FromType.isNull() && !ToType.isNull() && |
|
FromType.getLocalUnqualifiedType() == |
|
ToType.getLocalUnqualifiedType()) { |
|
Qualifiers FromQual = FromType.getLocalQualifiers(), |
|
ToQual = ToType.getLocalQualifiers(); |
|
PrintQualifiers(FromQual, ToQual); |
|
FromType.getLocalUnqualifiedType().print(OS, Policy); |
|
return; |
|
} |
|
|
|
std::string FromTypeStr = FromType.isNull() ? "(no argument)" |
|
: FromType.getAsString(Policy); |
|
std::string ToTypeStr = ToType.isNull() ? "(no argument)" |
|
: ToType.getAsString(Policy); |
|
// Switch to canonical typename if it is better. |
|
// TODO: merge this with other aka printing above. |
|
if (FromTypeStr == ToTypeStr) { |
|
std::string FromCanTypeStr = |
|
FromType.getCanonicalType().getAsString(Policy); |
|
std::string ToCanTypeStr = ToType.getCanonicalType().getAsString(Policy); |
|
if (FromCanTypeStr != ToCanTypeStr) { |
|
FromTypeStr = FromCanTypeStr; |
|
ToTypeStr = ToCanTypeStr; |
|
} |
|
} |
|
|
|
if (PrintTree) OS << '['; |
|
OS << (FromDefault ? "(default) " : ""); |
|
Bold(); |
|
OS << FromTypeStr; |
|
Unbold(); |
|
if (PrintTree) { |
|
OS << " != " << (ToDefault ? "(default) " : ""); |
|
Bold(); |
|
OS << ToTypeStr; |
|
Unbold(); |
|
OS << "]"; |
|
} |
|
} |
|
|
|
/// PrintExpr - Prints out the expr template arguments, highlighting argument |
|
/// differences. |
|
void PrintExpr(const Expr *FromExpr, const Expr *ToExpr, bool FromDefault, |
|
bool ToDefault, bool Same) { |
|
assert((FromExpr || ToExpr) && |
|
"Only one template argument may be missing."); |
|
if (Same) { |
|
PrintExpr(FromExpr); |
|
} else if (!PrintTree) { |
|
OS << (FromDefault ? "(default) " : ""); |
|
Bold(); |
|
PrintExpr(FromExpr); |
|
Unbold(); |
|
} else { |
|
OS << (FromDefault ? "[(default) " : "["); |
|
Bold(); |
|
PrintExpr(FromExpr); |
|
Unbold(); |
|
OS << " != " << (ToDefault ? "(default) " : ""); |
|
Bold(); |
|
PrintExpr(ToExpr); |
|
Unbold(); |
|
OS << ']'; |
|
} |
|
} |
|
|
|
/// PrintExpr - Actual formatting and printing of expressions. |
|
void PrintExpr(const Expr *E) { |
|
if (E) { |
|
E->printPretty(OS, nullptr, Policy); |
|
return; |
|
} |
|
OS << "(no argument)"; |
|
} |
|
|
|
/// PrintTemplateTemplate - Handles printing of template template arguments, |
|
/// highlighting argument differences. |
|
void PrintTemplateTemplate(TemplateDecl *FromTD, TemplateDecl *ToTD, |
|
bool FromDefault, bool ToDefault, bool Same) { |
|
assert((FromTD || ToTD) && "Only one template argument may be missing."); |
|
|
|
std::string FromName = FromTD ? FromTD->getName() : "(no argument)"; |
|
std::string ToName = ToTD ? ToTD->getName() : "(no argument)"; |
|
if (FromTD && ToTD && FromName == ToName) { |
|
FromName = FromTD->getQualifiedNameAsString(); |
|
ToName = ToTD->getQualifiedNameAsString(); |
|
} |
|
|
|
if (Same) { |
|
OS << "template " << FromTD->getNameAsString(); |
|
} else if (!PrintTree) { |
|
OS << (FromDefault ? "(default) template " : "template "); |
|
Bold(); |
|
OS << FromName; |
|
Unbold(); |
|
} else { |
|
OS << (FromDefault ? "[(default) template " : "[template "); |
|
Bold(); |
|
OS << FromName; |
|
Unbold(); |
|
OS << " != " << (ToDefault ? "(default) template " : "template "); |
|
Bold(); |
|
OS << ToName; |
|
Unbold(); |
|
OS << ']'; |
|
} |
|
} |
|
|
|
/// PrintAPSInt - Handles printing of integral arguments, highlighting |
|
/// argument differences. |
|
void PrintAPSInt(const llvm::APSInt &FromInt, const llvm::APSInt &ToInt, |
|
bool IsValidFromInt, bool IsValidToInt, QualType FromIntType, |
|
QualType ToIntType, Expr *FromExpr, Expr *ToExpr, |
|
bool FromDefault, bool ToDefault, bool Same) { |
|
assert((IsValidFromInt || IsValidToInt) && |
|
"Only one integral argument may be missing."); |
|
|
|
if (Same) { |
|
if (FromIntType->isBooleanType()) { |
|
OS << ((FromInt == 0) ? "false" : "true"); |
|
} else { |
|
OS << FromInt.toString(10); |
|
} |
|
return; |
|
} |
|
|
|
bool PrintType = IsValidFromInt && IsValidToInt && |
|
!Context.hasSameType(FromIntType, ToIntType); |
|
|
|
if (!PrintTree) { |
|
OS << (FromDefault ? "(default) " : ""); |
|
PrintAPSInt(FromInt, FromExpr, IsValidFromInt, FromIntType, PrintType); |
|
} else { |
|
OS << (FromDefault ? "[(default) " : "["); |
|
PrintAPSInt(FromInt, FromExpr, IsValidFromInt, FromIntType, PrintType); |
|
OS << " != " << (ToDefault ? "(default) " : ""); |
|
PrintAPSInt(ToInt, ToExpr, IsValidToInt, ToIntType, PrintType); |
|
OS << ']'; |
|
} |
|
} |
|
|
|
/// PrintAPSInt - If valid, print the APSInt. If the expression is |
|
/// gives more information, print it too. |
|
void PrintAPSInt(const llvm::APSInt &Val, Expr *E, bool Valid, |
|
QualType IntType, bool PrintType) { |
|
Bold(); |
|
if (Valid) { |
|
if (HasExtraInfo(E)) { |
|
PrintExpr(E); |
|
Unbold(); |
|
OS << " aka "; |
|
Bold(); |
|
} |
|
if (PrintType) { |
|
Unbold(); |
|
OS << "("; |
|
Bold(); |
|
IntType.print(OS, Context.getPrintingPolicy()); |
|
Unbold(); |
|
OS << ") "; |
|
Bold(); |
|
} |
|
if (IntType->isBooleanType()) { |
|
OS << ((Val == 0) ? "false" : "true"); |
|
} else { |
|
OS << Val.toString(10); |
|
} |
|
} else if (E) { |
|
PrintExpr(E); |
|
} else { |
|
OS << "(no argument)"; |
|
} |
|
Unbold(); |
|
} |
|
|
|
/// HasExtraInfo - Returns true if E is not an integer literal, the |
|
/// negation of an integer literal, or a boolean literal. |
|
bool HasExtraInfo(Expr *E) { |
|
if (!E) return false; |
|
|
|
E = E->IgnoreImpCasts(); |
|
|
|
if (isa<IntegerLiteral>(E)) return false; |
|
|
|
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) |
|
if (UO->getOpcode() == UO_Minus) |
|
if (isa<IntegerLiteral>(UO->getSubExpr())) |
|
return false; |
|
|
|
if (isa<CXXBoolLiteralExpr>(E)) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
void PrintValueDecl(ValueDecl *VD, bool AddressOf, Expr *E, bool NullPtr) { |
|
if (VD) { |
|
if (AddressOf) |
|
OS << "&"; |
|
OS << VD->getName(); |
|
return; |
|
} |
|
|
|
if (NullPtr) { |
|
if (E && !isa<CXXNullPtrLiteralExpr>(E)) { |
|
PrintExpr(E); |
|
if (IsBold) { |
|
Unbold(); |
|
OS << " aka "; |
|
Bold(); |
|
} else { |
|
OS << " aka "; |
|
} |
|
} |
|
|
|
OS << "nullptr"; |
|
return; |
|
} |
|
|
|
OS << "(no argument)"; |
|
} |
|
|
|
/// PrintDecl - Handles printing of Decl arguments, highlighting |
|
/// argument differences. |
|
void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl, |
|
bool FromAddressOf, bool ToAddressOf, bool FromNullPtr, |
|
bool ToNullPtr, Expr *FromExpr, Expr *ToExpr, |
|
bool FromDefault, bool ToDefault, bool Same) { |
|
assert((FromValueDecl || FromNullPtr || ToValueDecl || ToNullPtr) && |
|
"Only one Decl argument may be NULL"); |
|
|
|
if (Same) { |
|
PrintValueDecl(FromValueDecl, FromAddressOf, FromExpr, FromNullPtr); |
|
} else if (!PrintTree) { |
|
OS << (FromDefault ? "(default) " : ""); |
|
Bold(); |
|
PrintValueDecl(FromValueDecl, FromAddressOf, FromExpr, FromNullPtr); |
|
Unbold(); |
|
} else { |
|
OS << (FromDefault ? "[(default) " : "["); |
|
Bold(); |
|
PrintValueDecl(FromValueDecl, FromAddressOf, FromExpr, FromNullPtr); |
|
Unbold(); |
|
OS << " != " << (ToDefault ? "(default) " : ""); |
|
Bold(); |
|
PrintValueDecl(ToValueDecl, ToAddressOf, ToExpr, ToNullPtr); |
|
Unbold(); |
|
OS << ']'; |
|
} |
|
} |
|
|
|
/// PrintValueDeclAndInteger - Uses the print functions for ValueDecl and |
|
/// APSInt to print a mixed difference. |
|
void PrintValueDeclAndInteger(ValueDecl *VD, bool NeedAddressOf, |
|
bool IsNullPtr, Expr *VDExpr, bool DefaultDecl, |
|
const llvm::APSInt &Val, QualType IntType, |
|
Expr *IntExpr, bool DefaultInt) { |
|
if (!PrintTree) { |
|
OS << (DefaultDecl ? "(default) " : ""); |
|
Bold(); |
|
PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr); |
|
Unbold(); |
|
} else { |
|
OS << (DefaultDecl ? "[(default) " : "["); |
|
Bold(); |
|
PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr); |
|
Unbold(); |
|
OS << " != " << (DefaultInt ? "(default) " : ""); |
|
PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/); |
|
OS << ']'; |
|
} |
|
} |
|
|
|
/// PrintIntegerAndValueDecl - Uses the print functions for APSInt and |
|
/// ValueDecl to print a mixed difference. |
|
void PrintIntegerAndValueDecl(const llvm::APSInt &Val, QualType IntType, |
|
Expr *IntExpr, bool DefaultInt, ValueDecl *VD, |
|
bool NeedAddressOf, bool IsNullPtr, |
|
Expr *VDExpr, bool DefaultDecl) { |
|
if (!PrintTree) { |
|
OS << (DefaultInt ? "(default) " : ""); |
|
PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/); |
|
} else { |
|
OS << (DefaultInt ? "[(default) " : "["); |
|
PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/); |
|
OS << " != " << (DefaultDecl ? "(default) " : ""); |
|
Bold(); |
|
PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr); |
|
Unbold(); |
|
OS << ']'; |
|
} |
|
} |
|
|
|
// Prints the appropriate placeholder for elided template arguments. |
|
void PrintElideArgs(unsigned NumElideArgs, unsigned Indent) { |
|
if (PrintTree) { |
|
OS << '\n'; |
|
for (unsigned i = 0; i < Indent; ++i) |
|
OS << " "; |
|
} |
|
if (NumElideArgs == 0) return; |
|
if (NumElideArgs == 1) |
|
OS << "[...]"; |
|
else |
|
OS << "[" << NumElideArgs << " * ...]"; |
|
} |
|
|
|
// Prints and highlights differences in Qualifiers. |
|
void PrintQualifiers(Qualifiers FromQual, Qualifiers ToQual) { |
|
// Both types have no qualifiers |
|
if (FromQual.empty() && ToQual.empty()) |
|
return; |
|
|
|
// Both types have same qualifiers |
|
if (FromQual == ToQual) { |
|
PrintQualifier(FromQual, /*ApplyBold*/false); |
|
return; |
|
} |
|
|
|
// Find common qualifiers and strip them from FromQual and ToQual. |
|
Qualifiers CommonQual = Qualifiers::removeCommonQualifiers(FromQual, |
|
ToQual); |
|
|
|
// The qualifiers are printed before the template name. |
|
// Inline printing: |
|
// The common qualifiers are printed. Then, qualifiers only in this type |
|
// are printed and highlighted. Finally, qualifiers only in the other |
|
// type are printed and highlighted inside parentheses after "missing". |
|
// Tree printing: |
|
// Qualifiers are printed next to each other, inside brackets, and |
|
// separated by "!=". The printing order is: |
|
// common qualifiers, highlighted from qualifiers, "!=", |
|
// common qualifiers, highlighted to qualifiers |
|
if (PrintTree) { |
|
OS << "["; |
|
if (CommonQual.empty() && FromQual.empty()) { |
|
Bold(); |
|
OS << "(no qualifiers) "; |
|
Unbold(); |
|
} else { |
|
PrintQualifier(CommonQual, /*ApplyBold*/false); |
|
PrintQualifier(FromQual, /*ApplyBold*/true); |
|
} |
|
OS << "!= "; |
|
if (CommonQual.empty() && ToQual.empty()) { |
|
Bold(); |
|
OS << "(no qualifiers)"; |
|
Unbold(); |
|
} else { |
|
PrintQualifier(CommonQual, /*ApplyBold*/false, |
|
/*appendSpaceIfNonEmpty*/!ToQual.empty()); |
|
PrintQualifier(ToQual, /*ApplyBold*/true, |
|
/*appendSpaceIfNonEmpty*/false); |
|
} |
|
OS << "] "; |
|
} else { |
|
PrintQualifier(CommonQual, /*ApplyBold*/false); |
|
PrintQualifier(FromQual, /*ApplyBold*/true); |
|
} |
|
} |
|
|
|
void PrintQualifier(Qualifiers Q, bool ApplyBold, |
|
bool AppendSpaceIfNonEmpty = true) { |
|
if (Q.empty()) return; |
|
if (ApplyBold) Bold(); |
|
Q.print(OS, Policy, AppendSpaceIfNonEmpty); |
|
if (ApplyBold) Unbold(); |
|
} |
|
|
|
public: |
|
|
|
TemplateDiff(raw_ostream &OS, ASTContext &Context, QualType FromType, |
|
QualType ToType, bool PrintTree, bool PrintFromType, |
|
bool ElideType, bool ShowColor) |
|
: Context(Context), |
|
Policy(Context.getLangOpts()), |
|
ElideType(ElideType), |
|
PrintTree(PrintTree), |
|
ShowColor(ShowColor), |
|
// When printing a single type, the FromType is the one printed. |
|
FromTemplateType(PrintFromType ? FromType : ToType), |
|
ToTemplateType(PrintFromType ? ToType : FromType), |
|
OS(OS), |
|
IsBold(false) { |
|
} |
|
|
|
/// DiffTemplate - Start the template type diffing. |
|
void DiffTemplate() { |
|
Qualifiers FromQual = FromTemplateType.getQualifiers(), |
|
ToQual = ToTemplateType.getQualifiers(); |
|
|
|
const TemplateSpecializationType *FromOrigTST = |
|
GetTemplateSpecializationType(Context, FromTemplateType); |
|
const TemplateSpecializationType *ToOrigTST = |
|
GetTemplateSpecializationType(Context, ToTemplateType); |
|
|
|
// Only checking templates. |
|
if (!FromOrigTST || !ToOrigTST) |
|
return; |
|
|
|
// Different base templates. |
|
if (!hasSameTemplate(FromOrigTST, ToOrigTST)) { |
|
return; |
|
} |
|
|
|
FromQual -= QualType(FromOrigTST, 0).getQualifiers(); |
|
ToQual -= QualType(ToOrigTST, 0).getQualifiers(); |
|
|
|
// Same base template, but different arguments. |
|
Tree.SetTemplateDiff(FromOrigTST->getTemplateName().getAsTemplateDecl(), |
|
ToOrigTST->getTemplateName().getAsTemplateDecl(), |
|
FromQual, ToQual, false /*FromDefault*/, |
|
false /*ToDefault*/); |
|
|
|
DiffTemplate(FromOrigTST, ToOrigTST); |
|
} |
|
|
|
/// Emit - When the two types given are templated types with the same |
|
/// base template, a string representation of the type difference will be |
|
/// emitted to the stream and return true. Otherwise, return false. |
|
bool Emit() { |
|
Tree.StartTraverse(); |
|
if (Tree.Empty()) |
|
return false; |
|
|
|
TreeToString(); |
|
assert(!IsBold && "Bold is applied to end of string."); |
|
return true; |
|
} |
|
}; // end class TemplateDiff |
|
} // end anonymous namespace |
|
|
|
/// FormatTemplateTypeDiff - A helper static function to start the template |
|
/// diff and return the properly formatted string. Returns true if the diff |
|
/// is successful. |
|
static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType, |
|
QualType ToType, bool PrintTree, |
|
bool PrintFromType, bool ElideType, |
|
bool ShowColors, raw_ostream &OS) { |
|
if (PrintTree) |
|
PrintFromType = true; |
|
TemplateDiff TD(OS, Context, FromType, ToType, PrintTree, PrintFromType, |
|
ElideType, ShowColors); |
|
TD.DiffTemplate(); |
|
return TD.Emit(); |
|
}
|
|
|