diff options
-rw-r--r-- | include/clang/Basic/Diagnostic.h | 38 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | include/clang/Driver/Options.td | 6 | ||||
-rw-r--r-- | include/clang/Frontend/DiagnosticOptions.h | 3 | ||||
-rw-r--r-- | lib/AST/ASTDiagnostic.cpp | 933 | ||||
-rw-r--r-- | lib/Basic/Diagnostic.cpp | 79 | ||||
-rw-r--r-- | lib/Driver/Tools.cpp | 2 | ||||
-rw-r--r-- | lib/Frontend/CompilerInvocation.cpp | 2 | ||||
-rw-r--r-- | lib/Frontend/TextDiagnostic.cpp | 28 | ||||
-rw-r--r-- | lib/Frontend/Warnings.cpp | 6 | ||||
-rw-r--r-- | test/Misc/diag-aka-types.cpp | 21 | ||||
-rw-r--r-- | test/Misc/diag-template-diffing.cpp | 433 |
12 files changed, 1523 insertions, 30 deletions
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 883e9d193e..4c3649372c 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -153,7 +153,8 @@ public: ak_declarationname, // DeclarationName ak_nameddecl, // NamedDecl * ak_nestednamespec, // NestedNameSpecifier * - ak_declcontext // DeclContext * + ak_declcontext, // DeclContext * + ak_qualtype_pair // pair<QualType, QualType> }; /// Specifies which overload candidates to display when overload resolution @@ -175,6 +176,9 @@ private: bool ErrorsAsFatal; // Treat errors like fatal errors. bool SuppressSystemWarnings; // Suppress warnings in system headers. bool SuppressAllDiagnostics; // Suppress all diagnostics. + bool ElideType; // Elide common types of templates. + bool PrintTemplateTree; // Print a tree when comparing templates. + bool ShowColors; // Color printing is enabled. OverloadsShown ShowOverloads; // Which overload candidates to show. unsigned ErrorLimit; // Cap of # errors emitted, 0 -> no limit. unsigned TemplateBacktraceLimit; // Cap on depth of template backtrace stack, @@ -438,7 +442,22 @@ public: SuppressAllDiagnostics = Val; } bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; } - + + /// \brief Set type eliding, to skip outputting same types occurring in + /// template types. + void setElideType(bool Val = true) { ElideType = Val; } + bool getElideType() { return ElideType; } + + /// \brief Set tree printing, to outputting the template difference in a + /// tree format. + void setPrintTemplateTree(bool Val = false) { PrintTemplateTree = Val; } + bool getPrintTemplateTree() { return PrintTemplateTree; } + + /// \brief Set color printing, so the type diffing will inject color markers + /// into the output. + void setShowColors(bool Val = false) { ShowColors = Val; } + bool getShowColors() { return ShowColors; } + /// \brief Specify which overload candidates to show when overload resolution /// fails. By default, we show all candidates. void setShowOverloads(OverloadsShown Val) { @@ -1058,7 +1077,6 @@ public: return DiagObj->DiagArgumentsVal[Idx]; } - /// getNumRanges - Return the number of source ranges associated with this /// diagnostic. unsigned getNumRanges() const { @@ -1223,6 +1241,20 @@ class IgnoringDiagConsumer : public DiagnosticConsumer { } }; +// Struct used for sending info about how a type should be printed. +struct TemplateDiffTypes { + intptr_t FromType; + intptr_t ToType; + unsigned PrintTree : 1; + unsigned PrintFromType : 1; + unsigned ElideType : 1; + unsigned ShowColors : 1; +}; + +/// Special character that the diagnostic printer will use to toggle the bold +/// attribute. The character itself will be not be printed. +const char ToggleHighlight = 127; + } // end namespace clang #endif diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 41b8b8a913..38a22a7fce 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2162,7 +2162,7 @@ def note_ovl_candidate_bad_conv : Note<"candidate " "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0%1" - " not viable: no known conversion from %2 to %3 for " + " not viable: no known conversion %diff{from | to | }2,3for " "%select{%ordinal5 argument|object argument}4; " "%select{|dereference the argument with *|" "take the address of the argument with &|" diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 16a4366ce8..0161e2d48b 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -358,6 +358,9 @@ def fdiagnostics_show_note_include_stack : Flag<"-fdiagnostics-show-note-include Group<f_Group>, Flags<[CC1Option]>, HelpText<"Display include stacks for diagnostic notes">; def fdiagnostics_format_EQ : Joined<"-fdiagnostics-format=">, Group<f_clang_Group>; def fdiagnostics_show_category_EQ : Joined<"-fdiagnostics-show-category=">, Group<f_clang_Group>; +def fdiagnostics_show_template_tree : Flag<"-fdiagnostics-show-template-tree">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Print a template comparison tree for differing templates">; def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, Group<f_Group>, HelpText<"Allow '$' in identifiers">, Flags<[CC1Option]>; def fdwarf2_cfi_asm : Flag<"-fdwarf2-cfi-asm">, Group<f_Group>; @@ -365,6 +368,9 @@ def fno_dwarf2_cfi_asm : Flag<"-fno-dwarf2-cfi-asm">, Group<f_Group>, Flags<[CC def fdwarf_directory_asm : Flag<"-fdwarf-directory-asm">, Group<f_Group>; def fno_dwarf_directory_asm : Flag<"-fno-dwarf-directory-asm">, Group<f_Group>, Flags<[CC1Option]>; def felide_constructors : Flag<"-felide-constructors">, Group<f_Group>; +def fno_elide_type : Flag<"-fno-elide-type">, Group<f_Group>, + Flags<[CC1Option]>, + HelpText<"Do not elide types when printing diagnostics">; def feliminate_unused_debug_symbols : Flag<"-feliminate-unused-debug-symbols">, Group<f_Group>; def femit_all_decls : Flag<"-femit-all-decls">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Emit all declarations, even if unused">; diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h index 1c6ba6acc3..8dec37ca03 100644 --- a/include/clang/Frontend/DiagnosticOptions.h +++ b/include/clang/Frontend/DiagnosticOptions.h @@ -47,6 +47,9 @@ public: /// diagnostics, indicated by markers in the /// input source file. + unsigned ElideType: 1; /// Elide identical types in template diffing + unsigned ShowTemplateTree: 1; /// Print a template tree when diffing + unsigned ErrorLimit; /// Limit # errors emitted. unsigned MacroBacktraceLimit; /// Limit depth of macro expansion backtrace. unsigned TemplateBacktraceLimit; /// Limit depth of instantiation backtrace. diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index ca4fe26852..a5733237ef 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -14,7 +14,11 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Type.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -225,6 +229,11 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, return S; } +static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType, + QualType ToType, bool PrintTree, + bool PrintFromType, bool ElideType, + bool ShowColors, std::string &S); + void clang::FormatASTNodeDiagnosticArgument( DiagnosticsEngine::ArgumentKind Kind, intptr_t Val, @@ -244,6 +253,32 @@ void clang::FormatASTNodeDiagnosticArgument( switch (Kind) { default: llvm_unreachable("unknown ArgumentKind"); + case DiagnosticsEngine::ak_qualtype_pair: { + const 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, S)) { + NeedQuotes = !TDT.PrintTree; + break; + } + + // Don't fall-back during tree printing. The caller will handle + // this case. + if (TDT.PrintTree) + return; + + // Attempting to do a templete diff on non-templates. Set the variables + // and continue with regular type printing of the appropriate type. + Val = TDT.PrintFromType ? TDT.FromType : TDT.ToType; + ModLen = 0; + ArgLen = 0; + // Fall through + } case DiagnosticsEngine::ak_qualtype: { assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for QualType argument"); @@ -329,3 +364,901 @@ void clang::FormatASTNodeDiagnosticArgument( if (NeedQuotes) 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; + + /// FromType - 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 FromType; + + /// ToType - The type that FromType is compared to. Only in tree printing + /// will this type be outputed. + QualType ToType; + + /// Str - Storage for the output stream. + llvm::SmallString<128> Str; + + /// OS - The stream used to construct the output strings. + llvm::raw_svector_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 { + /// 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 { + /// NextNode - The index of the next sibling node or 0. + unsigned NextNode; + + /// ChildNode - The index of the first child node or 0. + unsigned ChildNode; + + /// ParentNode - The index of the parent node. + unsigned ParentNode; + + /// FromType, ToType - The type arguments. + QualType FromType, ToType; + + /// FromExpr, ToExpr - The expression arguments. + Expr *FromExpr, *ToExpr; + + /// FromTD, ToTD - The template decl for template template + /// arguments or the type arguments that are templates. + TemplateDecl *FromTD, *ToTD; + + /// FromDefault, ToDefault - Whether the argument is a default argument. + bool FromDefault, ToDefault; + + /// Same - Whether the two arguments evaluate to the same value. + bool Same; + + DiffNode(unsigned ParentNode = 0) + : NextNode(0), ChildNode(0), ParentNode(ParentNode), + FromType(), ToType(), FromExpr(0), ToExpr(0), FromTD(0), ToTD(0), + FromDefault(false), ToDefault(false), Same(false) { } + }; + + /// FlatTree - A flattened tree used to store the DiffNodes. + llvm::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. + /// SetNode - Sets FromTD and ToTD of the current node. + void SetNode(TemplateDecl *FromTD, TemplateDecl *ToTD) { + FlatTree[CurrentNode].FromTD = FromTD; + FlatTree[CurrentNode].ToTD = ToTD; + } + + /// SetNode - Sets FromType and ToType of the current node. + void SetNode(QualType FromType, QualType ToType) { + FlatTree[CurrentNode].FromType = FromType; + FlatTree[CurrentNode].ToType = ToType; + } + + /// SetNode - Set FromExpr and ToExpr of the current node. + void SetNode(Expr *FromExpr, Expr *ToExpr) { + FlatTree[CurrentNode].FromExpr = FromExpr; + FlatTree[CurrentNode].ToExpr = ToExpr; + } + + /// SetSame - Sets the same flag of the current node. + void SetSame(bool Same) { + FlatTree[CurrentNode].Same = Same; + } + + /// SetDefault - Sets FromDefault and ToDefault flags of the current node. + void SetDefault(bool FromDefault, bool ToDefault) { + FlatTree[CurrentNode].FromDefault = FromDefault; + FlatTree[CurrentNode].ToDefault = ToDefault; + } + + /// Up - Changes the node to the parent of the current node. + void Up() { + CurrentNode = FlatTree[CurrentNode].ParentNode; + } + + /// AddNode - Adds a child node to the current node, then sets that node + /// node as the current node. + void AddNode() { + 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; + } + + /// NodeIsTemplate - Returns true if a template decl is set, and types are + /// set. + bool NodeIsTemplate() { + return (FlatTree[ReadNode].FromTD && + !FlatTree[ReadNode].ToType.isNull()) || + (FlatTree[ReadNode].ToTD && !FlatTree[ReadNode].ToType.isNull()); + } + + /// NodeIsQualType - Returns true if a Qualtype is set. + bool NodeIsQualType() { + return !FlatTree[ReadNode].FromType.isNull() || + !FlatTree[ReadNode].ToType.isNull(); + } + + /// NodeIsExpr - Returns true if an expr is set. + bool NodeIsExpr() { + return FlatTree[ReadNode].FromExpr || FlatTree[ReadNode].ToExpr; + } + + /// NodeIsTemplateTemplate - Returns true if the argument is a template + /// template type. + bool NodeIsTemplateTemplate() { + return FlatTree[ReadNode].FromType.isNull() && + FlatTree[ReadNode].ToType.isNull() && + (FlatTree[ReadNode].FromTD || FlatTree[ReadNode].ToTD); + } + + /// GetNode - Gets the FromType and ToType. + void GetNode(QualType &FromType, QualType &ToType) { + FromType = FlatTree[ReadNode].FromType; + ToType = FlatTree[ReadNode].ToType; + } + + /// GetNode - Gets the FromExpr and ToExpr. + void GetNode(Expr *&FromExpr, Expr *&ToExpr) { + FromExpr = FlatTree[ReadNode].FromExpr; + ToExpr = FlatTree[ReadNode].ToExpr; + } + + /// GetNode - Gets the FromTD and ToTD. + void GetNode(TemplateDecl *&FromTD, TemplateDecl *&ToTD) { + FromTD = FlatTree[ReadNode].FromTD; + ToTD = FlatTree[ReadNode].ToTD; + } + + /// 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; + } + + /// FromDefault - Return true if the from argument is the default. + bool FromDefault() { + return FlatTree[ReadNode].FromDefault; + } + + /// ToDefault - Return true if the to argument is the default. + bool ToDefault() { + return FlatTree[ReadNode].ToDefault; + } + + /// Empty - Returns true if the tree has no information. + bool Empty() { + return !FlatTree[0].FromTD && !FlatTree[0].ToTD && + !FlatTree[0].FromExpr && !FlatTree[0].ToExpr && + FlatTree[0].FromType.isNull() && FlatTree[0].ToType.isNull(); + } + }; + + DiffTree Tree; + + /// TSTiterator - 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 TSTiterator { + typedef const TemplateArgument& reference; + typedef const TemplateArgument* pointer; + + /// 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; + + /// TSTiterator - Constructs an iterator and sets it to the first template + /// argument. + TSTiterator(const TemplateSpecializationType *TST) + : TST(TST), Index(0), CurrentTA(0), EndTA(0) { + 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. + TSTiterator &operator++() { + assert(!isEnd() && "Iterator incremented past end of arguments."); + + // 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*(); + } + }; + + // 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 0; + + const ClassTemplateSpecializationDecl *CTSD = + dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()); + + if (!CTSD) + return 0; + + Ty = Context.getTemplateSpecializationType( + TemplateName(CTSD->getSpecializedTemplate()), + CTSD->getTemplateArgs().data(), + CTSD->getTemplateArgs().size(), + Ty.getCanonicalType()); + + return Ty->getAs<TemplateSpecializationType>(); + } + + /// 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 *Params = + FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters(); + unsigned TotalArgs = 0; + for (TSTiterator FromIter(FromTST), ToIter(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. + NamedDecl *ParamND = Params->getParam( + (TotalArgs < Params->size()) ? TotalArgs + : Params->size() - 1); + // Handle Types + if (TemplateTypeParmDecl *DefaultTTPD = + dyn_cast<TemplateTypeParmDecl>(ParamND)) { + QualType FromType, ToType; + GetType(FromIter, DefaultTTPD, FromType); + GetType(ToIter, DefaultTTPD, ToType); + Tree.SetNode(FromType, ToType); + Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(), + ToIter.isEnd() && !ToType.isNull()); + if (!FromType.isNull() && !ToType.isNull()) { + if (Context.hasSameType(FromType, ToType)) { + Tree.SetSame(true); + } else { + const TemplateSpecializationType *FromArgTST = + GetTemplateSpecializationType(Context, FromType); + const TemplateSpecializationType *ToArgTST = + GetTemplateSpecializationType(Context, ToType); + + if (FromArgTST && ToArgTST) { + bool SameTemplate = hasSameTemplate(FromArgTST, ToArgTST); + if (SameTemplate) { + Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(), + ToArgTST->getTemplateName().getAsTemplateDecl()); + DiffTemplate(FromArgTST, ToArgTST); + } + } + } + } + } + + // Handle Expressions + if (NonTypeTemplateParmDecl *DefaultNTTPD = + dyn_cast<NonTypeTemplateParmDecl>(ParamND)) { + Expr *FromExpr, *ToExpr; + GetExpr(FromIter, DefaultNTTPD, FromExpr); + GetExpr(ToIter, DefaultNTTPD, ToExpr); + Tree.SetNode(FromExpr, ToExpr); + Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr)); + Tree.SetDefault(FromIter.isEnd() && FromExpr, + ToIter.isEnd() && ToExpr); + } + + // Handle Templates + if (TemplateTemplateParmDecl *DefaultTTPD = + dyn_cast<TemplateTemplateParmDecl>(ParamND)) { + TemplateDecl *FromDecl, *ToDecl; + GetTemplateDecl(FromIter, DefaultTTPD, FromDecl); + GetTemplateDecl(ToIter, DefaultTTPD, ToDecl); + Tree.SetNode(FromDecl, ToDecl); + Tree.SetSame(FromDecl && ToDecl && + FromDecl->getIdentifier() == ToDecl->getIdentifier()); + } + + if (!FromIter.isEnd()) ++FromIter; + if (!ToIter.isEnd()) ++ToIter; + Tree.Up(); + } + } + + /// 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 (FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() == + ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier()) + return true; + + // Create vectors of template aliases. + SmallVector<const TemplateSpecializationType*, 1> FromTemplateList, + ToTemplateList; + + const TemplateSpecializationType *TempToTST = ToTST, *TempFromTST = FromTST; + FromTemplateList.push_back(FromTST); + ToTemplateList.push_back(ToTST); + + // Dump every template alias into the vectors. + while (TempFromTST->isTypeAlias()) { + TempFromTST = + TempFromTST->getAliasedType()->getAs<TemplateSpecializationType>(); + if (!TempFromTST) + break; + FromTemplateList.push_back(TempFromTST); + } + while (TempToTST->isTypeAlias()) { + TempToTST = + TempToTST->getAliasedType()->getAs<TemplateSpecializationType>(); + if (!TempToTST) + break; + ToTemplateList.push_back(TempToTST); + } + + SmallVector<const TemplateSpecializationType*, 1>::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 ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() != + (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier()) + 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 ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() != + (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier()) + break; + } + + FromTST = FromIter[-1]; + ToTST = ToIter[-1]; + + return true; + } + + /// GetType - Retrieves the template type arguments, including default + /// arguments. + void GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD, + QualType &ArgType) { + ArgType = QualType(); + bool isVariadic = DefaultTTPD->isParameterPack(); + + if (!Iter.isEnd()) + ArgType = Iter->getAsType(); + else if (!isVariadic) + ArgType = DefaultTTPD->getDefaultArgument(); + }; + + /// GetExpr - Retrieves the template expression argument, including default + /// arguments. + void GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD, + Expr *&ArgExpr) { + ArgExpr = 0; + bool isVariadic = DefaultNTTPD->isParameterPack(); + + if (!Iter.isEnd()) + ArgExpr = Iter->getAsExpr(); + else if (!isVariadic) + ArgExpr = DefaultNTTPD->getDefaultArgument(); + + if (ArgExpr) + while (SubstNonTypeTemplateParmExpr *SNTTPE = + dyn_cast<SubstNonTypeTemplateParmExpr>(ArgExpr)) + ArgExpr = SNTTPE->getReplacement(); + } + + /// GetTemplateDecl - Retrieves the template template arguments, including + /// default arguments. + void GetTemplateDecl(const TSTiterator &Iter, + TemplateTemplateParmDecl *DefaultTTPD, + TemplateDecl *&ArgDecl) { + ArgDecl = 0; + bool isVariadic = DefaultTTPD->isParameterPack(); + + TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument(); + TemplateDecl *DefaultTD = TA.getAsTemplate().getAsTemplateDecl(); + + if (!Iter.isEnd()) + ArgDecl = Iter->getAsTemplate().getAsTemplateDecl(); + else if (!isVariadic) + ArgDecl = DefaultTD; + } + + /// IsEqualExpr - Returns true if the expressions evaluate to the same value. + static bool IsEqualExpr(ASTContext &Context, Expr *FromExpr, Expr *ToExpr) { + if (FromExpr == ToExpr) + return true; + + if (!FromExpr || !ToExpr) + return false; + + FromExpr = FromExpr->IgnoreParens(); + ToExpr = ToExpr->IgnoreParens(); + + DeclRefExpr *FromDRE = dyn_cast<DeclRefExpr>(FromExpr), + *ToDRE = dyn_cast<DeclRefExpr>(ToExpr); + + if (FromDRE || ToDRE) { + if (!FromDRE || !ToDRE) + return false; + return FromDRE->getDecl() == ToDRE->getDecl(); + } + + Expr::EvalResult FromResult, ToResult; + if (!FromExpr->EvaluateAsRValue(FromResult, Context) || + !ToExpr->EvaluateAsRValue(ToResult, Context)) + assert(0 && "Template arguments must be known at compile time."); + + APValue &FromVal = FromResult.Val; + APValue &ToVal = ToResult.Val; + + if (FromVal.getKind() != ToVal.getKind()) return false; + + switch (FromVal.getKind()) { + case APValue::Int: + return FromVal.getInt() == ToVal.getInt(); + case APValue::LValue: { + APValue::LValueBase FromBase = FromVal.getLValueBase(); + APValue::LValueBase ToBase = ToVal.getLValueBase(); + if (FromBase.isNull() && ToBase.isNull()) + return true; + if (FromBase.isNull() || ToBase.isNull()) + return false; + return FromBase.get<const ValueDecl*>() == + ToBase.get<const ValueDecl*>(); + } + case APValue::MemberPointer: + return FromVal.getMemberPointerDecl() == ToVal.getMemberPointerDecl(); + default: + llvm_unreachable("Unknown template argument expression."); + } + } + + // 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'; + for (int i = 0; i < Indent; ++i) + OS << " "; + ++Indent; + } + + // Handle cases where the difference is not templates with different + // arguments. + if (!Tree.NodeIsTemplate()) { + if (Tree.NodeIsQualType()) { + QualType FromType, ToType; + Tree.GetNode(FromType, ToType); + PrintTypeNames(FromType, ToType, Tree.FromDefault(), Tree.ToDefault(), + Tree.NodeIsSame()); + return; + } + if (Tree.NodeIsExpr()) { + Expr *FromExpr, *ToExpr; + Tree.GetNode(FromExpr, ToExpr); + PrintExpr(FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(), + Tree.NodeIsSame()); + return; + } + if (Tree.NodeIsTemplateTemplate()) { + TemplateDecl *FromTD, *ToTD; + Tree.GetNode(FromTD, ToTD); + PrintTemplateTemplate(FromTD, ToTD, Tree.FromDefault(), + Tree.ToDefault(), Tree.NodeIsSame()); + return; + } + llvm_unreachable("Unable to deduce template difference."); + } + + // Node is root of template. Recurse on children. + TemplateDecl *FromTD, *ToTD; + Tree.GetNode(FromTD, ToTD); + + assert(Tree.HasChildren() && "Template difference not found in diff tree."); + + OS << FromTD->getNameAsString() << '<'; + Tree.MoveToChild(); + unsigned NumElideArgs = 0; + do { + if (ElideType) { + if (Tree.NodeIsSame()) { + ++NumElideArgs; + continue; + } + if (NumElideArgs > 0) { + PrintElideArgs(NumElideArgs, Indent); + NumElideArgs = 0; + OS << ", "; + } + } + TreeToString(Indent); + if (Tree.HasNextSibling()) + OS << ", "; + } while (Tree.AdvanceSibling()); + if (NumElideArgs > 0) + PrintElideArgs(NumElideArgs, Indent); + + Tree.Parent(); + OS << ">"; + } + + // 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."); < |