1 | //===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for AST Nodes ------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements a diagnostic formatting hook for AST elements. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "clang/AST/ASTDiagnostic.h" |
14 | #include "clang/AST/ASTContext.h" |
15 | #include "clang/AST/ASTLambda.h" |
16 | #include "clang/AST/Attr.h" |
17 | #include "clang/AST/DeclObjC.h" |
18 | #include "clang/AST/DeclTemplate.h" |
19 | #include "clang/AST/ExprCXX.h" |
20 | #include "clang/AST/TemplateBase.h" |
21 | #include "clang/AST/Type.h" |
22 | #include "llvm/ADT/StringExtras.h" |
23 | #include "llvm/Support/raw_ostream.h" |
24 | |
25 | using namespace clang; |
26 | |
27 | // Returns a desugared version of the QualType, and marks ShouldAKA as true |
28 | // whenever we remove significant sugar from the type. Make sure ShouldAKA |
29 | // is initialized before passing it in. |
30 | QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT, |
31 | bool &ShouldAKA) { |
32 | QualifierCollector QC; |
33 | |
34 | while (true) { |
35 | const Type *Ty = QC.strip(type: QT); |
36 | |
37 | // Don't aka just because we saw an elaborated type... |
38 | if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Val: Ty)) { |
39 | QT = ET->desugar(); |
40 | continue; |
41 | } |
42 | // ... or a using type ... |
43 | if (const UsingType *UT = dyn_cast<UsingType>(Val: Ty)) { |
44 | QT = UT->desugar(); |
45 | continue; |
46 | } |
47 | // ... or a paren type ... |
48 | if (const ParenType *PT = dyn_cast<ParenType>(Val: Ty)) { |
49 | QT = PT->desugar(); |
50 | continue; |
51 | } |
52 | // ... or a macro defined type ... |
53 | if (const MacroQualifiedType *MDT = dyn_cast<MacroQualifiedType>(Val: Ty)) { |
54 | QT = MDT->desugar(); |
55 | continue; |
56 | } |
57 | // ...or a substituted template type parameter ... |
58 | if (const SubstTemplateTypeParmType *ST = |
59 | dyn_cast<SubstTemplateTypeParmType>(Val: Ty)) { |
60 | QT = ST->desugar(); |
61 | continue; |
62 | } |
63 | // ...or an attributed type... |
64 | if (const AttributedType *AT = dyn_cast<AttributedType>(Val: Ty)) { |
65 | QT = AT->desugar(); |
66 | continue; |
67 | } |
68 | // ...or an adjusted type... |
69 | if (const AdjustedType *AT = dyn_cast<AdjustedType>(Val: Ty)) { |
70 | QT = AT->desugar(); |
71 | continue; |
72 | } |
73 | // ... or an auto type. |
74 | if (const AutoType *AT = dyn_cast<AutoType>(Val: Ty)) { |
75 | if (!AT->isSugared()) |
76 | break; |
77 | QT = AT->desugar(); |
78 | continue; |
79 | } |
80 | |
81 | // Desugar FunctionType if return type or any parameter type should be |
82 | // desugared. Preserve nullability attribute on desugared types. |
83 | if (const FunctionType *FT = dyn_cast<FunctionType>(Val: Ty)) { |
84 | bool DesugarReturn = false; |
85 | QualType SugarRT = FT->getReturnType(); |
86 | QualType RT = desugarForDiagnostic(Context, QT: SugarRT, ShouldAKA&: DesugarReturn); |
87 | if (auto nullability = AttributedType::stripOuterNullability(T&: SugarRT)) { |
88 | RT = Context.getAttributedType( |
89 | attrKind: AttributedType::getNullabilityAttrKind(kind: *nullability), modifiedType: RT, equivalentType: RT); |
90 | } |
91 | |
92 | bool DesugarArgument = false; |
93 | SmallVector<QualType, 4> Args; |
94 | const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Val: FT); |
95 | if (FPT) { |
96 | for (QualType SugarPT : FPT->param_types()) { |
97 | QualType PT = desugarForDiagnostic(Context, QT: SugarPT, ShouldAKA&: DesugarArgument); |
98 | if (auto nullability = |
99 | AttributedType::stripOuterNullability(T&: SugarPT)) { |
100 | PT = Context.getAttributedType( |
101 | attrKind: AttributedType::getNullabilityAttrKind(kind: *nullability), modifiedType: PT, equivalentType: PT); |
102 | } |
103 | Args.push_back(Elt: PT); |
104 | } |
105 | } |
106 | |
107 | if (DesugarReturn || DesugarArgument) { |
108 | ShouldAKA = true; |
109 | QT = FPT ? Context.getFunctionType(ResultTy: RT, Args, EPI: FPT->getExtProtoInfo()) |
110 | : Context.getFunctionNoProtoType(ResultTy: RT, Info: FT->getExtInfo()); |
111 | break; |
112 | } |
113 | } |
114 | |
115 | // Desugar template specializations if any template argument should be |
116 | // desugared. |
117 | if (const TemplateSpecializationType *TST = |
118 | dyn_cast<TemplateSpecializationType>(Val: Ty)) { |
119 | if (!TST->isTypeAlias()) { |
120 | bool DesugarArgument = false; |
121 | SmallVector<TemplateArgument, 4> Args; |
122 | for (const TemplateArgument &Arg : TST->template_arguments()) { |
123 | if (Arg.getKind() == TemplateArgument::Type) |
124 | Args.push_back(Elt: desugarForDiagnostic(Context, QT: Arg.getAsType(), |
125 | ShouldAKA&: DesugarArgument)); |
126 | else |
127 | Args.push_back(Elt: Arg); |
128 | } |
129 | |
130 | if (DesugarArgument) { |
131 | ShouldAKA = true; |
132 | QT = Context.getTemplateSpecializationType( |
133 | T: TST->getTemplateName(), Args, Canon: QT); |
134 | } |
135 | break; |
136 | } |
137 | } |
138 | |
139 | if (const auto *AT = dyn_cast<ArrayType>(Val: Ty)) { |
140 | QualType ElementTy = |
141 | desugarForDiagnostic(Context, QT: AT->getElementType(), ShouldAKA); |
142 | if (const auto *CAT = dyn_cast<ConstantArrayType>(Val: AT)) |
143 | QT = Context.getConstantArrayType( |
144 | EltTy: ElementTy, ArySize: CAT->getSize(), SizeExpr: CAT->getSizeExpr(), |
145 | ASM: CAT->getSizeModifier(), IndexTypeQuals: CAT->getIndexTypeCVRQualifiers()); |
146 | else if (const auto *VAT = dyn_cast<VariableArrayType>(Val: AT)) |
147 | QT = Context.getVariableArrayType( |
148 | EltTy: ElementTy, NumElts: VAT->getSizeExpr(), ASM: VAT->getSizeModifier(), |
149 | IndexTypeQuals: VAT->getIndexTypeCVRQualifiers(), Brackets: VAT->getBracketsRange()); |
150 | else if (const auto *DSAT = dyn_cast<DependentSizedArrayType>(Val: AT)) |
151 | QT = Context.getDependentSizedArrayType( |
152 | EltTy: ElementTy, NumElts: DSAT->getSizeExpr(), ASM: DSAT->getSizeModifier(), |
153 | IndexTypeQuals: DSAT->getIndexTypeCVRQualifiers(), Brackets: DSAT->getBracketsRange()); |
154 | else if (const auto *IAT = dyn_cast<IncompleteArrayType>(Val: AT)) |
155 | QT = Context.getIncompleteArrayType(EltTy: ElementTy, ASM: IAT->getSizeModifier(), |
156 | IndexTypeQuals: IAT->getIndexTypeCVRQualifiers()); |
157 | else |
158 | llvm_unreachable("Unhandled array type" ); |
159 | break; |
160 | } |
161 | |
162 | // Don't desugar magic Objective-C types. |
163 | if (QualType(Ty,0) == Context.getObjCIdType() || |
164 | QualType(Ty,0) == Context.getObjCClassType() || |
165 | QualType(Ty,0) == Context.getObjCSelType() || |
166 | QualType(Ty,0) == Context.getObjCProtoType()) |
167 | break; |
168 | |
169 | // Don't desugar va_list. |
170 | if (QualType(Ty, 0) == Context.getBuiltinVaListType() || |
171 | QualType(Ty, 0) == Context.getBuiltinMSVaListType()) |
172 | break; |
173 | |
174 | // Otherwise, do a single-step desugar. |
175 | QualType Underlying; |
176 | bool IsSugar = false; |
177 | switch (Ty->getTypeClass()) { |
178 | #define ABSTRACT_TYPE(Class, Base) |
179 | #define TYPE(Class, Base) \ |
180 | case Type::Class: { \ |
181 | const Class##Type *CTy = cast<Class##Type>(Ty); \ |
182 | if (CTy->isSugared()) { \ |
183 | IsSugar = true; \ |
184 | Underlying = CTy->desugar(); \ |
185 | } \ |
186 | break; \ |
187 | } |
188 | #include "clang/AST/TypeNodes.inc" |
189 | } |
190 | |
191 | // If it wasn't sugared, we're done. |
192 | if (!IsSugar) |
193 | break; |
194 | |
195 | // If the desugared type is a vector type, we don't want to expand |
196 | // it, it will turn into an attribute mess. People want their "vec4". |
197 | if (isa<VectorType>(Val: Underlying)) |
198 | break; |
199 | |
200 | // Don't desugar through the primary typedef of an anonymous type. |
201 | if (const TagType *UTT = Underlying->getAs<TagType>()) |
202 | if (const TypedefType *QTT = dyn_cast<TypedefType>(Val&: QT)) |
203 | if (UTT->getDecl()->getTypedefNameForAnonDecl() == QTT->getDecl()) |
204 | break; |
205 | |
206 | // Record that we actually looked through an opaque type here. |
207 | ShouldAKA = true; |
208 | QT = Underlying; |
209 | } |
210 | |
211 | // If we have a pointer-like type, desugar the pointee as well. |
212 | // FIXME: Handle other pointer-like types. |
213 | if (const PointerType *Ty = QT->getAs<PointerType>()) { |
214 | QT = Context.getPointerType( |
215 | T: desugarForDiagnostic(Context, QT: Ty->getPointeeType(), ShouldAKA)); |
216 | } else if (const auto *Ty = QT->getAs<ObjCObjectPointerType>()) { |
217 | QT = Context.getObjCObjectPointerType( |
218 | OIT: desugarForDiagnostic(Context, QT: Ty->getPointeeType(), ShouldAKA)); |
219 | } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) { |
220 | QT = Context.getLValueReferenceType( |
221 | T: desugarForDiagnostic(Context, QT: Ty->getPointeeType(), ShouldAKA)); |
222 | } else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) { |
223 | QT = Context.getRValueReferenceType( |
224 | T: desugarForDiagnostic(Context, QT: Ty->getPointeeType(), ShouldAKA)); |
225 | } else if (const auto *Ty = QT->getAs<ObjCObjectType>()) { |
226 | if (Ty->getBaseType().getTypePtr() != Ty && !ShouldAKA) { |
227 | QualType BaseType = |
228 | desugarForDiagnostic(Context, QT: Ty->getBaseType(), ShouldAKA); |
229 | QT = Context.getObjCObjectType( |
230 | Base: BaseType, typeArgs: Ty->getTypeArgsAsWritten(), |
231 | protocols: llvm::ArrayRef(Ty->qual_begin(), Ty->getNumProtocols()), |
232 | isKindOf: Ty->isKindOfTypeAsWritten()); |
233 | } |
234 | } |
235 | |
236 | return QC.apply(Context, QT); |
237 | } |
238 | |
239 | /// Convert the given type to a string suitable for printing as part of |
240 | /// a diagnostic. |
241 | /// |
242 | /// There are four main criteria when determining whether we should have an |
243 | /// a.k.a. clause when pretty-printing a type: |
244 | /// |
245 | /// 1) Some types provide very minimal sugar that doesn't impede the |
246 | /// user's understanding --- for example, elaborated type |
247 | /// specifiers. If this is all the sugar we see, we don't want an |
248 | /// a.k.a. clause. |
249 | /// 2) Some types are technically sugared but are much more familiar |
250 | /// when seen in their sugared form --- for example, va_list, |
251 | /// vector types, and the magic Objective C types. We don't |
252 | /// want to desugar these, even if we do produce an a.k.a. clause. |
253 | /// 3) Some types may have already been desugared previously in this diagnostic. |
254 | /// if this is the case, doing another "aka" would just be clutter. |
255 | /// 4) Two different types within the same diagnostic have the same output |
256 | /// string. In this case, force an a.k.a with the desugared type when |
257 | /// doing so will provide additional information. |
258 | /// |
259 | /// \param Context the context in which the type was allocated |
260 | /// \param Ty the type to print |
261 | /// \param QualTypeVals pointer values to QualTypes which are used in the |
262 | /// diagnostic message |
263 | static std::string |
264 | ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, |
265 | ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs, |
266 | ArrayRef<intptr_t> QualTypeVals) { |
267 | // FIXME: Playing with std::string is really slow. |
268 | bool ForceAKA = false; |
269 | QualType CanTy = Ty.getCanonicalType(); |
270 | std::string S = Ty.getAsString(Policy: Context.getPrintingPolicy()); |
271 | std::string CanS = CanTy.getAsString(Policy: Context.getPrintingPolicy()); |
272 | |
273 | for (const intptr_t &QualTypeVal : QualTypeVals) { |
274 | QualType CompareTy = |
275 | QualType::getFromOpaquePtr(Ptr: reinterpret_cast<void *>(QualTypeVal)); |
276 | if (CompareTy.isNull()) |
277 | continue; |
278 | if (CompareTy == Ty) |
279 | continue; // Same types |
280 | QualType CompareCanTy = CompareTy.getCanonicalType(); |
281 | if (CompareCanTy == CanTy) |
282 | continue; // Same canonical types |
283 | std::string CompareS = CompareTy.getAsString(Policy: Context.getPrintingPolicy()); |
284 | bool ShouldAKA = false; |
285 | QualType CompareDesugar = |
286 | desugarForDiagnostic(Context, QT: CompareTy, ShouldAKA); |
287 | std::string CompareDesugarStr = |
288 | CompareDesugar.getAsString(Policy: Context.getPrintingPolicy()); |
289 | if (CompareS != S && CompareDesugarStr != S) |
290 | continue; // The type string is different than the comparison string |
291 | // and the desugared comparison string. |
292 | std::string CompareCanS = |
293 | CompareCanTy.getAsString(Policy: Context.getPrintingPolicy()); |
294 | |
295 | if (CompareCanS == CanS) |
296 | continue; // No new info from canonical type |
297 | |
298 | ForceAKA = true; |
299 | break; |
300 | } |
301 | |
302 | // Check to see if we already desugared this type in this |
303 | // diagnostic. If so, don't do it again. |
304 | bool Repeated = false; |
305 | for (const auto &PrevArg : PrevArgs) { |
306 | // TODO: Handle ak_declcontext case. |
307 | if (PrevArg.first == DiagnosticsEngine::ak_qualtype) { |
308 | QualType PrevTy( |
309 | QualType::getFromOpaquePtr(Ptr: reinterpret_cast<void *>(PrevArg.second))); |
310 | if (PrevTy == Ty) { |
311 | Repeated = true; |
312 | break; |
313 | } |
314 | } |
315 | } |
316 | |
317 | // Consider producing an a.k.a. clause if removing all the direct |
318 | // sugar gives us something "significantly different". |
319 | if (!Repeated) { |
320 | bool ShouldAKA = false; |
321 | QualType DesugaredTy = desugarForDiagnostic(Context, QT: Ty, ShouldAKA); |
322 | if (ShouldAKA || ForceAKA) { |
323 | if (DesugaredTy == Ty) { |
324 | DesugaredTy = Ty.getCanonicalType(); |
325 | } |
326 | std::string akaStr = DesugaredTy.getAsString(Policy: Context.getPrintingPolicy()); |
327 | if (akaStr != S) { |
328 | S = "'" + S + "' (aka '" + akaStr + "')" ; |
329 | return S; |
330 | } |
331 | } |
332 | |
333 | // Give some additional info on vector types. These are either not desugared |
334 | // or displaying complex __attribute__ expressions so add details of the |
335 | // type and element count. |
336 | if (const auto *VTy = Ty->getAs<VectorType>()) { |
337 | std::string DecoratedString; |
338 | llvm::raw_string_ostream OS(DecoratedString); |
339 | const char *Values = VTy->getNumElements() > 1 ? "values" : "value" ; |
340 | OS << "'" << S << "' (vector of " << VTy->getNumElements() << " '" |
341 | << VTy->getElementType().getAsString(Policy: Context.getPrintingPolicy()) |
342 | << "' " << Values << ")" ; |
343 | return DecoratedString; |
344 | } |
345 | } |
346 | |
347 | S = "'" + S + "'" ; |
348 | return S; |
349 | } |
350 | |
351 | static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType, |
352 | QualType ToType, bool PrintTree, |
353 | bool PrintFromType, bool ElideType, |
354 | bool ShowColors, raw_ostream &OS); |
355 | |
356 | void clang::FormatASTNodeDiagnosticArgument( |
357 | DiagnosticsEngine::ArgumentKind Kind, |
358 | intptr_t Val, |
359 | StringRef Modifier, |
360 | StringRef Argument, |
361 | ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs, |
362 | SmallVectorImpl<char> &Output, |
363 | void *Cookie, |
364 | ArrayRef<intptr_t> QualTypeVals) { |
365 | ASTContext &Context = *static_cast<ASTContext*>(Cookie); |
366 | |
367 | size_t OldEnd = Output.size(); |
368 | llvm::raw_svector_ostream OS(Output); |
369 | bool NeedQuotes = true; |
370 | |
371 | switch (Kind) { |
372 | default: llvm_unreachable("unknown ArgumentKind" ); |
373 | case DiagnosticsEngine::ak_addrspace: { |
374 | assert(Modifier.empty() && Argument.empty() && |
375 | "Invalid modifier for Qualifiers argument" ); |
376 | |
377 | auto S = Qualifiers::getAddrSpaceAsString(AS: static_cast<LangAS>(Val)); |
378 | if (S.empty()) { |
379 | OS << (Context.getLangOpts().OpenCL ? "default" : "generic" ); |
380 | OS << " address space" ; |
381 | } else { |
382 | OS << "address space" ; |
383 | OS << " '" << S << "'" ; |
384 | } |
385 | NeedQuotes = false; |
386 | break; |
387 | } |
388 | case DiagnosticsEngine::ak_qual: { |
389 | assert(Modifier.empty() && Argument.empty() && |
390 | "Invalid modifier for Qualifiers argument" ); |
391 | |
392 | Qualifiers Q(Qualifiers::fromOpaqueValue(opaque: Val)); |
393 | auto S = Q.getAsString(); |
394 | if (S.empty()) { |
395 | OS << "unqualified" ; |
396 | NeedQuotes = false; |
397 | } else { |
398 | OS << S; |
399 | } |
400 | break; |
401 | } |
402 | case DiagnosticsEngine::ak_qualtype_pair: { |
403 | TemplateDiffTypes &TDT = *reinterpret_cast<TemplateDiffTypes*>(Val); |
404 | QualType FromType = |
405 | QualType::getFromOpaquePtr(Ptr: reinterpret_cast<void*>(TDT.FromType)); |
406 | QualType ToType = |
407 | QualType::getFromOpaquePtr(Ptr: reinterpret_cast<void*>(TDT.ToType)); |
408 | |
409 | if (FormatTemplateTypeDiff(Context, FromType, ToType, PrintTree: TDT.PrintTree, |
410 | PrintFromType: TDT.PrintFromType, ElideType: TDT.ElideType, |
411 | ShowColors: TDT.ShowColors, OS)) { |
412 | NeedQuotes = !TDT.PrintTree; |
413 | TDT.TemplateDiffUsed = true; |
414 | break; |
415 | } |
416 | |
417 | // Don't fall-back during tree printing. The caller will handle |
418 | // this case. |
419 | if (TDT.PrintTree) |
420 | return; |
421 | |
422 | // Attempting to do a template diff on non-templates. Set the variables |
423 | // and continue with regular type printing of the appropriate type. |
424 | Val = TDT.PrintFromType ? TDT.FromType : TDT.ToType; |
425 | Modifier = StringRef(); |
426 | Argument = StringRef(); |
427 | // Fall through |
428 | [[fallthrough]]; |
429 | } |
430 | case DiagnosticsEngine::ak_qualtype: { |
431 | assert(Modifier.empty() && Argument.empty() && |
432 | "Invalid modifier for QualType argument" ); |
433 | |
434 | QualType Ty(QualType::getFromOpaquePtr(Ptr: reinterpret_cast<void*>(Val))); |
435 | OS << ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, QualTypeVals); |
436 | NeedQuotes = false; |
437 | break; |
438 | } |
439 | case DiagnosticsEngine::ak_declarationname: { |
440 | if (Modifier == "objcclass" && Argument.empty()) |
441 | OS << '+'; |
442 | else if (Modifier == "objcinstance" && Argument.empty()) |
443 | OS << '-'; |
444 | else |
445 | assert(Modifier.empty() && Argument.empty() && |
446 | "Invalid modifier for DeclarationName argument" ); |
447 | |
448 | OS << DeclarationName::getFromOpaqueInteger(P: Val); |
449 | break; |
450 | } |
451 | case DiagnosticsEngine::ak_nameddecl: { |
452 | bool Qualified; |
453 | if (Modifier == "q" && Argument.empty()) |
454 | Qualified = true; |
455 | else { |
456 | assert(Modifier.empty() && Argument.empty() && |
457 | "Invalid modifier for NamedDecl* argument" ); |
458 | Qualified = false; |
459 | } |
460 | const NamedDecl *ND = reinterpret_cast<const NamedDecl*>(Val); |
461 | ND->getNameForDiagnostic(OS, Policy: Context.getPrintingPolicy(), Qualified); |
462 | break; |
463 | } |
464 | case DiagnosticsEngine::ak_nestednamespec: { |
465 | NestedNameSpecifier *NNS = reinterpret_cast<NestedNameSpecifier*>(Val); |
466 | NNS->print(OS, Policy: Context.getPrintingPolicy()); |
467 | NeedQuotes = false; |
468 | break; |
469 | } |
470 | case DiagnosticsEngine::ak_declcontext: { |
471 | DeclContext *DC = reinterpret_cast<DeclContext *> (Val); |
472 | assert(DC && "Should never have a null declaration context" ); |
473 | NeedQuotes = false; |
474 | |
475 | // FIXME: Get the strings for DeclContext from some localized place |
476 | if (DC->isTranslationUnit()) { |
477 | if (Context.getLangOpts().CPlusPlus) |
478 | OS << "the global namespace" ; |
479 | else |
480 | OS << "the global scope" ; |
481 | } else if (DC->isClosure()) { |
482 | OS << "block literal" ; |
483 | } else if (isLambdaCallOperator(DC)) { |
484 | OS << "lambda expression" ; |
485 | } else if (TypeDecl *Type = dyn_cast<TypeDecl>(Val: DC)) { |
486 | OS << ConvertTypeToDiagnosticString(Context, |
487 | Ty: Context.getTypeDeclType(Decl: Type), |
488 | PrevArgs, QualTypeVals); |
489 | } else { |
490 | assert(isa<NamedDecl>(DC) && "Expected a NamedDecl" ); |
491 | NamedDecl *ND = cast<NamedDecl>(Val: DC); |
492 | if (isa<NamespaceDecl>(Val: ND)) |
493 | OS << "namespace " ; |
494 | else if (isa<ObjCMethodDecl>(Val: ND)) |
495 | OS << "method " ; |
496 | else if (isa<FunctionDecl>(Val: ND)) |
497 | OS << "function " ; |
498 | |
499 | OS << '\''; |
500 | ND->getNameForDiagnostic(OS, Policy: Context.getPrintingPolicy(), Qualified: true); |
501 | OS << '\''; |
502 | } |
503 | break; |
504 | } |
505 | case DiagnosticsEngine::ak_attr: { |
506 | const Attr *At = reinterpret_cast<Attr *>(Val); |
507 | assert(At && "Received null Attr object!" ); |
508 | OS << '\'' << At->getSpelling() << '\''; |
509 | NeedQuotes = false; |
510 | break; |
511 | } |
512 | } |
513 | |
514 | if (NeedQuotes) { |
515 | Output.insert(I: Output.begin()+OldEnd, Elt: '\''); |
516 | Output.push_back(Elt: '\''); |
517 | } |
518 | } |
519 | |
520 | /// TemplateDiff - A class that constructs a pretty string for a pair of |
521 | /// QualTypes. For the pair of types, a diff tree will be created containing |
522 | /// all the information about the templates and template arguments. Afterwards, |
523 | /// the tree is transformed to a string according to the options passed in. |
524 | namespace { |
525 | class TemplateDiff { |
526 | /// Context - The ASTContext which is used for comparing template arguments. |
527 | ASTContext &Context; |
528 | |
529 | /// Policy - Used during expression printing. |
530 | PrintingPolicy Policy; |
531 | |
532 | /// ElideType - Option to elide identical types. |
533 | bool ElideType; |
534 | |
535 | /// PrintTree - Format output string as a tree. |
536 | bool PrintTree; |
537 | |
538 | /// ShowColor - Diagnostics support color, so bolding will be used. |
539 | bool ShowColor; |
540 | |
541 | /// FromTemplateType - When single type printing is selected, this is the |
542 | /// type to be printed. When tree printing is selected, this type will |
543 | /// show up first in the tree. |
544 | QualType FromTemplateType; |
545 | |
546 | /// ToTemplateType - The type that FromType is compared to. Only in tree |
547 | /// printing will this type be outputed. |
548 | QualType ToTemplateType; |
549 | |
550 | /// OS - The stream used to construct the output strings. |
551 | raw_ostream &OS; |
552 | |
553 | /// IsBold - Keeps track of the bold formatting for the output string. |
554 | bool IsBold; |
555 | |
556 | /// DiffTree - A tree representation the differences between two types. |
557 | class DiffTree { |
558 | public: |
559 | /// DiffKind - The difference in a DiffNode. Fields of |
560 | /// TemplateArgumentInfo needed by each difference can be found in the |
561 | /// Set* and Get* functions. |
562 | enum DiffKind { |
563 | /// Incomplete or invalid node. |
564 | Invalid, |
565 | /// Another level of templates |
566 | Template, |
567 | /// Type difference, all type differences except those falling under |
568 | /// the Template difference. |
569 | Type, |
570 | /// Expression difference, this is only when both arguments are |
571 | /// expressions. If one argument is an expression and the other is |
572 | /// Integer or Declaration, then use that diff type instead. |
573 | Expression, |
574 | /// Template argument difference |
575 | TemplateTemplate, |
576 | /// Integer difference |
577 | Integer, |
578 | /// Declaration difference, nullptr arguments are included here |
579 | Declaration, |
580 | /// One argument being integer and the other being declaration |
581 | FromIntegerAndToDeclaration, |
582 | FromDeclarationAndToInteger |
583 | }; |
584 | |
585 | private: |
586 | /// TemplateArgumentInfo - All the information needed to pretty print |
587 | /// a template argument. See the Set* and Get* functions to see which |
588 | /// fields are used for each DiffKind. |
589 | struct TemplateArgumentInfo { |
590 | QualType ArgType; |
591 | Qualifiers Qual; |
592 | llvm::APSInt Val; |
593 | bool IsValidInt = false; |
594 | Expr *ArgExpr = nullptr; |
595 | TemplateDecl *TD = nullptr; |
596 | ValueDecl *VD = nullptr; |
597 | bool NeedAddressOf = false; |
598 | bool IsNullPtr = false; |
599 | bool IsDefault = false; |
600 | }; |
601 | |
602 | /// DiffNode - The root node stores the original type. Each child node |
603 | /// stores template arguments of their parents. For templated types, the |
604 | /// template decl is also stored. |
605 | struct DiffNode { |
606 | DiffKind Kind = Invalid; |
607 | |
608 | /// NextNode - The index of the next sibling node or 0. |
609 | unsigned NextNode = 0; |
610 | |
611 | /// ChildNode - The index of the first child node or 0. |
612 | unsigned ChildNode = 0; |
613 | |
614 | /// ParentNode - The index of the parent node. |
615 | unsigned ParentNode = 0; |
616 | |
617 | TemplateArgumentInfo FromArgInfo, ToArgInfo; |
618 | |
619 | /// Same - Whether the two arguments evaluate to the same value. |
620 | bool Same = false; |
621 | |
622 | DiffNode(unsigned ParentNode = 0) : ParentNode(ParentNode) {} |
623 | }; |
624 | |
625 | /// FlatTree - A flattened tree used to store the DiffNodes. |
626 | SmallVector<DiffNode, 16> FlatTree; |
627 | |
628 | /// CurrentNode - The index of the current node being used. |
629 | unsigned CurrentNode; |
630 | |
631 | /// NextFreeNode - The index of the next unused node. Used when creating |
632 | /// child nodes. |
633 | unsigned NextFreeNode; |
634 | |
635 | /// ReadNode - The index of the current node being read. |
636 | unsigned ReadNode; |
637 | |
638 | public: |
639 | DiffTree() : CurrentNode(0), NextFreeNode(1), ReadNode(0) { |
640 | FlatTree.push_back(Elt: DiffNode()); |
641 | } |
642 | |
643 | // Node writing functions, one for each valid DiffKind element. |
644 | void SetTemplateDiff(TemplateDecl *FromTD, TemplateDecl *ToTD, |
645 | Qualifiers FromQual, Qualifiers ToQual, |
646 | bool FromDefault, bool ToDefault) { |
647 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty." ); |
648 | FlatTree[CurrentNode].Kind = Template; |
649 | FlatTree[CurrentNode].FromArgInfo.TD = FromTD; |
650 | FlatTree[CurrentNode].ToArgInfo.TD = ToTD; |
651 | FlatTree[CurrentNode].FromArgInfo.Qual = FromQual; |
652 | FlatTree[CurrentNode].ToArgInfo.Qual = ToQual; |
653 | SetDefault(FromDefault, ToDefault); |
654 | } |
655 | |
656 | void SetTypeDiff(QualType FromType, QualType ToType, bool FromDefault, |
657 | bool ToDefault) { |
658 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty." ); |
659 | FlatTree[CurrentNode].Kind = Type; |
660 | FlatTree[CurrentNode].FromArgInfo.ArgType = FromType; |
661 | FlatTree[CurrentNode].ToArgInfo.ArgType = ToType; |
662 | SetDefault(FromDefault, ToDefault); |
663 | } |
664 | |
665 | void SetExpressionDiff(Expr *FromExpr, Expr *ToExpr, bool FromDefault, |
666 | bool ToDefault) { |
667 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty." ); |
668 | FlatTree[CurrentNode].Kind = Expression; |
669 | FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
670 | FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
671 | SetDefault(FromDefault, ToDefault); |
672 | } |
673 | |
674 | void SetTemplateTemplateDiff(TemplateDecl *FromTD, TemplateDecl *ToTD, |
675 | bool FromDefault, bool ToDefault) { |
676 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty." ); |
677 | FlatTree[CurrentNode].Kind = TemplateTemplate; |
678 | FlatTree[CurrentNode].FromArgInfo.TD = FromTD; |
679 | FlatTree[CurrentNode].ToArgInfo.TD = ToTD; |
680 | SetDefault(FromDefault, ToDefault); |
681 | } |
682 | |
683 | void SetIntegerDiff(const llvm::APSInt &FromInt, const llvm::APSInt &ToInt, |
684 | bool IsValidFromInt, bool IsValidToInt, |
685 | QualType FromIntType, QualType ToIntType, |
686 | Expr *FromExpr, Expr *ToExpr, bool FromDefault, |
687 | bool ToDefault) { |
688 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty." ); |
689 | FlatTree[CurrentNode].Kind = Integer; |
690 | FlatTree[CurrentNode].FromArgInfo.Val = FromInt; |
691 | FlatTree[CurrentNode].ToArgInfo.Val = ToInt; |
692 | FlatTree[CurrentNode].FromArgInfo.IsValidInt = IsValidFromInt; |
693 | FlatTree[CurrentNode].ToArgInfo.IsValidInt = IsValidToInt; |
694 | FlatTree[CurrentNode].FromArgInfo.ArgType = FromIntType; |
695 | FlatTree[CurrentNode].ToArgInfo.ArgType = ToIntType; |
696 | FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
697 | FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
698 | SetDefault(FromDefault, ToDefault); |
699 | } |
700 | |
701 | void SetDeclarationDiff(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl, |
702 | bool FromAddressOf, bool ToAddressOf, |
703 | bool FromNullPtr, bool ToNullPtr, Expr *FromExpr, |
704 | Expr *ToExpr, bool FromDefault, bool ToDefault) { |
705 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty." ); |
706 | FlatTree[CurrentNode].Kind = Declaration; |
707 | FlatTree[CurrentNode].FromArgInfo.VD = FromValueDecl; |
708 | FlatTree[CurrentNode].ToArgInfo.VD = ToValueDecl; |
709 | FlatTree[CurrentNode].FromArgInfo.NeedAddressOf = FromAddressOf; |
710 | FlatTree[CurrentNode].ToArgInfo.NeedAddressOf = ToAddressOf; |
711 | FlatTree[CurrentNode].FromArgInfo.IsNullPtr = FromNullPtr; |
712 | FlatTree[CurrentNode].ToArgInfo.IsNullPtr = ToNullPtr; |
713 | FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
714 | FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
715 | SetDefault(FromDefault, ToDefault); |
716 | } |
717 | |
718 | void SetFromDeclarationAndToIntegerDiff( |
719 | ValueDecl *FromValueDecl, bool FromAddressOf, bool FromNullPtr, |
720 | Expr *FromExpr, const llvm::APSInt &ToInt, bool IsValidToInt, |
721 | QualType ToIntType, Expr *ToExpr, bool FromDefault, bool ToDefault) { |
722 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty." ); |
723 | FlatTree[CurrentNode].Kind = FromDeclarationAndToInteger; |
724 | FlatTree[CurrentNode].FromArgInfo.VD = FromValueDecl; |
725 | FlatTree[CurrentNode].FromArgInfo.NeedAddressOf = FromAddressOf; |
726 | FlatTree[CurrentNode].FromArgInfo.IsNullPtr = FromNullPtr; |
727 | FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
728 | FlatTree[CurrentNode].ToArgInfo.Val = ToInt; |
729 | FlatTree[CurrentNode].ToArgInfo.IsValidInt = IsValidToInt; |
730 | FlatTree[CurrentNode].ToArgInfo.ArgType = ToIntType; |
731 | FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
732 | SetDefault(FromDefault, ToDefault); |
733 | } |
734 | |
735 | void SetFromIntegerAndToDeclarationDiff( |
736 | const llvm::APSInt &FromInt, bool IsValidFromInt, QualType FromIntType, |
737 | Expr *FromExpr, ValueDecl *ToValueDecl, bool ToAddressOf, |
738 | bool ToNullPtr, Expr *ToExpr, bool FromDefault, bool ToDefault) { |
739 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty." ); |
740 | FlatTree[CurrentNode].Kind = FromIntegerAndToDeclaration; |
741 | FlatTree[CurrentNode].FromArgInfo.Val = FromInt; |
742 | FlatTree[CurrentNode].FromArgInfo.IsValidInt = IsValidFromInt; |
743 | FlatTree[CurrentNode].FromArgInfo.ArgType = FromIntType; |
744 | FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
745 | FlatTree[CurrentNode].ToArgInfo.VD = ToValueDecl; |
746 | FlatTree[CurrentNode].ToArgInfo.NeedAddressOf = ToAddressOf; |
747 | FlatTree[CurrentNode].ToArgInfo.IsNullPtr = ToNullPtr; |
748 | FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
749 | SetDefault(FromDefault, ToDefault); |
750 | } |
751 | |
752 | /// SetDefault - Sets FromDefault and ToDefault flags of the current node. |
753 | void SetDefault(bool FromDefault, bool ToDefault) { |
754 | assert((!FromDefault || !ToDefault) && "Both arguments cannot be default." ); |
755 | FlatTree[CurrentNode].FromArgInfo.IsDefault = FromDefault; |
756 | FlatTree[CurrentNode].ToArgInfo.IsDefault = ToDefault; |
757 | } |
758 | |
759 | /// SetSame - Sets the same flag of the current node. |
760 | void SetSame(bool Same) { |
761 | FlatTree[CurrentNode].Same = Same; |
762 | } |
763 | |
764 | /// SetKind - Sets the current node's type. |
765 | void SetKind(DiffKind Kind) { |
766 | FlatTree[CurrentNode].Kind = Kind; |
767 | } |
768 | |
769 | /// Up - Changes the node to the parent of the current node. |
770 | void Up() { |
771 | assert(FlatTree[CurrentNode].Kind != Invalid && |
772 | "Cannot exit node before setting node information." ); |
773 | CurrentNode = FlatTree[CurrentNode].ParentNode; |
774 | } |
775 | |
776 | /// AddNode - Adds a child node to the current node, then sets that node |
777 | /// node as the current node. |
778 | void AddNode() { |
779 | assert(FlatTree[CurrentNode].Kind == Template && |
780 | "Only Template nodes can have children nodes." ); |
781 | FlatTree.push_back(Elt: DiffNode(CurrentNode)); |
782 | DiffNode &Node = FlatTree[CurrentNode]; |
783 | if (Node.ChildNode == 0) { |
784 | // If a child node doesn't exist, add one. |
785 | Node.ChildNode = NextFreeNode; |
786 | } else { |
787 | // If a child node exists, find the last child node and add a |
788 | // next node to it. |
789 | unsigned i; |
790 | for (i = Node.ChildNode; FlatTree[i].NextNode != 0; |
791 | i = FlatTree[i].NextNode) { |
792 | } |
793 | FlatTree[i].NextNode = NextFreeNode; |
794 | } |
795 | CurrentNode = NextFreeNode; |
796 | ++NextFreeNode; |
797 | } |
798 | |
799 | // Node reading functions. |
800 | /// StartTraverse - Prepares the tree for recursive traversal. |
801 | void StartTraverse() { |
802 | ReadNode = 0; |
803 | CurrentNode = NextFreeNode; |
804 | NextFreeNode = 0; |
805 | } |
806 | |
807 | /// Parent - Move the current read node to its parent. |
808 | void Parent() { |
809 | ReadNode = FlatTree[ReadNode].ParentNode; |
810 | } |
811 | |
812 | void GetTemplateDiff(TemplateDecl *&FromTD, TemplateDecl *&ToTD, |
813 | Qualifiers &FromQual, Qualifiers &ToQual) { |
814 | assert(FlatTree[ReadNode].Kind == Template && "Unexpected kind." ); |
815 | FromTD = FlatTree[ReadNode].FromArgInfo.TD; |
816 | ToTD = FlatTree[ReadNode].ToArgInfo.TD; |
817 | FromQual = FlatTree[ReadNode].FromArgInfo.Qual; |
818 | ToQual = FlatTree[ReadNode].ToArgInfo.Qual; |
819 | } |
820 | |
821 | void GetTypeDiff(QualType &FromType, QualType &ToType) { |
822 | assert(FlatTree[ReadNode].Kind == Type && "Unexpected kind" ); |
823 | FromType = FlatTree[ReadNode].FromArgInfo.ArgType; |
824 | ToType = FlatTree[ReadNode].ToArgInfo.ArgType; |
825 | } |
826 | |
827 | void GetExpressionDiff(Expr *&FromExpr, Expr *&ToExpr) { |
828 | assert(FlatTree[ReadNode].Kind == Expression && "Unexpected kind" ); |
829 | FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
830 | ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
831 | } |
832 | |
833 | void GetTemplateTemplateDiff(TemplateDecl *&FromTD, TemplateDecl *&ToTD) { |
834 | assert(FlatTree[ReadNode].Kind == TemplateTemplate && "Unexpected kind." ); |
835 | FromTD = FlatTree[ReadNode].FromArgInfo.TD; |
836 | ToTD = FlatTree[ReadNode].ToArgInfo.TD; |
837 | } |
838 | |
839 | void GetIntegerDiff(llvm::APSInt &FromInt, llvm::APSInt &ToInt, |
840 | bool &IsValidFromInt, bool &IsValidToInt, |
841 | QualType &FromIntType, QualType &ToIntType, |
842 | Expr *&FromExpr, Expr *&ToExpr) { |
843 | assert(FlatTree[ReadNode].Kind == Integer && "Unexpected kind." ); |
844 | FromInt = FlatTree[ReadNode].FromArgInfo.Val; |
845 | ToInt = FlatTree[ReadNode].ToArgInfo.Val; |
846 | IsValidFromInt = FlatTree[ReadNode].FromArgInfo.IsValidInt; |
847 | IsValidToInt = FlatTree[ReadNode].ToArgInfo.IsValidInt; |
848 | FromIntType = FlatTree[ReadNode].FromArgInfo.ArgType; |
849 | ToIntType = FlatTree[ReadNode].ToArgInfo.ArgType; |
850 | FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
851 | ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
852 | } |
853 | |
854 | void GetDeclarationDiff(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl, |
855 | bool &FromAddressOf, bool &ToAddressOf, |
856 | bool &FromNullPtr, bool &ToNullPtr, Expr *&FromExpr, |
857 | Expr *&ToExpr) { |
858 | assert(FlatTree[ReadNode].Kind == Declaration && "Unexpected kind." ); |
859 | FromValueDecl = FlatTree[ReadNode].FromArgInfo.VD; |
860 | ToValueDecl = FlatTree[ReadNode].ToArgInfo.VD; |
861 | FromAddressOf = FlatTree[ReadNode].FromArgInfo.NeedAddressOf; |
862 | ToAddressOf = FlatTree[ReadNode].ToArgInfo.NeedAddressOf; |
863 | FromNullPtr = FlatTree[ReadNode].FromArgInfo.IsNullPtr; |
864 | ToNullPtr = FlatTree[ReadNode].ToArgInfo.IsNullPtr; |
865 | FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
866 | ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
867 | } |
868 | |
869 | void GetFromDeclarationAndToIntegerDiff( |
870 | ValueDecl *&FromValueDecl, bool &FromAddressOf, bool &FromNullPtr, |
871 | Expr *&FromExpr, llvm::APSInt &ToInt, bool &IsValidToInt, |
872 | QualType &ToIntType, Expr *&ToExpr) { |
873 | assert(FlatTree[ReadNode].Kind == FromDeclarationAndToInteger && |
874 | "Unexpected kind." ); |
875 | FromValueDecl = FlatTree[ReadNode].FromArgInfo.VD; |
876 | FromAddressOf = FlatTree[ReadNode].FromArgInfo.NeedAddressOf; |
877 | FromNullPtr = FlatTree[ReadNode].FromArgInfo.IsNullPtr; |
878 | FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
879 | ToInt = FlatTree[ReadNode].ToArgInfo.Val; |
880 | IsValidToInt = FlatTree[ReadNode].ToArgInfo.IsValidInt; |
881 | ToIntType = FlatTree[ReadNode].ToArgInfo.ArgType; |
882 | ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
883 | } |
884 | |
885 | void GetFromIntegerAndToDeclarationDiff( |
886 | llvm::APSInt &FromInt, bool &IsValidFromInt, QualType &FromIntType, |
887 | Expr *&FromExpr, ValueDecl *&ToValueDecl, bool &ToAddressOf, |
888 | bool &ToNullPtr, Expr *&ToExpr) { |
889 | assert(FlatTree[ReadNode].Kind == FromIntegerAndToDeclaration && |
890 | "Unexpected kind." ); |
891 | FromInt = FlatTree[ReadNode].FromArgInfo.Val; |
892 | IsValidFromInt = FlatTree[ReadNode].FromArgInfo.IsValidInt; |
893 | FromIntType = FlatTree[ReadNode].FromArgInfo.ArgType; |
894 | FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
895 | ToValueDecl = FlatTree[ReadNode].ToArgInfo.VD; |
896 | ToAddressOf = FlatTree[ReadNode].ToArgInfo.NeedAddressOf; |
897 | ToNullPtr = FlatTree[ReadNode].ToArgInfo.IsNullPtr; |
898 | ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
899 | } |
900 | |
901 | /// FromDefault - Return true if the from argument is the default. |
902 | bool FromDefault() { |
903 | return FlatTree[ReadNode].FromArgInfo.IsDefault; |
904 | } |
905 | |
906 | /// ToDefault - Return true if the to argument is the default. |
907 | bool ToDefault() { |
908 | return FlatTree[ReadNode].ToArgInfo.IsDefault; |
909 | } |
910 | |
911 | /// NodeIsSame - Returns true the arguments are the same. |
912 | bool NodeIsSame() { |
913 | return FlatTree[ReadNode].Same; |
914 | } |
915 | |
916 | /// HasChildrend - Returns true if the node has children. |
917 | bool HasChildren() { |
918 | return FlatTree[ReadNode].ChildNode != 0; |
919 | } |
920 | |
921 | /// MoveToChild - Moves from the current node to its child. |
922 | void MoveToChild() { |
923 | ReadNode = FlatTree[ReadNode].ChildNode; |
924 | } |
925 | |
926 | /// AdvanceSibling - If there is a next sibling, advance to it and return |
927 | /// true. Otherwise, return false. |
928 | bool AdvanceSibling() { |
929 | if (FlatTree[ReadNode].NextNode == 0) |
930 | return false; |
931 | |
932 | ReadNode = FlatTree[ReadNode].NextNode; |
933 | return true; |
934 | } |
935 | |
936 | /// HasNextSibling - Return true if the node has a next sibling. |
937 | bool HasNextSibling() { |
938 | return FlatTree[ReadNode].NextNode != 0; |
939 | } |
940 | |
941 | /// Empty - Returns true if the tree has no information. |
942 | bool Empty() { |
943 | return GetKind() == Invalid; |
944 | } |
945 | |
946 | /// GetKind - Returns the current node's type. |
947 | DiffKind GetKind() { |
948 | return FlatTree[ReadNode].Kind; |
949 | } |
950 | }; |
951 | |
952 | DiffTree Tree; |
953 | |
954 | /// TSTiterator - a pair of iterators that walks the |
955 | /// TemplateSpecializationType and the desugared TemplateSpecializationType. |
956 | /// The deseguared TemplateArgument should provide the canonical argument |
957 | /// for comparisons. |
958 | class TSTiterator { |
959 | typedef const TemplateArgument& reference; |
960 | typedef const TemplateArgument* pointer; |
961 | |
962 | /// InternalIterator - an iterator that is used to enter a |
963 | /// TemplateSpecializationType and read TemplateArguments inside template |
964 | /// parameter packs in order with the rest of the TemplateArguments. |
965 | struct InternalIterator { |
966 | /// TST - the template specialization whose arguments this iterator |
967 | /// traverse over. |
968 | const TemplateSpecializationType *TST; |
969 | |
970 | /// Index - the index of the template argument in TST. |
971 | unsigned Index; |
972 | |
973 | /// CurrentTA - if CurrentTA is not the same as EndTA, then CurrentTA |
974 | /// points to a TemplateArgument within a parameter pack. |
975 | TemplateArgument::pack_iterator CurrentTA; |
976 | |
977 | /// EndTA - the end iterator of a parameter pack |
978 | TemplateArgument::pack_iterator EndTA; |
979 | |
980 | /// InternalIterator - Constructs an iterator and sets it to the first |
981 | /// template argument. |
982 | InternalIterator(const TemplateSpecializationType *TST) |
983 | : TST(TST), Index(0), CurrentTA(nullptr), EndTA(nullptr) { |
984 | if (!TST) return; |
985 | |
986 | if (isEnd()) return; |
987 | |
988 | // Set to first template argument. If not a parameter pack, done. |
989 | TemplateArgument TA = TST->template_arguments()[0]; |
990 | if (TA.getKind() != TemplateArgument::Pack) return; |
991 | |
992 | // Start looking into the parameter pack. |
993 | CurrentTA = TA.pack_begin(); |
994 | EndTA = TA.pack_end(); |
995 | |
996 | // Found a valid template argument. |
997 | if (CurrentTA != EndTA) return; |
998 | |
999 | // Parameter pack is empty, use the increment to get to a valid |
1000 | // template argument. |
1001 | ++(*this); |
1002 | } |
1003 | |
1004 | /// Return true if the iterator is non-singular. |
1005 | bool isValid() const { return TST; } |
1006 | |
1007 | /// isEnd - Returns true if the iterator is one past the end. |
1008 | bool isEnd() const { |
1009 | assert(TST && "InternalIterator is invalid with a null TST." ); |
1010 | return Index >= TST->template_arguments().size(); |
1011 | } |
1012 | |
1013 | /// &operator++ - Increment the iterator to the next template argument. |
1014 | InternalIterator &operator++() { |
1015 | assert(TST && "InternalIterator is invalid with a null TST." ); |
1016 | if (isEnd()) { |
1017 | return *this; |
1018 | } |
1019 | |
1020 | // If in a parameter pack, advance in the parameter pack. |
1021 | if (CurrentTA != EndTA) { |
1022 | ++CurrentTA; |
1023 | if (CurrentTA != EndTA) |
1024 | return *this; |
1025 | } |
1026 | |
1027 | // Loop until a template argument is found, or the end is reached. |
1028 | while (true) { |
1029 | // Advance to the next template argument. Break if reached the end. |
1030 | if (++Index == TST->template_arguments().size()) |
1031 | break; |
1032 | |
1033 | // If the TemplateArgument is not a parameter pack, done. |
1034 | TemplateArgument TA = TST->template_arguments()[Index]; |
1035 | if (TA.getKind() != TemplateArgument::Pack) |
1036 | break; |
1037 | |
1038 | // Handle parameter packs. |
1039 | CurrentTA = TA.pack_begin(); |
1040 | EndTA = TA.pack_end(); |
1041 | |
1042 | // If the parameter pack is empty, try to advance again. |
1043 | if (CurrentTA != EndTA) |
1044 | break; |
1045 | } |
1046 | return *this; |
1047 | } |
1048 | |
1049 | /// operator* - Returns the appropriate TemplateArgument. |
1050 | reference operator*() const { |
1051 | assert(TST && "InternalIterator is invalid with a null TST." ); |
1052 | assert(!isEnd() && "Index exceeds number of arguments." ); |
1053 | if (CurrentTA == EndTA) |
1054 | return TST->template_arguments()[Index]; |
1055 | else |
1056 | return *CurrentTA; |
1057 | } |
1058 | |
1059 | /// operator-> - Allow access to the underlying TemplateArgument. |
1060 | pointer operator->() const { |
1061 | assert(TST && "InternalIterator is invalid with a null TST." ); |
1062 | return &operator*(); |
1063 | } |
1064 | }; |
1065 | |
1066 | InternalIterator SugaredIterator; |
1067 | InternalIterator DesugaredIterator; |
1068 | |
1069 | public: |
1070 | TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST) |
1071 | : SugaredIterator(TST), |
1072 | DesugaredIterator( |
1073 | (TST->isSugared() && !TST->isTypeAlias()) |
1074 | ? GetTemplateSpecializationType(Context, Ty: TST->desugar()) |
1075 | : nullptr) {} |
1076 | |
1077 | /// &operator++ - Increment the iterator to the next template argument. |
1078 | TSTiterator &operator++() { |
1079 | ++SugaredIterator; |
1080 | if (DesugaredIterator.isValid()) |
1081 | ++DesugaredIterator; |
1082 | return *this; |
1083 | } |
1084 | |
1085 | /// operator* - Returns the appropriate TemplateArgument. |
1086 | reference operator*() const { |
1087 | return *SugaredIterator; |
1088 | } |
1089 | |
1090 | /// operator-> - Allow access to the underlying TemplateArgument. |
1091 | pointer operator->() const { |
1092 | return &operator*(); |
1093 | } |
1094 | |
1095 | /// isEnd - Returns true if no more TemplateArguments are available. |
1096 | bool isEnd() const { |
1097 | return SugaredIterator.isEnd(); |
1098 | } |
1099 | |
1100 | /// hasDesugaredTA - Returns true if there is another TemplateArgument |
1101 | /// available. |
1102 | bool hasDesugaredTA() const { |
1103 | return DesugaredIterator.isValid() && !DesugaredIterator.isEnd(); |
1104 | } |
1105 | |
1106 | /// getDesugaredTA - Returns the desugared TemplateArgument. |
1107 | reference getDesugaredTA() const { |
1108 | assert(DesugaredIterator.isValid() && |
1109 | "Desugared TemplateArgument should not be used." ); |
1110 | return *DesugaredIterator; |
1111 | } |
1112 | }; |
1113 | |
1114 | // These functions build up the template diff tree, including functions to |
1115 | // retrieve and compare template arguments. |
1116 | |
1117 | static const TemplateSpecializationType *GetTemplateSpecializationType( |
1118 | ASTContext &Context, QualType Ty) { |
1119 | if (const TemplateSpecializationType *TST = |
1120 | Ty->getAs<TemplateSpecializationType>()) |
1121 | return TST; |
1122 | |
1123 | if (const auto* SubstType = Ty->getAs<SubstTemplateTypeParmType>()) |
1124 | Ty = SubstType->getReplacementType(); |
1125 | |
1126 | const RecordType *RT = Ty->getAs<RecordType>(); |
1127 | |
1128 | if (!RT) |
1129 | return nullptr; |
1130 | |
1131 | const ClassTemplateSpecializationDecl *CTSD = |
1132 | dyn_cast<ClassTemplateSpecializationDecl>(Val: RT->getDecl()); |
1133 | |
1134 | if (!CTSD) |
1135 | return nullptr; |
1136 | |
1137 | Ty = Context.getTemplateSpecializationType( |
1138 | T: TemplateName(CTSD->getSpecializedTemplate()), |
1139 | Args: CTSD->getTemplateArgs().asArray(), |
1140 | Canon: Ty.getLocalUnqualifiedType().getCanonicalType()); |
1141 | |
1142 | return Ty->getAs<TemplateSpecializationType>(); |
1143 | } |
1144 | |
1145 | /// Returns true if the DiffType is Type and false for Template. |
1146 | static bool OnlyPerformTypeDiff(ASTContext &Context, QualType FromType, |
1147 | QualType ToType, |
1148 | const TemplateSpecializationType *&FromArgTST, |
1149 | const TemplateSpecializationType *&ToArgTST) { |
1150 | if (FromType.isNull() || ToType.isNull()) |
1151 | return true; |
1152 | |
1153 | if (Context.hasSameType(T1: FromType, T2: ToType)) |
1154 | return true; |
1155 | |
1156 | FromArgTST = GetTemplateSpecializationType(Context, Ty: FromType); |
1157 | ToArgTST = GetTemplateSpecializationType(Context, Ty: ToType); |
1158 | |
1159 | if (!FromArgTST || !ToArgTST) |
1160 | return true; |
1161 | |
1162 | if (!hasSameTemplate(FromTST&: FromArgTST, ToTST&: ToArgTST)) |
1163 | return true; |
1164 | |
1165 | return false; |
1166 | } |
1167 | |
1168 | /// DiffTypes - Fills a DiffNode with information about a type difference. |
1169 | void DiffTypes(const TSTiterator &FromIter, const TSTiterator &ToIter) { |
1170 | QualType FromType = GetType(Iter: FromIter); |
1171 | QualType ToType = GetType(Iter: ToIter); |
1172 | |
1173 | bool FromDefault = FromIter.isEnd() && !FromType.isNull(); |
1174 | bool ToDefault = ToIter.isEnd() && !ToType.isNull(); |
1175 | |
1176 | const TemplateSpecializationType *FromArgTST = nullptr; |
1177 | const TemplateSpecializationType *ToArgTST = nullptr; |
1178 | if (OnlyPerformTypeDiff(Context, FromType, ToType, FromArgTST, ToArgTST)) { |
1179 | Tree.SetTypeDiff(FromType, ToType, FromDefault, ToDefault); |
1180 | Tree.SetSame(!FromType.isNull() && !ToType.isNull() && |
1181 | Context.hasSameType(T1: FromType, T2: ToType)); |
1182 | } else { |
1183 | assert(FromArgTST && ToArgTST && |
1184 | "Both template specializations need to be valid." ); |
1185 | Qualifiers FromQual = FromType.getQualifiers(), |
1186 | ToQual = ToType.getQualifiers(); |
1187 | FromQual -= QualType(FromArgTST, 0).getQualifiers(); |
1188 | ToQual -= QualType(ToArgTST, 0).getQualifiers(); |
1189 | Tree.SetTemplateDiff(FromTD: FromArgTST->getTemplateName().getAsTemplateDecl(), |
1190 | ToTD: ToArgTST->getTemplateName().getAsTemplateDecl(), |
1191 | FromQual, ToQual, FromDefault, ToDefault); |
1192 | DiffTemplate(FromTST: FromArgTST, ToTST: ToArgTST); |
1193 | } |
1194 | } |
1195 | |
1196 | /// DiffTemplateTemplates - Fills a DiffNode with information about a |
1197 | /// template template difference. |
1198 | void DiffTemplateTemplates(const TSTiterator &FromIter, |
1199 | const TSTiterator &ToIter) { |
1200 | TemplateDecl *FromDecl = GetTemplateDecl(Iter: FromIter); |
1201 | TemplateDecl *ToDecl = GetTemplateDecl(Iter: ToIter); |
1202 | Tree.SetTemplateTemplateDiff(FromTD: FromDecl, ToTD: ToDecl, FromDefault: FromIter.isEnd() && FromDecl, |
1203 | ToDefault: ToIter.isEnd() && ToDecl); |
1204 | Tree.SetSame(FromDecl && ToDecl && |
1205 | FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl()); |
1206 | } |
1207 | |
1208 | /// InitializeNonTypeDiffVariables - Helper function for DiffNonTypes |
1209 | static void InitializeNonTypeDiffVariables(ASTContext &Context, |
1210 | const TSTiterator &Iter, |
1211 | NonTypeTemplateParmDecl *Default, |
1212 | llvm::APSInt &Value, bool &HasInt, |
1213 | QualType &IntType, bool &IsNullPtr, |
1214 | Expr *&E, ValueDecl *&VD, |
1215 | bool &NeedAddressOf) { |
1216 | if (!Iter.isEnd()) { |
1217 | switch (Iter->getKind()) { |
1218 | case TemplateArgument::StructuralValue: |
1219 | // FIXME: Diffing of structural values is not implemented. |
1220 | // There is no possible fallback in this case, this will show up |
1221 | // as '(no argument)'. |
1222 | return; |
1223 | case TemplateArgument::Integral: |
1224 | Value = Iter->getAsIntegral(); |
1225 | HasInt = true; |
1226 | IntType = Iter->getIntegralType(); |
1227 | return; |
1228 | case TemplateArgument::Declaration: { |
1229 | VD = Iter->getAsDecl(); |
1230 | QualType ArgType = Iter->getParamTypeForDecl(); |
1231 | QualType VDType = VD->getType(); |
1232 | if (ArgType->isPointerType() && |
1233 | Context.hasSameType(T1: ArgType->getPointeeType(), T2: VDType)) |
1234 | NeedAddressOf = true; |
1235 | return; |
1236 | } |
1237 | case TemplateArgument::NullPtr: |
1238 | IsNullPtr = true; |
1239 | return; |
1240 | case TemplateArgument::Expression: |
1241 | E = Iter->getAsExpr(); |
1242 | break; |
1243 | case TemplateArgument::Null: |
1244 | case TemplateArgument::Type: |
1245 | case TemplateArgument::Template: |
1246 | case TemplateArgument::TemplateExpansion: |
1247 | llvm_unreachable("TemplateArgument kind is not expected for NTTP" ); |
1248 | case TemplateArgument::Pack: |
1249 | llvm_unreachable("TemplateArgument kind should be handled elsewhere" ); |
1250 | } |
1251 | } else if (!Default->isParameterPack()) { |
1252 | E = Default->getDefaultArgument().getArgument().getAsExpr(); |
1253 | } |
1254 | |
1255 | if (!Iter.hasDesugaredTA()) |
1256 | return; |
1257 | |
1258 | const TemplateArgument &TA = Iter.getDesugaredTA(); |
1259 | switch (TA.getKind()) { |
1260 | case TemplateArgument::StructuralValue: |
1261 | // FIXME: Diffing of structural values is not implemented. |
1262 | // Just fall back to the expression. |
1263 | return; |
1264 | case TemplateArgument::Integral: |
1265 | Value = TA.getAsIntegral(); |
1266 | HasInt = true; |
1267 | IntType = TA.getIntegralType(); |
1268 | return; |
1269 | case TemplateArgument::Declaration: { |
1270 | VD = TA.getAsDecl(); |
1271 | QualType ArgType = TA.getParamTypeForDecl(); |
1272 | QualType VDType = VD->getType(); |
1273 | if (ArgType->isPointerType() && |
1274 | Context.hasSameType(T1: ArgType->getPointeeType(), T2: VDType)) |
1275 | NeedAddressOf = true; |
1276 | return; |
1277 | } |
1278 | case TemplateArgument::NullPtr: |
1279 | IsNullPtr = true; |
1280 | return; |
1281 | case TemplateArgument::Expression: |
1282 | // TODO: Sometimes, the desugared template argument Expr differs from |
1283 | // the sugared template argument Expr. It may be useful in the future |
1284 | // but for now, it is just discarded. |
1285 | if (!E) |
1286 | E = TA.getAsExpr(); |
1287 | return; |
1288 | case TemplateArgument::Null: |
1289 | case TemplateArgument::Type: |
1290 | case TemplateArgument::Template: |
1291 | case TemplateArgument::TemplateExpansion: |
1292 | llvm_unreachable("TemplateArgument kind is not expected for NTTP" ); |
1293 | case TemplateArgument::Pack: |
1294 | llvm_unreachable("TemplateArgument kind should be handled elsewhere" ); |
1295 | } |
1296 | llvm_unreachable("Unexpected TemplateArgument kind" ); |
1297 | } |
1298 | |
1299 | /// DiffNonTypes - Handles any template parameters not handled by DiffTypes |
1300 | /// of DiffTemplatesTemplates, such as integer and declaration parameters. |
1301 | void DiffNonTypes(const TSTiterator &FromIter, const TSTiterator &ToIter, |
1302 | NonTypeTemplateParmDecl *FromDefaultNonTypeDecl, |
1303 | NonTypeTemplateParmDecl *ToDefaultNonTypeDecl) { |
1304 | Expr *FromExpr = nullptr, *ToExpr = nullptr; |
1305 | llvm::APSInt FromInt, ToInt; |
1306 | QualType FromIntType, ToIntType; |
1307 | ValueDecl *FromValueDecl = nullptr, *ToValueDecl = nullptr; |
1308 | bool HasFromInt = false, HasToInt = false, FromNullPtr = false, |
1309 | ToNullPtr = false, NeedFromAddressOf = false, NeedToAddressOf = false; |
1310 | InitializeNonTypeDiffVariables( |
1311 | Context, Iter: FromIter, Default: FromDefaultNonTypeDecl, Value&: FromInt, HasInt&: HasFromInt, |
1312 | IntType&: FromIntType, IsNullPtr&: FromNullPtr, E&: FromExpr, VD&: FromValueDecl, NeedAddressOf&: NeedFromAddressOf); |
1313 | InitializeNonTypeDiffVariables(Context, Iter: ToIter, Default: ToDefaultNonTypeDecl, Value&: ToInt, |
1314 | HasInt&: HasToInt, IntType&: ToIntType, IsNullPtr&: ToNullPtr, E&: ToExpr, |
1315 | VD&: ToValueDecl, NeedAddressOf&: NeedToAddressOf); |
1316 | |
1317 | bool FromDefault = FromIter.isEnd() && |
1318 | (FromExpr || FromValueDecl || HasFromInt || FromNullPtr); |
1319 | bool ToDefault = ToIter.isEnd() && |
1320 | (ToExpr || ToValueDecl || HasToInt || ToNullPtr); |
1321 | |
1322 | bool FromDeclaration = FromValueDecl || FromNullPtr; |
1323 | bool ToDeclaration = ToValueDecl || ToNullPtr; |
1324 | |
1325 | if (FromDeclaration && HasToInt) { |
1326 | Tree.SetFromDeclarationAndToIntegerDiff( |
1327 | FromValueDecl, FromAddressOf: NeedFromAddressOf, FromNullPtr, FromExpr, ToInt, |
1328 | IsValidToInt: HasToInt, ToIntType, ToExpr, FromDefault, ToDefault); |
1329 | Tree.SetSame(false); |
1330 | return; |
1331 | |
1332 | } |
1333 | |
1334 | if (HasFromInt && ToDeclaration) { |
1335 | Tree.SetFromIntegerAndToDeclarationDiff( |
1336 | FromInt, IsValidFromInt: HasFromInt, FromIntType, FromExpr, ToValueDecl, |
1337 | ToAddressOf: NeedToAddressOf, ToNullPtr, ToExpr, FromDefault, ToDefault); |
1338 | Tree.SetSame(false); |
1339 | return; |
1340 | } |
1341 | |
1342 | if (HasFromInt || HasToInt) { |
1343 | Tree.SetIntegerDiff(FromInt, ToInt, IsValidFromInt: HasFromInt, IsValidToInt: HasToInt, FromIntType, |
1344 | ToIntType, FromExpr, ToExpr, FromDefault, ToDefault); |
1345 | if (HasFromInt && HasToInt) { |
1346 | Tree.SetSame(Context.hasSameType(T1: FromIntType, T2: ToIntType) && |
1347 | FromInt == ToInt); |
1348 | } |
1349 | return; |
1350 | } |
1351 | |
1352 | if (FromDeclaration || ToDeclaration) { |
1353 | Tree.SetDeclarationDiff(FromValueDecl, ToValueDecl, FromAddressOf: NeedFromAddressOf, |
1354 | ToAddressOf: NeedToAddressOf, FromNullPtr, ToNullPtr, FromExpr, |
1355 | ToExpr, FromDefault, ToDefault); |
1356 | bool BothNull = FromNullPtr && ToNullPtr; |
1357 | bool SameValueDecl = |
1358 | FromValueDecl && ToValueDecl && |
1359 | NeedFromAddressOf == NeedToAddressOf && |
1360 | FromValueDecl->getCanonicalDecl() == ToValueDecl->getCanonicalDecl(); |
1361 | Tree.SetSame(BothNull || SameValueDecl); |
1362 | return; |
1363 | } |
1364 | |
1365 | assert((FromExpr || ToExpr) && "Both template arguments cannot be empty." ); |
1366 | Tree.SetExpressionDiff(FromExpr, ToExpr, FromDefault, ToDefault); |
1367 | Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr)); |
1368 | } |
1369 | |
1370 | /// DiffTemplate - recursively visits template arguments and stores the |
1371 | /// argument info into a tree. |
1372 | void DiffTemplate(const TemplateSpecializationType *FromTST, |
1373 | const TemplateSpecializationType *ToTST) { |
1374 | // Begin descent into diffing template tree. |
1375 | TemplateParameterList *ParamsFrom = |
1376 | FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters(); |
1377 | TemplateParameterList *ParamsTo = |
1378 | ToTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters(); |
1379 | unsigned TotalArgs = 0; |
1380 | for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST); |
1381 | !FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) { |
1382 | Tree.AddNode(); |
1383 | |
1384 | // Get the parameter at index TotalArgs. If index is larger |
1385 | // than the total number of parameters, then there is an |
1386 | // argument pack, so re-use the last parameter. |
1387 | unsigned FromParamIndex = std::min(a: TotalArgs, b: ParamsFrom->size() - 1); |
1388 | unsigned ToParamIndex = std::min(a: TotalArgs, b: ParamsTo->size() - 1); |
1389 | NamedDecl *FromParamND = ParamsFrom->getParam(Idx: FromParamIndex); |
1390 | NamedDecl *ToParamND = ParamsTo->getParam(Idx: ToParamIndex); |
1391 | |
1392 | assert(FromParamND->getKind() == ToParamND->getKind() && |
1393 | "Parameter Decl are not the same kind." ); |
1394 | |
1395 | if (isa<TemplateTypeParmDecl>(Val: FromParamND)) { |
1396 | DiffTypes(FromIter, ToIter); |
1397 | } else if (isa<TemplateTemplateParmDecl>(Val: FromParamND)) { |
1398 | DiffTemplateTemplates(FromIter, ToIter); |
1399 | } else if (isa<NonTypeTemplateParmDecl>(Val: FromParamND)) { |
1400 | NonTypeTemplateParmDecl *FromDefaultNonTypeDecl = |
1401 | cast<NonTypeTemplateParmDecl>(Val: FromParamND); |
1402 | NonTypeTemplateParmDecl *ToDefaultNonTypeDecl = |
1403 | cast<NonTypeTemplateParmDecl>(Val: ToParamND); |
1404 | DiffNonTypes(FromIter, ToIter, FromDefaultNonTypeDecl, |
1405 | ToDefaultNonTypeDecl); |
1406 | } else { |
1407 | llvm_unreachable("Unexpected Decl type." ); |
1408 | } |
1409 | |
1410 | ++FromIter; |
1411 | ++ToIter; |
1412 | Tree.Up(); |
1413 | } |
1414 | } |
1415 | |
1416 | /// makeTemplateList - Dump every template alias into the vector. |
1417 | static void makeTemplateList( |
1418 | SmallVectorImpl<const TemplateSpecializationType *> &TemplateList, |
1419 | const TemplateSpecializationType *TST) { |
1420 | while (TST) { |
1421 | TemplateList.push_back(Elt: TST); |
1422 | if (!TST->isTypeAlias()) |
1423 | return; |
1424 | TST = TST->getAliasedType()->getAs<TemplateSpecializationType>(); |
1425 | } |
1426 | } |
1427 | |
1428 | /// hasSameBaseTemplate - Returns true when the base templates are the same, |
1429 | /// even if the template arguments are not. |
1430 | static bool hasSameBaseTemplate(const TemplateSpecializationType *FromTST, |
1431 | const TemplateSpecializationType *ToTST) { |
1432 | return FromTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl() == |
1433 | ToTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl(); |
1434 | } |
1435 | |
1436 | /// hasSameTemplate - Returns true if both types are specialized from the |
1437 | /// same template declaration. If they come from different template aliases, |
1438 | /// do a parallel ascension search to determine the highest template alias in |
1439 | /// common and set the arguments to them. |
1440 | static bool hasSameTemplate(const TemplateSpecializationType *&FromTST, |
1441 | const TemplateSpecializationType *&ToTST) { |
1442 | // Check the top templates if they are the same. |
1443 | if (hasSameBaseTemplate(FromTST, ToTST)) |
1444 | return true; |
1445 | |
1446 | // Create vectors of template aliases. |
1447 | SmallVector<const TemplateSpecializationType*, 1> FromTemplateList, |
1448 | ToTemplateList; |
1449 | |
1450 | makeTemplateList(TemplateList&: FromTemplateList, TST: FromTST); |
1451 | makeTemplateList(TemplateList&: ToTemplateList, TST: ToTST); |
1452 | |
1453 | SmallVectorImpl<const TemplateSpecializationType *>::reverse_iterator |
1454 | FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(), |
1455 | ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend(); |
1456 | |
1457 | // Check if the lowest template types are the same. If not, return. |
1458 | if (!hasSameBaseTemplate(FromTST: *FromIter, ToTST: *ToIter)) |
1459 | return false; |
1460 | |
1461 | // Begin searching up the template aliases. The bottom most template |
1462 | // matches so move up until one pair does not match. Use the template |
1463 | // right before that one. |
1464 | for (; FromIter != FromEnd && ToIter != ToEnd; ++FromIter, ++ToIter) { |
1465 | if (!hasSameBaseTemplate(FromTST: *FromIter, ToTST: *ToIter)) |
1466 | break; |
1467 | } |
1468 | |
1469 | FromTST = FromIter[-1]; |
1470 | ToTST = ToIter[-1]; |
1471 | |
1472 | return true; |
1473 | } |
1474 | |
1475 | /// GetType - Retrieves the template type arguments, including default |
1476 | /// arguments. |
1477 | static QualType GetType(const TSTiterator &Iter) { |
1478 | if (!Iter.isEnd()) |
1479 | return Iter->getAsType(); |
1480 | if (Iter.hasDesugaredTA()) |
1481 | return Iter.getDesugaredTA().getAsType(); |
1482 | return QualType(); |
1483 | } |
1484 | |
1485 | /// GetTemplateDecl - Retrieves the template template arguments, including |
1486 | /// default arguments. |
1487 | static TemplateDecl *GetTemplateDecl(const TSTiterator &Iter) { |
1488 | if (!Iter.isEnd()) |
1489 | return Iter->getAsTemplate().getAsTemplateDecl(); |
1490 | if (Iter.hasDesugaredTA()) |
1491 | return Iter.getDesugaredTA().getAsTemplate().getAsTemplateDecl(); |
1492 | return nullptr; |
1493 | } |
1494 | |
1495 | /// IsEqualExpr - Returns true if the expressions are the same in regards to |
1496 | /// template arguments. These expressions are dependent, so profile them |
1497 | /// instead of trying to evaluate them. |
1498 | static bool IsEqualExpr(ASTContext &Context, Expr *FromExpr, Expr *ToExpr) { |
1499 | if (FromExpr == ToExpr) |
1500 | return true; |
1501 | |
1502 | if (!FromExpr || !ToExpr) |
1503 | return false; |
1504 | |
1505 | llvm::FoldingSetNodeID FromID, ToID; |
1506 | FromExpr->Profile(ID&: FromID, Context, Canonical: true); |
1507 | ToExpr->Profile(ID&: ToID, Context, Canonical: true); |
1508 | return FromID == ToID; |
1509 | } |
1510 | |
1511 | // These functions converts the tree representation of the template |
1512 | // differences into the internal character vector. |
1513 | |
1514 | /// TreeToString - Converts the Tree object into a character stream which |
1515 | /// will later be turned into the output string. |
1516 | void TreeToString(int Indent = 1) { |
1517 | if (PrintTree) { |
1518 | OS << '\n'; |
1519 | OS.indent(NumSpaces: 2 * Indent); |
1520 | ++Indent; |
1521 | } |
1522 | |
1523 | // Handle cases where the difference is not templates with different |
1524 | // arguments. |
1525 | switch (Tree.GetKind()) { |
1526 | case DiffTree::Invalid: |
1527 | llvm_unreachable("Template diffing failed with bad DiffNode" ); |
1528 | case DiffTree::Type: { |
1529 | QualType FromType, ToType; |
1530 | Tree.GetTypeDiff(FromType, ToType); |
1531 | PrintTypeNames(FromType, ToType, FromDefault: Tree.FromDefault(), ToDefault: Tree.ToDefault(), |
1532 | Same: Tree.NodeIsSame()); |
1533 | return; |
1534 | } |
1535 | case DiffTree::Expression: { |
1536 | Expr *FromExpr, *ToExpr; |
1537 | Tree.GetExpressionDiff(FromExpr, ToExpr); |
1538 | PrintExpr(FromExpr, ToExpr, FromDefault: Tree.FromDefault(), ToDefault: Tree.ToDefault(), |
1539 | Same: Tree.NodeIsSame()); |
1540 | return; |
1541 | } |
1542 | case DiffTree::TemplateTemplate: { |
1543 | TemplateDecl *FromTD, *ToTD; |
1544 | Tree.GetTemplateTemplateDiff(FromTD, ToTD); |
1545 | PrintTemplateTemplate(FromTD, ToTD, FromDefault: Tree.FromDefault(), |
1546 | ToDefault: Tree.ToDefault(), Same: Tree.NodeIsSame()); |
1547 | return; |
1548 | } |
1549 | case DiffTree::Integer: { |
1550 | llvm::APSInt FromInt, ToInt; |
1551 | Expr *FromExpr, *ToExpr; |
1552 | bool IsValidFromInt, IsValidToInt; |
1553 | QualType FromIntType, ToIntType; |
1554 | Tree.GetIntegerDiff(FromInt, ToInt, IsValidFromInt, IsValidToInt, |
1555 | FromIntType, ToIntType, FromExpr, ToExpr); |
1556 | PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt, FromIntType, |
1557 | ToIntType, FromExpr, ToExpr, FromDefault: Tree.FromDefault(), |
1558 | ToDefault: Tree.ToDefault(), Same: Tree.NodeIsSame()); |
1559 | return; |
1560 | } |
1561 | case DiffTree::Declaration: { |
1562 | ValueDecl *FromValueDecl, *ToValueDecl; |
1563 | bool FromAddressOf, ToAddressOf; |
1564 | bool FromNullPtr, ToNullPtr; |
1565 | Expr *FromExpr, *ToExpr; |
1566 | Tree.GetDeclarationDiff(FromValueDecl, ToValueDecl, FromAddressOf, |
1567 | ToAddressOf, FromNullPtr, ToNullPtr, FromExpr, |
1568 | ToExpr); |
1569 | PrintValueDecl(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf, |
1570 | FromNullPtr, ToNullPtr, FromExpr, ToExpr, |
1571 | FromDefault: Tree.FromDefault(), ToDefault: Tree.ToDefault(), Same: Tree.NodeIsSame()); |
1572 | return; |
1573 | } |
1574 | case DiffTree::FromDeclarationAndToInteger: { |
1575 | ValueDecl *FromValueDecl; |
1576 | bool FromAddressOf; |
1577 | bool FromNullPtr; |
1578 | Expr *FromExpr; |
1579 | llvm::APSInt ToInt; |
1580 | bool IsValidToInt; |
1581 | QualType ToIntType; |
1582 | Expr *ToExpr; |
1583 | Tree.GetFromDeclarationAndToIntegerDiff( |
1584 | FromValueDecl, FromAddressOf, FromNullPtr, FromExpr, ToInt, |
1585 | IsValidToInt, ToIntType, ToExpr); |
1586 | assert((FromValueDecl || FromNullPtr) && IsValidToInt); |
1587 | PrintValueDeclAndInteger(VD: FromValueDecl, NeedAddressOf: FromAddressOf, IsNullPtr: FromNullPtr, |
1588 | VDExpr: FromExpr, DefaultDecl: Tree.FromDefault(), Val: ToInt, IntType: ToIntType, |
1589 | IntExpr: ToExpr, DefaultInt: Tree.ToDefault()); |
1590 | return; |
1591 | } |
1592 | case DiffTree::FromIntegerAndToDeclaration: { |
1593 | llvm::APSInt FromInt; |
1594 | bool IsValidFromInt; |
1595 | QualType FromIntType; |
1596 | Expr *FromExpr; |
1597 | ValueDecl *ToValueDecl; |
1598 | bool ToAddressOf; |
1599 | bool ToNullPtr; |
1600 | Expr *ToExpr; |
1601 | Tree.GetFromIntegerAndToDeclarationDiff( |
1602 | FromInt, IsValidFromInt, FromIntType, FromExpr, ToValueDecl, |
1603 | ToAddressOf, ToNullPtr, ToExpr); |
1604 | assert(IsValidFromInt && (ToValueDecl || ToNullPtr)); |
1605 | PrintIntegerAndValueDecl(Val: FromInt, IntType: FromIntType, IntExpr: FromExpr, |
1606 | DefaultInt: Tree.FromDefault(), VD: ToValueDecl, NeedAddressOf: ToAddressOf, |
1607 | IsNullPtr: ToNullPtr, VDExpr: ToExpr, DefaultDecl: Tree.ToDefault()); |
1608 | return; |
1609 | } |
1610 | case DiffTree::Template: { |
1611 | // Node is root of template. Recurse on children. |
1612 | TemplateDecl *FromTD, *ToTD; |
1613 | Qualifiers FromQual, ToQual; |
1614 | Tree.GetTemplateDiff(FromTD, ToTD, FromQual, ToQual); |
1615 | |
1616 | PrintQualifiers(FromQual, ToQual); |
1617 | |
1618 | if (!Tree.HasChildren()) { |
1619 | // If we're dealing with a template specialization with zero |
1620 | // arguments, there are no children; special-case this. |
1621 | OS << FromTD->getDeclName() << "<>" ; |
1622 | return; |
1623 | } |
1624 | |
1625 | OS << FromTD->getDeclName() << '<'; |
1626 | Tree.MoveToChild(); |
1627 | unsigned NumElideArgs = 0; |
1628 | bool AllArgsElided = true; |
1629 | do { |
1630 | if (ElideType) { |
1631 | if (Tree.NodeIsSame()) { |
1632 | ++NumElideArgs; |
1633 | continue; |
1634 | } |
1635 | AllArgsElided = false; |
1636 | if (NumElideArgs > 0) { |
1637 | PrintElideArgs(NumElideArgs, Indent); |
1638 | NumElideArgs = 0; |
1639 | OS << ", " ; |
1640 | } |
1641 | } |
1642 | TreeToString(Indent); |
1643 | if (Tree.HasNextSibling()) |
1644 | OS << ", " ; |
1645 | } while (Tree.AdvanceSibling()); |
1646 | if (NumElideArgs > 0) { |
1647 | if (AllArgsElided) |
1648 | OS << "..." ; |
1649 | else |
1650 | PrintElideArgs(NumElideArgs, Indent); |
1651 | } |
1652 | |
1653 | Tree.Parent(); |
1654 | OS << ">" ; |
1655 | return; |
1656 | } |
1657 | } |
1658 | } |
1659 | |
1660 | // To signal to the text printer that a certain text needs to be bolded, |
1661 | // a special character is injected into the character stream which the |
1662 | // text printer will later strip out. |
1663 | |
1664 | /// Bold - Start bolding text. |
1665 | void Bold() { |
1666 | assert(!IsBold && "Attempting to bold text that is already bold." ); |
1667 | IsBold = true; |
1668 | if (ShowColor) |
1669 | OS << ToggleHighlight; |
1670 | } |
1671 | |
1672 | /// Unbold - Stop bolding text. |
1673 | void Unbold() { |
1674 | assert(IsBold && "Attempting to remove bold from unbold text." ); |
1675 | IsBold = false; |
1676 | if (ShowColor) |
1677 | OS << ToggleHighlight; |
1678 | } |
1679 | |
1680 | // Functions to print out the arguments and highlighting the difference. |
1681 | |
1682 | /// PrintTypeNames - prints the typenames, bolding differences. Will detect |
1683 | /// typenames that are the same and attempt to disambiguate them by using |
1684 | /// canonical typenames. |
1685 | void PrintTypeNames(QualType FromType, QualType ToType, |
1686 | bool FromDefault, bool ToDefault, bool Same) { |
1687 | assert((!FromType.isNull() || !ToType.isNull()) && |
1688 | "Only one template argument may be missing." ); |
1689 | |
1690 | if (Same) { |
1691 | OS << FromType.getAsString(Policy); |
1692 | return; |
1693 | } |
1694 | |
1695 | if (!FromType.isNull() && !ToType.isNull() && |
1696 | FromType.getLocalUnqualifiedType() == |
1697 | ToType.getLocalUnqualifiedType()) { |
1698 | Qualifiers FromQual = FromType.getLocalQualifiers(), |
1699 | ToQual = ToType.getLocalQualifiers(); |
1700 | PrintQualifiers(FromQual, ToQual); |
1701 | FromType.getLocalUnqualifiedType().print(OS, Policy); |
1702 | return; |
1703 | } |
1704 | |
1705 | std::string FromTypeStr = FromType.isNull() ? "(no argument)" |
1706 | : FromType.getAsString(Policy); |
1707 | std::string ToTypeStr = ToType.isNull() ? "(no argument)" |
1708 | : ToType.getAsString(Policy); |
1709 | // Print without ElaboratedType sugar if it is better. |
1710 | // TODO: merge this with other aka printing above. |
1711 | if (FromTypeStr == ToTypeStr) { |
1712 | const auto *FromElTy = dyn_cast<ElaboratedType>(Val&: FromType), |
1713 | *ToElTy = dyn_cast<ElaboratedType>(Val&: ToType); |
1714 | if (FromElTy || ToElTy) { |
1715 | std::string FromNamedTypeStr = |
1716 | FromElTy ? FromElTy->getNamedType().getAsString(Policy) |
1717 | : FromTypeStr; |
1718 | std::string ToNamedTypeStr = |
1719 | ToElTy ? ToElTy->getNamedType().getAsString(Policy) : ToTypeStr; |
1720 | if (FromNamedTypeStr != ToNamedTypeStr) { |
1721 | FromTypeStr = FromNamedTypeStr; |
1722 | ToTypeStr = ToNamedTypeStr; |
1723 | goto PrintTypes; |
1724 | } |
1725 | } |
1726 | // Switch to canonical typename if it is better. |
1727 | std::string FromCanTypeStr = |
1728 | FromType.getCanonicalType().getAsString(Policy); |
1729 | std::string ToCanTypeStr = ToType.getCanonicalType().getAsString(Policy); |
1730 | if (FromCanTypeStr != ToCanTypeStr) { |
1731 | FromTypeStr = FromCanTypeStr; |
1732 | ToTypeStr = ToCanTypeStr; |
1733 | } |
1734 | } |
1735 | |
1736 | PrintTypes: |
1737 | if (PrintTree) OS << '['; |
1738 | OS << (FromDefault ? "(default) " : "" ); |
1739 | Bold(); |
1740 | OS << FromTypeStr; |
1741 | Unbold(); |
1742 | if (PrintTree) { |
1743 | OS << " != " << (ToDefault ? "(default) " : "" ); |
1744 | Bold(); |
1745 | OS << ToTypeStr; |
1746 | Unbold(); |
1747 | OS << "]" ; |
1748 | } |
1749 | } |
1750 | |
1751 | /// PrintExpr - Prints out the expr template arguments, highlighting argument |
1752 | /// differences. |
1753 | void PrintExpr(const Expr *FromExpr, const Expr *ToExpr, bool FromDefault, |
1754 | bool ToDefault, bool Same) { |
1755 | assert((FromExpr || ToExpr) && |
1756 | "Only one template argument may be missing." ); |
1757 | if (Same) { |
1758 | PrintExpr(E: FromExpr); |
1759 | } else if (!PrintTree) { |
1760 | OS << (FromDefault ? "(default) " : "" ); |
1761 | Bold(); |
1762 | PrintExpr(E: FromExpr); |
1763 | Unbold(); |
1764 | } else { |
1765 | OS << (FromDefault ? "[(default) " : "[" ); |
1766 | Bold(); |
1767 | PrintExpr(E: FromExpr); |
1768 | Unbold(); |
1769 | OS << " != " << (ToDefault ? "(default) " : "" ); |
1770 | Bold(); |
1771 | PrintExpr(E: ToExpr); |
1772 | Unbold(); |
1773 | OS << ']'; |
1774 | } |
1775 | } |
1776 | |
1777 | /// PrintExpr - Actual formatting and printing of expressions. |
1778 | void PrintExpr(const Expr *E) { |
1779 | if (E) { |
1780 | E->printPretty(OS, Helper: nullptr, Policy); |
1781 | return; |
1782 | } |
1783 | OS << "(no argument)" ; |
1784 | } |
1785 | |
1786 | /// PrintTemplateTemplate - Handles printing of template template arguments, |
1787 | /// highlighting argument differences. |
1788 | void PrintTemplateTemplate(TemplateDecl *FromTD, TemplateDecl *ToTD, |
1789 | bool FromDefault, bool ToDefault, bool Same) { |
1790 | assert((FromTD || ToTD) && "Only one template argument may be missing." ); |
1791 | |
1792 | std::string FromName = |
1793 | std::string(FromTD ? FromTD->getName() : "(no argument)" ); |
1794 | std::string ToName = std::string(ToTD ? ToTD->getName() : "(no argument)" ); |
1795 | if (FromTD && ToTD && FromName == ToName) { |
1796 | FromName = FromTD->getQualifiedNameAsString(); |
1797 | ToName = ToTD->getQualifiedNameAsString(); |
1798 | } |
1799 | |
1800 | if (Same) { |
1801 | OS << "template " << FromTD->getDeclName(); |
1802 | } else if (!PrintTree) { |
1803 | OS << (FromDefault ? "(default) template " : "template " ); |
1804 | Bold(); |
1805 | OS << FromName; |
1806 | Unbold(); |
1807 | } else { |
1808 | OS << (FromDefault ? "[(default) template " : "[template " ); |
1809 | Bold(); |
1810 | OS << FromName; |
1811 | Unbold(); |
1812 | OS << " != " << (ToDefault ? "(default) template " : "template " ); |
1813 | Bold(); |
1814 | OS << ToName; |
1815 | Unbold(); |
1816 | OS << ']'; |
1817 | } |
1818 | } |
1819 | |
1820 | /// PrintAPSInt - Handles printing of integral arguments, highlighting |
1821 | /// argument differences. |
1822 | void PrintAPSInt(const llvm::APSInt &FromInt, const llvm::APSInt &ToInt, |
1823 | bool IsValidFromInt, bool IsValidToInt, QualType FromIntType, |
1824 | QualType ToIntType, Expr *FromExpr, Expr *ToExpr, |
1825 | bool FromDefault, bool ToDefault, bool Same) { |
1826 | assert((IsValidFromInt || IsValidToInt) && |
1827 | "Only one integral argument may be missing." ); |
1828 | |
1829 | if (Same) { |
1830 | if (FromIntType->isBooleanType()) { |
1831 | OS << ((FromInt == 0) ? "false" : "true" ); |
1832 | } else { |
1833 | OS << toString(I: FromInt, Radix: 10); |
1834 | } |
1835 | return; |
1836 | } |
1837 | |
1838 | bool PrintType = IsValidFromInt && IsValidToInt && |
1839 | !Context.hasSameType(T1: FromIntType, T2: ToIntType); |
1840 | |
1841 | if (!PrintTree) { |
1842 | OS << (FromDefault ? "(default) " : "" ); |
1843 | PrintAPSInt(Val: FromInt, E: FromExpr, Valid: IsValidFromInt, IntType: FromIntType, PrintType); |
1844 | } else { |
1845 | OS << (FromDefault ? "[(default) " : "[" ); |
1846 | PrintAPSInt(Val: FromInt, E: FromExpr, Valid: IsValidFromInt, IntType: FromIntType, PrintType); |
1847 | OS << " != " << (ToDefault ? "(default) " : "" ); |
1848 | PrintAPSInt(Val: ToInt, E: ToExpr, Valid: IsValidToInt, IntType: ToIntType, PrintType); |
1849 | OS << ']'; |
1850 | } |
1851 | } |
1852 | |
1853 | /// PrintAPSInt - If valid, print the APSInt. If the expression is |
1854 | /// gives more information, print it too. |
1855 | void PrintAPSInt(const llvm::APSInt &Val, Expr *E, bool Valid, |
1856 | QualType IntType, bool PrintType) { |
1857 | Bold(); |
1858 | if (Valid) { |
1859 | if (HasExtraInfo(E)) { |
1860 | PrintExpr(E); |
1861 | Unbold(); |
1862 | OS << " aka " ; |
1863 | Bold(); |
1864 | } |
1865 | if (PrintType) { |
1866 | Unbold(); |
1867 | OS << "(" ; |
1868 | Bold(); |
1869 | IntType.print(OS, Policy: Context.getPrintingPolicy()); |
1870 | Unbold(); |
1871 | OS << ") " ; |
1872 | Bold(); |
1873 | } |
1874 | if (IntType->isBooleanType()) { |
1875 | OS << ((Val == 0) ? "false" : "true" ); |
1876 | } else { |
1877 | OS << toString(I: Val, Radix: 10); |
1878 | } |
1879 | } else if (E) { |
1880 | PrintExpr(E); |
1881 | } else { |
1882 | OS << "(no argument)" ; |
1883 | } |
1884 | Unbold(); |
1885 | } |
1886 | |
1887 | /// HasExtraInfo - Returns true if E is not an integer literal, the |
1888 | /// negation of an integer literal, or a boolean literal. |
1889 | bool (Expr *E) { |
1890 | if (!E) return false; |
1891 | |
1892 | E = E->IgnoreImpCasts(); |
1893 | |
1894 | if (isa<IntegerLiteral>(Val: E)) return false; |
1895 | |
1896 | if (UnaryOperator *UO = dyn_cast<UnaryOperator>(Val: E)) |
1897 | if (UO->getOpcode() == UO_Minus) |
1898 | if (isa<IntegerLiteral>(Val: UO->getSubExpr())) |
1899 | return false; |
1900 | |
1901 | if (isa<CXXBoolLiteralExpr>(Val: E)) |
1902 | return false; |
1903 | |
1904 | return true; |
1905 | } |
1906 | |
1907 | void PrintValueDecl(ValueDecl *VD, bool AddressOf, Expr *E, bool NullPtr) { |
1908 | if (VD) { |
1909 | if (AddressOf) |
1910 | OS << "&" ; |
1911 | else if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(Val: VD)) { |
1912 | // FIXME: Diffing the APValue would be neat. |
1913 | // FIXME: Suppress this and use the full name of the declaration if the |
1914 | // parameter is a pointer or reference. |
1915 | TPO->getType().getUnqualifiedType().print(OS, Policy); |
1916 | TPO->printAsInit(OS, Policy); |
1917 | return; |
1918 | } |
1919 | VD->printName(OS, Policy); |
1920 | return; |
1921 | } |
1922 | |
1923 | if (NullPtr) { |
1924 | if (E && !isa<CXXNullPtrLiteralExpr>(Val: E)) { |
1925 | PrintExpr(E); |
1926 | if (IsBold) { |
1927 | Unbold(); |
1928 | OS << " aka " ; |
1929 | Bold(); |
1930 | } else { |
1931 | OS << " aka " ; |
1932 | } |
1933 | } |
1934 | |
1935 | OS << "nullptr" ; |
1936 | return; |
1937 | } |
1938 | |
1939 | if (E) { |
1940 | PrintExpr(E); |
1941 | return; |
1942 | } |
1943 | |
1944 | OS << "(no argument)" ; |
1945 | } |
1946 | |
1947 | /// PrintDecl - Handles printing of Decl arguments, highlighting |
1948 | /// argument differences. |
1949 | void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl, |
1950 | bool FromAddressOf, bool ToAddressOf, bool FromNullPtr, |
1951 | bool ToNullPtr, Expr *FromExpr, Expr *ToExpr, |
1952 | bool FromDefault, bool ToDefault, bool Same) { |
1953 | assert((FromValueDecl || FromNullPtr || ToValueDecl || ToNullPtr) && |
1954 | "Only one Decl argument may be NULL" ); |
1955 | |
1956 | if (Same) { |
1957 | PrintValueDecl(VD: FromValueDecl, AddressOf: FromAddressOf, E: FromExpr, NullPtr: FromNullPtr); |
1958 | } else if (!PrintTree) { |
1959 | OS << (FromDefault ? "(default) " : "" ); |
1960 | Bold(); |
1961 | PrintValueDecl(VD: FromValueDecl, AddressOf: FromAddressOf, E: FromExpr, NullPtr: FromNullPtr); |
1962 | Unbold(); |
1963 | } else { |
1964 | OS << (FromDefault ? "[(default) " : "[" ); |
1965 | Bold(); |
1966 | PrintValueDecl(VD: FromValueDecl, AddressOf: FromAddressOf, E: FromExpr, NullPtr: FromNullPtr); |
1967 | Unbold(); |
1968 | OS << " != " << (ToDefault ? "(default) " : "" ); |
1969 | Bold(); |
1970 | PrintValueDecl(VD: ToValueDecl, AddressOf: ToAddressOf, E: ToExpr, NullPtr: ToNullPtr); |
1971 | Unbold(); |
1972 | OS << ']'; |
1973 | } |
1974 | } |
1975 | |
1976 | /// PrintValueDeclAndInteger - Uses the print functions for ValueDecl and |
1977 | /// APSInt to print a mixed difference. |
1978 | void PrintValueDeclAndInteger(ValueDecl *VD, bool NeedAddressOf, |
1979 | bool IsNullPtr, Expr *VDExpr, bool DefaultDecl, |
1980 | const llvm::APSInt &Val, QualType IntType, |
1981 | Expr *IntExpr, bool DefaultInt) { |
1982 | if (!PrintTree) { |
1983 | OS << (DefaultDecl ? "(default) " : "" ); |
1984 | Bold(); |
1985 | PrintValueDecl(VD, AddressOf: NeedAddressOf, E: VDExpr, NullPtr: IsNullPtr); |
1986 | Unbold(); |
1987 | } else { |
1988 | OS << (DefaultDecl ? "[(default) " : "[" ); |
1989 | Bold(); |
1990 | PrintValueDecl(VD, AddressOf: NeedAddressOf, E: VDExpr, NullPtr: IsNullPtr); |
1991 | Unbold(); |
1992 | OS << " != " << (DefaultInt ? "(default) " : "" ); |
1993 | PrintAPSInt(Val, E: IntExpr, Valid: true /*Valid*/, IntType, PrintType: false /*PrintType*/); |
1994 | OS << ']'; |
1995 | } |
1996 | } |
1997 | |
1998 | /// PrintIntegerAndValueDecl - Uses the print functions for APSInt and |
1999 | /// ValueDecl to print a mixed difference. |
2000 | void PrintIntegerAndValueDecl(const llvm::APSInt &Val, QualType IntType, |
2001 | Expr *IntExpr, bool DefaultInt, ValueDecl *VD, |
2002 | bool NeedAddressOf, bool IsNullPtr, |
2003 | Expr *VDExpr, bool DefaultDecl) { |
2004 | if (!PrintTree) { |
2005 | OS << (DefaultInt ? "(default) " : "" ); |
2006 | PrintAPSInt(Val, E: IntExpr, Valid: true /*Valid*/, IntType, PrintType: false /*PrintType*/); |
2007 | } else { |
2008 | OS << (DefaultInt ? "[(default) " : "[" ); |
2009 | PrintAPSInt(Val, E: IntExpr, Valid: true /*Valid*/, IntType, PrintType: false /*PrintType*/); |
2010 | OS << " != " << (DefaultDecl ? "(default) " : "" ); |
2011 | Bold(); |
2012 | PrintValueDecl(VD, AddressOf: NeedAddressOf, E: VDExpr, NullPtr: IsNullPtr); |
2013 | Unbold(); |
2014 | OS << ']'; |
2015 | } |
2016 | } |
2017 | |
2018 | // Prints the appropriate placeholder for elided template arguments. |
2019 | void PrintElideArgs(unsigned NumElideArgs, unsigned Indent) { |
2020 | if (PrintTree) { |
2021 | OS << '\n'; |
2022 | for (unsigned i = 0; i < Indent; ++i) |
2023 | OS << " " ; |
2024 | } |
2025 | if (NumElideArgs == 0) return; |
2026 | if (NumElideArgs == 1) |
2027 | OS << "[...]" ; |
2028 | else |
2029 | OS << "[" << NumElideArgs << " * ...]" ; |
2030 | } |
2031 | |
2032 | // Prints and highlights differences in Qualifiers. |
2033 | void PrintQualifiers(Qualifiers FromQual, Qualifiers ToQual) { |
2034 | // Both types have no qualifiers |
2035 | if (FromQual.empty() && ToQual.empty()) |
2036 | return; |
2037 | |
2038 | // Both types have same qualifiers |
2039 | if (FromQual == ToQual) { |
2040 | PrintQualifier(Q: FromQual, /*ApplyBold*/false); |
2041 | return; |
2042 | } |
2043 | |
2044 | // Find common qualifiers and strip them from FromQual and ToQual. |
2045 | Qualifiers CommonQual = Qualifiers::removeCommonQualifiers(L&: FromQual, |
2046 | R&: ToQual); |
2047 | |
2048 | // The qualifiers are printed before the template name. |
2049 | // Inline printing: |
2050 | // The common qualifiers are printed. Then, qualifiers only in this type |
2051 | // are printed and highlighted. Finally, qualifiers only in the other |
2052 | // type are printed and highlighted inside parentheses after "missing". |
2053 | // Tree printing: |
2054 | // Qualifiers are printed next to each other, inside brackets, and |
2055 | // separated by "!=". The printing order is: |
2056 | // common qualifiers, highlighted from qualifiers, "!=", |
2057 | // common qualifiers, highlighted to qualifiers |
2058 | if (PrintTree) { |
2059 | OS << "[" ; |
2060 | if (CommonQual.empty() && FromQual.empty()) { |
2061 | Bold(); |
2062 | OS << "(no qualifiers) " ; |
2063 | Unbold(); |
2064 | } else { |
2065 | PrintQualifier(Q: CommonQual, /*ApplyBold*/false); |
2066 | PrintQualifier(Q: FromQual, /*ApplyBold*/true); |
2067 | } |
2068 | OS << "!= " ; |
2069 | if (CommonQual.empty() && ToQual.empty()) { |
2070 | Bold(); |
2071 | OS << "(no qualifiers)" ; |
2072 | Unbold(); |
2073 | } else { |
2074 | PrintQualifier(Q: CommonQual, /*ApplyBold*/false, |
2075 | /*appendSpaceIfNonEmpty*/AppendSpaceIfNonEmpty: !ToQual.empty()); |
2076 | PrintQualifier(Q: ToQual, /*ApplyBold*/true, |
2077 | /*appendSpaceIfNonEmpty*/AppendSpaceIfNonEmpty: false); |
2078 | } |
2079 | OS << "] " ; |
2080 | } else { |
2081 | PrintQualifier(Q: CommonQual, /*ApplyBold*/false); |
2082 | PrintQualifier(Q: FromQual, /*ApplyBold*/true); |
2083 | } |
2084 | } |
2085 | |
2086 | void PrintQualifier(Qualifiers Q, bool ApplyBold, |
2087 | bool AppendSpaceIfNonEmpty = true) { |
2088 | if (Q.empty()) return; |
2089 | if (ApplyBold) Bold(); |
2090 | Q.print(OS, Policy, appendSpaceIfNonEmpty: AppendSpaceIfNonEmpty); |
2091 | if (ApplyBold) Unbold(); |
2092 | } |
2093 | |
2094 | public: |
2095 | |
2096 | TemplateDiff(raw_ostream &OS, ASTContext &Context, QualType FromType, |
2097 | QualType ToType, bool PrintTree, bool PrintFromType, |
2098 | bool ElideType, bool ShowColor) |
2099 | : Context(Context), |
2100 | Policy(Context.getLangOpts()), |
2101 | ElideType(ElideType), |
2102 | PrintTree(PrintTree), |
2103 | ShowColor(ShowColor), |
2104 | // When printing a single type, the FromType is the one printed. |
2105 | FromTemplateType(PrintFromType ? FromType : ToType), |
2106 | ToTemplateType(PrintFromType ? ToType : FromType), |
2107 | OS(OS), |
2108 | IsBold(false) { |
2109 | } |
2110 | |
2111 | /// DiffTemplate - Start the template type diffing. |
2112 | void DiffTemplate() { |
2113 | Qualifiers FromQual = FromTemplateType.getQualifiers(), |
2114 | ToQual = ToTemplateType.getQualifiers(); |
2115 | |
2116 | const TemplateSpecializationType *FromOrigTST = |
2117 | GetTemplateSpecializationType(Context, Ty: FromTemplateType); |
2118 | const TemplateSpecializationType *ToOrigTST = |
2119 | GetTemplateSpecializationType(Context, Ty: ToTemplateType); |
2120 | |
2121 | // Only checking templates. |
2122 | if (!FromOrigTST || !ToOrigTST) |
2123 | return; |
2124 | |
2125 | // Different base templates. |
2126 | if (!hasSameTemplate(FromTST&: FromOrigTST, ToTST&: ToOrigTST)) { |
2127 | return; |
2128 | } |
2129 | |
2130 | FromQual -= QualType(FromOrigTST, 0).getQualifiers(); |
2131 | ToQual -= QualType(ToOrigTST, 0).getQualifiers(); |
2132 | |
2133 | // Same base template, but different arguments. |
2134 | Tree.SetTemplateDiff(FromTD: FromOrigTST->getTemplateName().getAsTemplateDecl(), |
2135 | ToTD: ToOrigTST->getTemplateName().getAsTemplateDecl(), |
2136 | FromQual, ToQual, FromDefault: false /*FromDefault*/, |
2137 | ToDefault: false /*ToDefault*/); |
2138 | |
2139 | DiffTemplate(FromTST: FromOrigTST, ToTST: ToOrigTST); |
2140 | } |
2141 | |
2142 | /// Emit - When the two types given are templated types with the same |
2143 | /// base template, a string representation of the type difference will be |
2144 | /// emitted to the stream and return true. Otherwise, return false. |
2145 | bool Emit() { |
2146 | Tree.StartTraverse(); |
2147 | if (Tree.Empty()) |
2148 | return false; |
2149 | |
2150 | TreeToString(); |
2151 | assert(!IsBold && "Bold is applied to end of string." ); |
2152 | return true; |
2153 | } |
2154 | }; // end class TemplateDiff |
2155 | } // end anonymous namespace |
2156 | |
2157 | /// FormatTemplateTypeDiff - A helper static function to start the template |
2158 | /// diff and return the properly formatted string. Returns true if the diff |
2159 | /// is successful. |
2160 | static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType, |
2161 | QualType ToType, bool PrintTree, |
2162 | bool PrintFromType, bool ElideType, |
2163 | bool ShowColors, raw_ostream &OS) { |
2164 | if (PrintTree) |
2165 | PrintFromType = true; |
2166 | TemplateDiff TD(OS, Context, FromType, ToType, PrintTree, PrintFromType, |
2167 | ElideType, ShowColors); |
2168 | TD.DiffTemplate(); |
2169 | return TD.Emit(); |
2170 | } |
2171 | |