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/ConvertUTF.h" |
24 | #include "llvm/Support/Format.h" |
25 | #include "llvm/Support/raw_ostream.h" |
26 | |
27 | using namespace clang; |
28 | |
29 | // Returns a desugared version of the QualType, and marks ShouldAKA as true |
30 | // whenever we remove significant sugar from the type. Make sure ShouldAKA |
31 | // is initialized before passing it in. |
32 | QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT, |
33 | bool &ShouldAKA) { |
34 | QualifierCollector QC; |
35 | |
36 | while (true) { |
37 | const Type *Ty = QC.strip(type: QT); |
38 | |
39 | // Don't aka just because we saw an elaborated type... |
40 | if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Val: Ty)) { |
41 | QT = ET->desugar(); |
42 | continue; |
43 | } |
44 | // ... or a using type ... |
45 | if (const UsingType *UT = dyn_cast<UsingType>(Val: Ty)) { |
46 | QT = UT->desugar(); |
47 | continue; |
48 | } |
49 | // ... or a paren type ... |
50 | if (const ParenType *PT = dyn_cast<ParenType>(Val: Ty)) { |
51 | QT = PT->desugar(); |
52 | continue; |
53 | } |
54 | // ... or a macro defined type ... |
55 | if (const MacroQualifiedType *MDT = dyn_cast<MacroQualifiedType>(Val: Ty)) { |
56 | QT = MDT->desugar(); |
57 | continue; |
58 | } |
59 | // ...or a substituted template type parameter ... |
60 | if (const SubstTemplateTypeParmType *ST = |
61 | dyn_cast<SubstTemplateTypeParmType>(Val: Ty)) { |
62 | QT = ST->desugar(); |
63 | continue; |
64 | } |
65 | // ...or an attributed type... |
66 | if (const AttributedType *AT = dyn_cast<AttributedType>(Val: Ty)) { |
67 | QT = AT->desugar(); |
68 | continue; |
69 | } |
70 | // ...or an adjusted type... |
71 | if (const AdjustedType *AT = dyn_cast<AdjustedType>(Val: Ty)) { |
72 | QT = AT->desugar(); |
73 | continue; |
74 | } |
75 | // ... or an auto type. |
76 | if (const AutoType *AT = dyn_cast<AutoType>(Val: Ty)) { |
77 | if (!AT->isSugared()) |
78 | break; |
79 | QT = AT->desugar(); |
80 | continue; |
81 | } |
82 | |
83 | // Desugar FunctionType if return type or any parameter type should be |
84 | // desugared. Preserve nullability attribute on desugared types. |
85 | if (const FunctionType *FT = dyn_cast<FunctionType>(Val: Ty)) { |
86 | bool DesugarReturn = false; |
87 | QualType SugarRT = FT->getReturnType(); |
88 | QualType RT = desugarForDiagnostic(Context, QT: SugarRT, ShouldAKA&: DesugarReturn); |
89 | if (auto nullability = AttributedType::stripOuterNullability(T&: SugarRT)) { |
90 | RT = Context.getAttributedType(nullability: *nullability, modifiedType: RT, equivalentType: RT); |
91 | } |
92 | |
93 | bool DesugarArgument = false; |
94 | SmallVector<QualType, 4> Args; |
95 | const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Val: FT); |
96 | if (FPT) { |
97 | for (QualType SugarPT : FPT->param_types()) { |
98 | QualType PT = desugarForDiagnostic(Context, QT: SugarPT, ShouldAKA&: DesugarArgument); |
99 | if (auto nullability = |
100 | AttributedType::stripOuterNullability(T&: SugarPT)) { |
101 | PT = Context.getAttributedType(nullability: *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(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(), SpecifiedArgs: Args, /*CanonicalArgs=*/std::nullopt, Underlying: 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(EltTy: ElementTy, NumElts: VAT->getSizeExpr(), |
148 | ASM: VAT->getSizeModifier(), |
149 | IndexTypeQuals: VAT->getIndexTypeCVRQualifiers()); |
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()); |
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>(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>(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, Ty->getPointeeType(), ShouldAKA)); |
219 | } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) { |
220 | QT = Context.getLValueReferenceType( |
221 | T: desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA)); |
222 | } else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) { |
223 | QT = Context.getRValueReferenceType( |
224 | T: desugarForDiagnostic(Context, 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, Ty->getBaseType(), ShouldAKA); |
229 | QT = Context.getObjCObjectType( |
230 | BaseType, Ty->getTypeArgsAsWritten(), |
231 | llvm::ArrayRef(Ty->qual_begin(), Ty->getNumProtocols()), |
232 | 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 | /*ResolveTemplateArguments=*/false, |
468 | /*PrintFinalScopeResOp=*/false); |
469 | break; |
470 | } |
471 | case DiagnosticsEngine::ak_declcontext: { |
472 | DeclContext *DC = reinterpret_cast<DeclContext *> (Val); |
473 | assert(DC && "Should never have a null declaration context"); |
474 | NeedQuotes = false; |
475 | |
476 | // FIXME: Get the strings for DeclContext from some localized place |
477 | if (DC->isTranslationUnit()) { |
478 | if (Context.getLangOpts().CPlusPlus) |
479 | OS << "the global namespace"; |
480 | else |
481 | OS << "the global scope"; |
482 | } else if (DC->isClosure()) { |
483 | OS << "block literal"; |
484 | } else if (isLambdaCallOperator(DC)) { |
485 | OS << "lambda expression"; |
486 | } else if (TypeDecl *Type = dyn_cast<TypeDecl>(Val: DC)) { |
487 | OS << ConvertTypeToDiagnosticString(Context, |
488 | Ty: Context.getTypeDeclType(Decl: Type), |
489 | PrevArgs, QualTypeVals); |
490 | } else { |
491 | assert(isa<NamedDecl>(DC) && "Expected a NamedDecl"); |
492 | NamedDecl *ND = cast<NamedDecl>(Val: DC); |
493 | if (isa<NamespaceDecl>(Val: ND)) |
494 | OS << "namespace "; |
495 | else if (isa<ObjCMethodDecl>(Val: ND)) |
496 | OS << "method "; |
497 | else if (isa<FunctionDecl>(Val: ND)) |
498 | OS << "function "; |
499 | |
500 | OS << '\''; |
501 | ND->getNameForDiagnostic(OS, Policy: Context.getPrintingPolicy(), Qualified: true); |
502 | OS << '\''; |
503 | } |
504 | break; |
505 | } |
506 | case DiagnosticsEngine::ak_attr: { |
507 | const Attr *At = reinterpret_cast<Attr *>(Val); |
508 | assert(At && "Received null Attr object!"); |
509 | OS << '\'' << At->getSpelling() << '\''; |
510 | NeedQuotes = false; |
511 | break; |
512 | } |
513 | case DiagnosticsEngine::ak_expr: { |
514 | const Expr *E = reinterpret_cast<Expr *>(Val); |
515 | assert(E && "Received null Expr!"); |
516 | E->printPretty(OS, /*Helper=*/nullptr, Context.getPrintingPolicy()); |
517 | break; |
518 | } |
519 | } |
520 | |
521 | if (NeedQuotes) { |
522 | Output.insert(I: Output.begin()+OldEnd, Elt: '\''); |
523 | Output.push_back(Elt: '\''); |
524 | } |
525 | } |
526 | |
527 | /// TemplateDiff - A class that constructs a pretty string for a pair of |
528 | /// QualTypes. For the pair of types, a diff tree will be created containing |
529 | /// all the information about the templates and template arguments. Afterwards, |
530 | /// the tree is transformed to a string according to the options passed in. |
531 | namespace { |
532 | class TemplateDiff { |
533 | /// Context - The ASTContext which is used for comparing template arguments. |
534 | ASTContext &Context; |
535 | |
536 | /// Policy - Used during expression printing. |
537 | PrintingPolicy Policy; |
538 | |
539 | /// ElideType - Option to elide identical types. |
540 | bool ElideType; |
541 | |
542 | /// PrintTree - Format output string as a tree. |
543 | bool PrintTree; |
544 | |
545 | /// ShowColor - Diagnostics support color, so bolding will be used. |
546 | bool ShowColor; |
547 | |
548 | /// FromTemplateType - When single type printing is selected, this is the |
549 | /// type to be printed. When tree printing is selected, this type will |
550 | /// show up first in the tree. |
551 | QualType FromTemplateType; |
552 | |
553 | /// ToTemplateType - The type that FromType is compared to. Only in tree |
554 | /// printing will this type be outputed. |
555 | QualType ToTemplateType; |
556 | |
557 | /// OS - The stream used to construct the output strings. |
558 | raw_ostream &OS; |
559 | |
560 | /// IsBold - Keeps track of the bold formatting for the output string. |
561 | bool IsBold; |
562 | |
563 | /// DiffTree - A tree representation the differences between two types. |
564 | class DiffTree { |
565 | public: |
566 | /// DiffKind - The difference in a DiffNode. Fields of |
567 | /// TemplateArgumentInfo needed by each difference can be found in the |
568 | /// Set* and Get* functions. |
569 | enum DiffKind { |
570 | /// Incomplete or invalid node. |
571 | Invalid, |
572 | /// Another level of templates |
573 | Template, |
574 | /// Type difference, all type differences except those falling under |
575 | /// the Template difference. |
576 | Type, |
577 | /// Expression difference, this is only when both arguments are |
578 | /// expressions. If one argument is an expression and the other is |
579 | /// Integer or Declaration, then use that diff type instead. |
580 | Expression, |
581 | /// Template argument difference |
582 | TemplateTemplate, |
583 | /// Integer difference |
584 | Integer, |
585 | /// Declaration difference, nullptr arguments are included here |
586 | Declaration, |
587 | /// One argument being integer and the other being declaration |
588 | FromIntegerAndToDeclaration, |
589 | FromDeclarationAndToInteger |
590 | }; |
591 | |
592 | private: |
593 | /// TemplateArgumentInfo - All the information needed to pretty print |
594 | /// a template argument. See the Set* and Get* functions to see which |
595 | /// fields are used for each DiffKind. |
596 | struct TemplateArgumentInfo { |
597 | QualType ArgType; |
598 | Qualifiers Qual; |
599 | llvm::APSInt Val; |
600 | bool IsValidInt = false; |
601 | Expr *ArgExpr = nullptr; |
602 | TemplateDecl *TD = nullptr; |
603 | ValueDecl *VD = nullptr; |
604 | bool NeedAddressOf = false; |
605 | bool IsNullPtr = false; |
606 | bool IsDefault = false; |
607 | }; |
608 | |
609 | /// DiffNode - The root node stores the original type. Each child node |
610 | /// stores template arguments of their parents. For templated types, the |
611 | /// template decl is also stored. |
612 | struct DiffNode { |
613 | DiffKind Kind = Invalid; |
614 | |
615 | /// NextNode - The index of the next sibling node or 0. |
616 | unsigned NextNode = 0; |
617 | |
618 | /// ChildNode - The index of the first child node or 0. |
619 | unsigned ChildNode = 0; |
620 | |
621 | /// ParentNode - The index of the parent node. |
622 | unsigned ParentNode = 0; |
623 | |
624 | TemplateArgumentInfo FromArgInfo, ToArgInfo; |
625 | |
626 | /// Same - Whether the two arguments evaluate to the same value. |
627 | bool Same = false; |
628 | |
629 | DiffNode(unsigned ParentNode = 0) : ParentNode(ParentNode) {} |
630 | }; |
631 | |
632 | /// FlatTree - A flattened tree used to store the DiffNodes. |
633 | SmallVector<DiffNode, 16> FlatTree; |
634 | |
635 | /// CurrentNode - The index of the current node being used. |
636 | unsigned CurrentNode; |
637 | |
638 | /// NextFreeNode - The index of the next unused node. Used when creating |
639 | /// child nodes. |
640 | unsigned NextFreeNode; |
641 | |
642 | /// ReadNode - The index of the current node being read. |
643 | unsigned ReadNode; |
644 | |
645 | public: |
646 | DiffTree() : CurrentNode(0), NextFreeNode(1), ReadNode(0) { |
647 | FlatTree.push_back(Elt: DiffNode()); |
648 | } |
649 | |
650 | // Node writing functions, one for each valid DiffKind element. |
651 | void SetTemplateDiff(TemplateDecl *FromTD, TemplateDecl *ToTD, |
652 | Qualifiers FromQual, Qualifiers ToQual, |
653 | bool FromDefault, bool ToDefault) { |
654 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
655 | FlatTree[CurrentNode].Kind = Template; |
656 | FlatTree[CurrentNode].FromArgInfo.TD = FromTD; |
657 | FlatTree[CurrentNode].ToArgInfo.TD = ToTD; |
658 | FlatTree[CurrentNode].FromArgInfo.Qual = FromQual; |
659 | FlatTree[CurrentNode].ToArgInfo.Qual = ToQual; |
660 | SetDefault(FromDefault, ToDefault); |
661 | } |
662 | |
663 | void SetTypeDiff(QualType FromType, QualType ToType, bool FromDefault, |
664 | bool ToDefault) { |
665 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
666 | FlatTree[CurrentNode].Kind = Type; |
667 | FlatTree[CurrentNode].FromArgInfo.ArgType = FromType; |
668 | FlatTree[CurrentNode].ToArgInfo.ArgType = ToType; |
669 | SetDefault(FromDefault, ToDefault); |
670 | } |
671 | |
672 | void SetExpressionDiff(Expr *FromExpr, Expr *ToExpr, bool FromDefault, |
673 | bool ToDefault) { |
674 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
675 | FlatTree[CurrentNode].Kind = Expression; |
676 | FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
677 | FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
678 | SetDefault(FromDefault, ToDefault); |
679 | } |
680 | |
681 | void SetTemplateTemplateDiff(TemplateDecl *FromTD, TemplateDecl *ToTD, |
682 | bool FromDefault, bool ToDefault) { |
683 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
684 | FlatTree[CurrentNode].Kind = TemplateTemplate; |
685 | FlatTree[CurrentNode].FromArgInfo.TD = FromTD; |
686 | FlatTree[CurrentNode].ToArgInfo.TD = ToTD; |
687 | SetDefault(FromDefault, ToDefault); |
688 | } |
689 | |
690 | void SetIntegerDiff(const llvm::APSInt &FromInt, const llvm::APSInt &ToInt, |
691 | bool IsValidFromInt, bool IsValidToInt, |
692 | QualType FromIntType, QualType ToIntType, |
693 | Expr *FromExpr, Expr *ToExpr, bool FromDefault, |
694 | bool ToDefault) { |
695 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
696 | FlatTree[CurrentNode].Kind = Integer; |
697 | FlatTree[CurrentNode].FromArgInfo.Val = FromInt; |
698 | FlatTree[CurrentNode].ToArgInfo.Val = ToInt; |
699 | FlatTree[CurrentNode].FromArgInfo.IsValidInt = IsValidFromInt; |
700 | FlatTree[CurrentNode].ToArgInfo.IsValidInt = IsValidToInt; |
701 | FlatTree[CurrentNode].FromArgInfo.ArgType = FromIntType; |
702 | FlatTree[CurrentNode].ToArgInfo.ArgType = ToIntType; |
703 | FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
704 | FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
705 | SetDefault(FromDefault, ToDefault); |
706 | } |
707 | |
708 | void SetDeclarationDiff(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl, |
709 | bool FromAddressOf, bool ToAddressOf, |
710 | bool FromNullPtr, bool ToNullPtr, Expr *FromExpr, |
711 | Expr *ToExpr, bool FromDefault, bool ToDefault) { |
712 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
713 | FlatTree[CurrentNode].Kind = Declaration; |
714 | FlatTree[CurrentNode].FromArgInfo.VD = FromValueDecl; |
715 | FlatTree[CurrentNode].ToArgInfo.VD = ToValueDecl; |
716 | FlatTree[CurrentNode].FromArgInfo.NeedAddressOf = FromAddressOf; |
717 | FlatTree[CurrentNode].ToArgInfo.NeedAddressOf = ToAddressOf; |
718 | FlatTree[CurrentNode].FromArgInfo.IsNullPtr = FromNullPtr; |
719 | FlatTree[CurrentNode].ToArgInfo.IsNullPtr = ToNullPtr; |
720 | FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
721 | FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
722 | SetDefault(FromDefault, ToDefault); |
723 | } |
724 | |
725 | void SetFromDeclarationAndToIntegerDiff( |
726 | ValueDecl *FromValueDecl, bool FromAddressOf, bool FromNullPtr, |
727 | Expr *FromExpr, const llvm::APSInt &ToInt, bool IsValidToInt, |
728 | QualType ToIntType, Expr *ToExpr, bool FromDefault, bool ToDefault) { |
729 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
730 | FlatTree[CurrentNode].Kind = FromDeclarationAndToInteger; |
731 | FlatTree[CurrentNode].FromArgInfo.VD = FromValueDecl; |
732 | FlatTree[CurrentNode].FromArgInfo.NeedAddressOf = FromAddressOf; |
733 | FlatTree[CurrentNode].FromArgInfo.IsNullPtr = FromNullPtr; |
734 | FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
735 | FlatTree[CurrentNode].ToArgInfo.Val = ToInt; |
736 | FlatTree[CurrentNode].ToArgInfo.IsValidInt = IsValidToInt; |
737 | FlatTree[CurrentNode].ToArgInfo.ArgType = ToIntType; |
738 | FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
739 | SetDefault(FromDefault, ToDefault); |
740 | } |
741 | |
742 | void SetFromIntegerAndToDeclarationDiff( |
743 | const llvm::APSInt &FromInt, bool IsValidFromInt, QualType FromIntType, |
744 | Expr *FromExpr, ValueDecl *ToValueDecl, bool ToAddressOf, |
745 | bool ToNullPtr, Expr *ToExpr, bool FromDefault, bool ToDefault) { |
746 | assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty."); |
747 | FlatTree[CurrentNode].Kind = FromIntegerAndToDeclaration; |
748 | FlatTree[CurrentNode].FromArgInfo.Val = FromInt; |
749 | FlatTree[CurrentNode].FromArgInfo.IsValidInt = IsValidFromInt; |
750 | FlatTree[CurrentNode].FromArgInfo.ArgType = FromIntType; |
751 | FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr; |
752 | FlatTree[CurrentNode].ToArgInfo.VD = ToValueDecl; |
753 | FlatTree[CurrentNode].ToArgInfo.NeedAddressOf = ToAddressOf; |
754 | FlatTree[CurrentNode].ToArgInfo.IsNullPtr = ToNullPtr; |
755 | FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr; |
756 | SetDefault(FromDefault, ToDefault); |
757 | } |
758 | |
759 | /// SetDefault - Sets FromDefault and ToDefault flags of the current node. |
760 | void SetDefault(bool FromDefault, bool ToDefault) { |
761 | assert((!FromDefault || !ToDefault) && "Both arguments cannot be default."); |
762 | FlatTree[CurrentNode].FromArgInfo.IsDefault = FromDefault; |
763 | FlatTree[CurrentNode].ToArgInfo.IsDefault = ToDefault; |
764 | } |
765 | |
766 | /// SetSame - Sets the same flag of the current node. |
767 | void SetSame(bool Same) { |
768 | FlatTree[CurrentNode].Same = Same; |
769 | } |
770 | |
771 | /// SetKind - Sets the current node's type. |
772 | void SetKind(DiffKind Kind) { |
773 | FlatTree[CurrentNode].Kind = Kind; |
774 | } |
775 | |
776 | /// Up - Changes the node to the parent of the current node. |
777 | void Up() { |
778 | assert(FlatTree[CurrentNode].Kind != Invalid && |
779 | "Cannot exit node before setting node information."); |
780 | CurrentNode = FlatTree[CurrentNode].ParentNode; |
781 | } |
782 | |
783 | /// AddNode - Adds a child node to the current node, then sets that node |
784 | /// node as the current node. |
785 | void AddNode() { |
786 | assert(FlatTree[CurrentNode].Kind == Template && |
787 | "Only Template nodes can have children nodes."); |
788 | FlatTree.push_back(Elt: DiffNode(CurrentNode)); |
789 | DiffNode &Node = FlatTree[CurrentNode]; |
790 | if (Node.ChildNode == 0) { |
791 | // If a child node doesn't exist, add one. |
792 | Node.ChildNode = NextFreeNode; |
793 | } else { |
794 | // If a child node exists, find the last child node and add a |
795 | // next node to it. |
796 | unsigned i; |
797 | for (i = Node.ChildNode; FlatTree[i].NextNode != 0; |
798 | i = FlatTree[i].NextNode) { |
799 | } |
800 | FlatTree[i].NextNode = NextFreeNode; |
801 | } |
802 | CurrentNode = NextFreeNode; |
803 | ++NextFreeNode; |
804 | } |
805 | |
806 | // Node reading functions. |
807 | /// StartTraverse - Prepares the tree for recursive traversal. |
808 | void StartTraverse() { |
809 | ReadNode = 0; |
810 | CurrentNode = NextFreeNode; |
811 | NextFreeNode = 0; |
812 | } |
813 | |
814 | /// Parent - Move the current read node to its parent. |
815 | void Parent() { |
816 | ReadNode = FlatTree[ReadNode].ParentNode; |
817 | } |
818 | |
819 | void GetTemplateDiff(TemplateDecl *&FromTD, TemplateDecl *&ToTD, |
820 | Qualifiers &FromQual, Qualifiers &ToQual) { |
821 | assert(FlatTree[ReadNode].Kind == Template && "Unexpected kind."); |
822 | FromTD = FlatTree[ReadNode].FromArgInfo.TD; |
823 | ToTD = FlatTree[ReadNode].ToArgInfo.TD; |
824 | FromQual = FlatTree[ReadNode].FromArgInfo.Qual; |
825 | ToQual = FlatTree[ReadNode].ToArgInfo.Qual; |
826 | } |
827 | |
828 | void GetTypeDiff(QualType &FromType, QualType &ToType) { |
829 | assert(FlatTree[ReadNode].Kind == Type && "Unexpected kind"); |
830 | FromType = FlatTree[ReadNode].FromArgInfo.ArgType; |
831 | ToType = FlatTree[ReadNode].ToArgInfo.ArgType; |
832 | } |
833 | |
834 | void GetExpressionDiff(Expr *&FromExpr, Expr *&ToExpr) { |
835 | assert(FlatTree[ReadNode].Kind == Expression && "Unexpected kind"); |
836 | FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
837 | ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
838 | } |
839 | |
840 | void GetTemplateTemplateDiff(TemplateDecl *&FromTD, TemplateDecl *&ToTD) { |
841 | assert(FlatTree[ReadNode].Kind == TemplateTemplate && "Unexpected kind."); |
842 | FromTD = FlatTree[ReadNode].FromArgInfo.TD; |
843 | ToTD = FlatTree[ReadNode].ToArgInfo.TD; |
844 | } |
845 | |
846 | void GetIntegerDiff(llvm::APSInt &FromInt, llvm::APSInt &ToInt, |
847 | bool &IsValidFromInt, bool &IsValidToInt, |
848 | QualType &FromIntType, QualType &ToIntType, |
849 | Expr *&FromExpr, Expr *&ToExpr) { |
850 | assert(FlatTree[ReadNode].Kind == Integer && "Unexpected kind."); |
851 | FromInt = FlatTree[ReadNode].FromArgInfo.Val; |
852 | ToInt = FlatTree[ReadNode].ToArgInfo.Val; |
853 | IsValidFromInt = FlatTree[ReadNode].FromArgInfo.IsValidInt; |
854 | IsValidToInt = FlatTree[ReadNode].ToArgInfo.IsValidInt; |
855 | FromIntType = FlatTree[ReadNode].FromArgInfo.ArgType; |
856 | ToIntType = FlatTree[ReadNode].ToArgInfo.ArgType; |
857 | FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
858 | ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
859 | } |
860 | |
861 | void GetDeclarationDiff(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl, |
862 | bool &FromAddressOf, bool &ToAddressOf, |
863 | bool &FromNullPtr, bool &ToNullPtr, Expr *&FromExpr, |
864 | Expr *&ToExpr) { |
865 | assert(FlatTree[ReadNode].Kind == Declaration && "Unexpected kind."); |
866 | FromValueDecl = FlatTree[ReadNode].FromArgInfo.VD; |
867 | ToValueDecl = FlatTree[ReadNode].ToArgInfo.VD; |
868 | FromAddressOf = FlatTree[ReadNode].FromArgInfo.NeedAddressOf; |
869 | ToAddressOf = FlatTree[ReadNode].ToArgInfo.NeedAddressOf; |
870 | FromNullPtr = FlatTree[ReadNode].FromArgInfo.IsNullPtr; |
871 | ToNullPtr = FlatTree[ReadNode].ToArgInfo.IsNullPtr; |
872 | FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
873 | ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
874 | } |
875 | |
876 | void GetFromDeclarationAndToIntegerDiff( |
877 | ValueDecl *&FromValueDecl, bool &FromAddressOf, bool &FromNullPtr, |
878 | Expr *&FromExpr, llvm::APSInt &ToInt, bool &IsValidToInt, |
879 | QualType &ToIntType, Expr *&ToExpr) { |
880 | assert(FlatTree[ReadNode].Kind == FromDeclarationAndToInteger && |
881 | "Unexpected kind."); |
882 | FromValueDecl = FlatTree[ReadNode].FromArgInfo.VD; |
883 | FromAddressOf = FlatTree[ReadNode].FromArgInfo.NeedAddressOf; |
884 | FromNullPtr = FlatTree[ReadNode].FromArgInfo.IsNullPtr; |
885 | FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
886 | ToInt = FlatTree[ReadNode].ToArgInfo.Val; |
887 | IsValidToInt = FlatTree[ReadNode].ToArgInfo.IsValidInt; |
888 | ToIntType = FlatTree[ReadNode].ToArgInfo.ArgType; |
889 | ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
890 | } |
891 | |
892 | void GetFromIntegerAndToDeclarationDiff( |
893 | llvm::APSInt &FromInt, bool &IsValidFromInt, QualType &FromIntType, |
894 | Expr *&FromExpr, ValueDecl *&ToValueDecl, bool &ToAddressOf, |
895 | bool &ToNullPtr, Expr *&ToExpr) { |
896 | assert(FlatTree[ReadNode].Kind == FromIntegerAndToDeclaration && |
897 | "Unexpected kind."); |
898 | FromInt = FlatTree[ReadNode].FromArgInfo.Val; |
899 | IsValidFromInt = FlatTree[ReadNode].FromArgInfo.IsValidInt; |
900 | FromIntType = FlatTree[ReadNode].FromArgInfo.ArgType; |
901 | FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr; |
902 | ToValueDecl = FlatTree[ReadNode].ToArgInfo.VD; |
903 | ToAddressOf = FlatTree[ReadNode].ToArgInfo.NeedAddressOf; |
904 | ToNullPtr = FlatTree[ReadNode].ToArgInfo.IsNullPtr; |
905 | ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr; |
906 | } |
907 | |
908 | /// FromDefault - Return true if the from argument is the default. |
909 | bool FromDefault() { |
910 | return FlatTree[ReadNode].FromArgInfo.IsDefault; |
911 | } |
912 | |
913 | /// ToDefault - Return true if the to argument is the default. |
914 | bool ToDefault() { |
915 | return FlatTree[ReadNode].ToArgInfo.IsDefault; |
916 | } |
917 | |
918 | /// NodeIsSame - Returns true the arguments are the same. |
919 | bool NodeIsSame() { |
920 | return FlatTree[ReadNode].Same; |
921 | } |
922 | |
923 | /// HasChildrend - Returns true if the node has children. |
924 | bool HasChildren() { |
925 | return FlatTree[ReadNode].ChildNode != 0; |
926 | } |
927 | |
928 | /// MoveToChild - Moves from the current node to its child. |
929 | void MoveToChild() { |
930 | ReadNode = FlatTree[ReadNode].ChildNode; |
931 | } |
932 | |
933 | /// AdvanceSibling - If there is a next sibling, advance to it and return |
934 | /// true. Otherwise, return false. |
935 | bool AdvanceSibling() { |
936 | if (FlatTree[ReadNode].NextNode == 0) |
937 | return false; |
938 | |
939 | ReadNode = FlatTree[ReadNode].NextNode; |
940 | return true; |
941 | } |
942 | |
943 | /// HasNextSibling - Return true if the node has a next sibling. |
944 | bool HasNextSibling() { |
945 | return FlatTree[ReadNode].NextNode != 0; |
946 | } |
947 | |
948 | /// Empty - Returns true if the tree has no information. |
949 | bool Empty() { |
950 | return GetKind() == Invalid; |
951 | } |
952 | |
953 | /// GetKind - Returns the current node's type. |
954 | DiffKind GetKind() { |
955 | return FlatTree[ReadNode].Kind; |
956 | } |
957 | }; |
958 | |
959 | DiffTree Tree; |
960 | |
961 | /// TSTiterator - a pair of iterators that walks the |
962 | /// TemplateSpecializationType and the desugared TemplateSpecializationType. |
963 | /// The deseguared TemplateArgument should provide the canonical argument |
964 | /// for comparisons. |
965 | class TSTiterator { |
966 | typedef const TemplateArgument& reference; |
967 | typedef const TemplateArgument* pointer; |
968 | |
969 | /// InternalIterator - an iterator that is used to enter a |
970 | /// TemplateSpecializationType and read TemplateArguments inside template |
971 | /// parameter packs in order with the rest of the TemplateArguments. |
972 | struct InternalIterator { |
973 | /// TST - the template specialization whose arguments this iterator |
974 | /// traverse over. |
975 | const TemplateSpecializationType *TST; |
976 | |
977 | /// Index - the index of the template argument in TST. |
978 | unsigned Index; |
979 | |
980 | /// CurrentTA - if CurrentTA is not the same as EndTA, then CurrentTA |
981 | /// points to a TemplateArgument within a parameter pack. |
982 | TemplateArgument::pack_iterator CurrentTA; |
983 | |
984 | /// EndTA - the end iterator of a parameter pack |
985 | TemplateArgument::pack_iterator EndTA; |
986 | |
987 | /// InternalIterator - Constructs an iterator and sets it to the first |
988 | /// template argument. |
989 | InternalIterator(const TemplateSpecializationType *TST) |
990 | : TST(TST), Index(0), CurrentTA(nullptr), EndTA(nullptr) { |
991 | if (!TST) return; |
992 | |
993 | if (isEnd()) return; |
994 | |
995 | // Set to first template argument. If not a parameter pack, done. |
996 | TemplateArgument TA = TST->template_arguments()[0]; |
997 | if (TA.getKind() != TemplateArgument::Pack) return; |
998 | |
999 | // Start looking into the parameter pack. |
1000 | CurrentTA = TA.pack_begin(); |
1001 | EndTA = TA.pack_end(); |
1002 | |
1003 | // Found a valid template argument. |
1004 | if (CurrentTA != EndTA) return; |
1005 | |
1006 | // Parameter pack is empty, use the increment to get to a valid |
1007 | // template argument. |
1008 | ++(*this); |
1009 | } |
1010 | |
1011 | /// Return true if the iterator is non-singular. |
1012 | bool isValid() const { return TST; } |
1013 | |
1014 | /// isEnd - Returns true if the iterator is one past the end. |
1015 | bool isEnd() const { |
1016 | assert(TST && "InternalIterator is invalid with a null TST."); |
1017 | return Index >= TST->template_arguments().size(); |
1018 | } |
1019 | |
1020 | /// &operator++ - Increment the iterator to the next template argument. |
1021 | InternalIterator &operator++() { |
1022 | assert(TST && "InternalIterator is invalid with a null TST."); |
1023 | if (isEnd()) { |
1024 | return *this; |
1025 | } |
1026 | |
1027 | // If in a parameter pack, advance in the parameter pack. |
1028 | if (CurrentTA != EndTA) { |
1029 | ++CurrentTA; |
1030 | if (CurrentTA != EndTA) |
1031 | return *this; |
1032 | } |
1033 | |
1034 | // Loop until a template argument is found, or the end is reached. |
1035 | while (true) { |
1036 | // Advance to the next template argument. Break if reached the end. |
1037 | if (++Index == TST->template_arguments().size()) |
1038 | break; |
1039 | |
1040 | // If the TemplateArgument is not a parameter pack, done. |
1041 | TemplateArgument TA = TST->template_arguments()[Index]; |
1042 | if (TA.getKind() != TemplateArgument::Pack) |
1043 | break; |
1044 | |
1045 | // Handle parameter packs. |
1046 | CurrentTA = TA.pack_begin(); |
1047 | EndTA = TA.pack_end(); |
1048 | |
1049 | // If the parameter pack is empty, try to advance again. |
1050 | if (CurrentTA != EndTA) |
1051 | break; |
1052 | } |
1053 | return *this; |
1054 | } |
1055 | |
1056 | /// operator* - Returns the appropriate TemplateArgument. |
1057 | reference operator*() const { |
1058 | assert(TST && "InternalIterator is invalid with a null TST."); |
1059 | assert(!isEnd() && "Index exceeds number of arguments."); |
1060 | if (CurrentTA == EndTA) |
1061 | return TST->template_arguments()[Index]; |
1062 | else |
1063 | return *CurrentTA; |
1064 | } |
1065 | |
1066 | /// operator-> - Allow access to the underlying TemplateArgument. |
1067 | pointer operator->() const { |
1068 | assert(TST && "InternalIterator is invalid with a null TST."); |
1069 | return &operator*(); |
1070 | } |
1071 | }; |
1072 | |
1073 | InternalIterator SugaredIterator; |
1074 | InternalIterator DesugaredIterator; |
1075 | |
1076 | public: |
1077 | TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST) |
1078 | : SugaredIterator(TST), |
1079 | DesugaredIterator( |
1080 | (TST->isSugared() && !TST->isTypeAlias()) |
1081 | ? GetTemplateSpecializationType(Context, Ty: TST->desugar()) |
1082 | : nullptr) {} |
1083 | |
1084 | /// &operator++ - Increment the iterator to the next template argument. |
1085 | TSTiterator &operator++() { |
1086 | ++SugaredIterator; |
1087 | if (DesugaredIterator.isValid()) |
1088 | ++DesugaredIterator; |
1089 | return *this; |
1090 | } |
1091 | |
1092 | /// operator* - Returns the appropriate TemplateArgument. |
1093 | reference operator*() const { |
1094 | return *SugaredIterator; |
1095 | } |
1096 | |
1097 | /// operator-> - Allow access to the underlying TemplateArgument. |
1098 | pointer operator->() const { |
1099 | return &operator*(); |
1100 | } |
1101 | |
1102 | /// isEnd - Returns true if no more TemplateArguments are available. |
1103 | bool isEnd() const { |
1104 | return SugaredIterator.isEnd(); |
1105 | } |
1106 | |
1107 | /// hasDesugaredTA - Returns true if there is another TemplateArgument |
1108 | /// available. |
1109 | bool hasDesugaredTA() const { |
1110 | return DesugaredIterator.isValid() && !DesugaredIterator.isEnd(); |
1111 | } |
1112 | |
1113 | /// getDesugaredTA - Returns the desugared TemplateArgument. |
1114 | reference getDesugaredTA() const { |
1115 | assert(DesugaredIterator.isValid() && |
1116 | "Desugared TemplateArgument should not be used."); |
1117 | return *DesugaredIterator; |
1118 | } |
1119 | }; |
1120 | |
1121 | // These functions build up the template diff tree, including functions to |
1122 | // retrieve and compare template arguments. |
1123 | |
1124 | static const TemplateSpecializationType * |
1125 | GetTemplateSpecializationType(ASTContext &Context, QualType Ty) { |
1126 | if (const TemplateSpecializationType *TST = |
1127 | Ty->getAs<TemplateSpecializationType>()) |
1128 | return TST; |
1129 | |
1130 | if (const auto* SubstType = Ty->getAs<SubstTemplateTypeParmType>()) |
1131 | Ty = SubstType->getReplacementType(); |
1132 | |
1133 | const RecordType *RT = Ty->getAs<RecordType>(); |
1134 | |
1135 | if (!RT) |
1136 | return nullptr; |
1137 | |
1138 | const ClassTemplateSpecializationDecl *CTSD = |
1139 | dyn_cast<ClassTemplateSpecializationDecl>(Val: RT->getDecl()); |
1140 | |
1141 | if (!CTSD) |
1142 | return nullptr; |
1143 | |
1144 | Ty = Context.getTemplateSpecializationType( |
1145 | T: TemplateName(CTSD->getSpecializedTemplate()), |
1146 | SpecifiedArgs: CTSD->getTemplateArgs().asArray(), /*CanonicalArgs=*/std::nullopt, |
1147 | Underlying: Ty.getLocalUnqualifiedType().getCanonicalType()); |
1148 | |
1149 | return Ty->getAs<TemplateSpecializationType>(); |
1150 | } |
1151 | |
1152 | /// Returns true if the DiffType is Type and false for Template. |
1153 | static bool OnlyPerformTypeDiff(ASTContext &Context, QualType FromType, |
1154 | QualType ToType, |
1155 | const TemplateSpecializationType *&FromArgTST, |
1156 | const TemplateSpecializationType *&ToArgTST) { |
1157 | if (FromType.isNull() || ToType.isNull()) |
1158 | return true; |
1159 | |
1160 | if (Context.hasSameType(T1: FromType, T2: ToType)) |
1161 | return true; |
1162 | |
1163 | FromArgTST = GetTemplateSpecializationType(Context, Ty: FromType); |
1164 | ToArgTST = GetTemplateSpecializationType(Context, Ty: ToType); |
1165 | |
1166 | if (!FromArgTST || !ToArgTST) |
1167 | return true; |
1168 | |
1169 | if (!hasSameTemplate(Context, FromTST&: FromArgTST, ToTST&: ToArgTST)) |
1170 | return true; |
1171 | |
1172 | return false; |
1173 | } |
1174 | |
1175 | /// DiffTypes - Fills a DiffNode with information about a type difference. |
1176 | void DiffTypes(const TSTiterator &FromIter, const TSTiterator &ToIter) { |
1177 | QualType FromType = GetType(Iter: FromIter); |
1178 | QualType ToType = GetType(Iter: ToIter); |
1179 | |
1180 | bool FromDefault = FromIter.isEnd() && !FromType.isNull(); |
1181 | bool ToDefault = ToIter.isEnd() && !ToType.isNull(); |
1182 | |
1183 | const TemplateSpecializationType *FromArgTST = nullptr; |
1184 | const TemplateSpecializationType *ToArgTST = nullptr; |
1185 | if (OnlyPerformTypeDiff(Context, FromType, ToType, FromArgTST, ToArgTST)) { |
1186 | Tree.SetTypeDiff(FromType, ToType, FromDefault, ToDefault); |
1187 | Tree.SetSame(!FromType.isNull() && !ToType.isNull() && |
1188 | Context.hasSameType(T1: FromType, T2: ToType)); |
1189 | } else { |
1190 | assert(FromArgTST && ToArgTST && |
1191 | "Both template specializations need to be valid."); |
1192 | Qualifiers FromQual = FromType.getQualifiers(), |
1193 | ToQual = ToType.getQualifiers(); |
1194 | FromQual -= QualType(FromArgTST, 0).getQualifiers(); |
1195 | ToQual -= QualType(ToArgTST, 0).getQualifiers(); |
1196 | Tree.SetTemplateDiff(FromTD: FromArgTST->getTemplateName().getAsTemplateDecl(), |
1197 | ToTD: ToArgTST->getTemplateName().getAsTemplateDecl(), |
1198 | FromQual, ToQual, FromDefault, ToDefault); |
1199 | DiffTemplate(FromTST: FromArgTST, ToTST: ToArgTST); |
1200 | } |
1201 | } |
1202 | |
1203 | /// DiffTemplateTemplates - Fills a DiffNode with information about a |
1204 | /// template template difference. |
1205 | void DiffTemplateTemplates(const TSTiterator &FromIter, |
1206 | const TSTiterator &ToIter) { |
1207 | TemplateDecl *FromDecl = GetTemplateDecl(Iter: FromIter); |
1208 | TemplateDecl *ToDecl = GetTemplateDecl(Iter: ToIter); |
1209 | Tree.SetTemplateTemplateDiff(FromTD: FromDecl, ToTD: ToDecl, FromDefault: FromIter.isEnd() && FromDecl, |
1210 | ToDefault: ToIter.isEnd() && ToDecl); |
1211 | Tree.SetSame(FromDecl && ToDecl && |
1212 | FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl()); |
1213 | } |
1214 | |
1215 | /// InitializeNonTypeDiffVariables - Helper function for DiffNonTypes |
1216 | static void InitializeNonTypeDiffVariables(ASTContext &Context, |
1217 | const TSTiterator &Iter, |
1218 | NonTypeTemplateParmDecl *Default, |
1219 | llvm::APSInt &Value, bool &HasInt, |
1220 | QualType &IntType, bool &IsNullPtr, |
1221 | Expr *&E, ValueDecl *&VD, |
1222 | bool &NeedAddressOf) { |
1223 | if (!Iter.isEnd()) { |
1224 | switch (Iter->getKind()) { |
1225 | case TemplateArgument::StructuralValue: |
1226 | // FIXME: Diffing of structural values is not implemented. |
1227 | // There is no possible fallback in this case, this will show up |
1228 | // as '(no argument)'. |
1229 | return; |
1230 | case TemplateArgument::Integral: |
1231 | Value = Iter->getAsIntegral(); |
1232 | HasInt = true; |
1233 | IntType = Iter->getIntegralType(); |
1234 | return; |
1235 | case TemplateArgument::Declaration: { |
1236 | VD = Iter->getAsDecl(); |
1237 | QualType ArgType = Iter->getParamTypeForDecl(); |
1238 | QualType VDType = VD->getType(); |
1239 | if (ArgType->isPointerType() && |
1240 | Context.hasSameType(T1: ArgType->getPointeeType(), T2: VDType)) |
1241 | NeedAddressOf = true; |
1242 | return; |
1243 | } |
1244 | case TemplateArgument::NullPtr: |
1245 | IsNullPtr = true; |
1246 | return; |
1247 | case TemplateArgument::Expression: |
1248 | E = Iter->getAsExpr(); |
1249 | break; |
1250 | case TemplateArgument::Null: |
1251 | case TemplateArgument::Type: |
1252 | case TemplateArgument::Template: |
1253 | case TemplateArgument::TemplateExpansion: |
1254 | llvm_unreachable("TemplateArgument kind is not expected for NTTP"); |
1255 | case TemplateArgument::Pack: |
1256 | llvm_unreachable("TemplateArgument kind should be handled elsewhere"); |
1257 | } |
1258 | } else if (!Default->isParameterPack()) { |
1259 | E = Default->getDefaultArgument().getArgument().getAsExpr(); |
1260 | } |
1261 | |
1262 | if (!Iter.hasDesugaredTA()) |
1263 | return; |
1264 | |
1265 | const TemplateArgument &TA = Iter.getDesugaredTA(); |
1266 | switch (TA.getKind()) { |
1267 | case TemplateArgument::StructuralValue: |
1268 | // FIXME: Diffing of structural values is not implemented. |
1269 | // Just fall back to the expression. |
1270 | return; |
1271 | case TemplateArgument::Integral: |
1272 | Value = TA.getAsIntegral(); |
1273 | HasInt = true; |
1274 | IntType = TA.getIntegralType(); |
1275 | return; |
1276 | case TemplateArgument::Declaration: { |
1277 | VD = TA.getAsDecl(); |
1278 | QualType ArgType = TA.getParamTypeForDecl(); |
1279 | QualType VDType = VD->getType(); |
1280 | if (ArgType->isPointerType() && |
1281 | Context.hasSameType(T1: ArgType->getPointeeType(), T2: VDType)) |
1282 | NeedAddressOf = true; |
1283 | return; |
1284 | } |
1285 | case TemplateArgument::NullPtr: |
1286 | IsNullPtr = true; |
1287 | return; |
1288 | case TemplateArgument::Expression: |
1289 | // TODO: Sometimes, the desugared template argument Expr differs from |
1290 | // the sugared template argument Expr. It may be useful in the future |
1291 | // but for now, it is just discarded. |
1292 | if (!E) |
1293 | E = TA.getAsExpr(); |
1294 | return; |
1295 | case TemplateArgument::Null: |
1296 | case TemplateArgument::Type: |
1297 | case TemplateArgument::Template: |
1298 | case TemplateArgument::TemplateExpansion: |
1299 | llvm_unreachable("TemplateArgument kind is not expected for NTTP"); |
1300 | case TemplateArgument::Pack: |
1301 | llvm_unreachable("TemplateArgument kind should be handled elsewhere"); |
1302 | } |
1303 | llvm_unreachable("Unexpected TemplateArgument kind"); |
1304 | } |
1305 | |
1306 | /// DiffNonTypes - Handles any template parameters not handled by DiffTypes |
1307 | /// of DiffTemplatesTemplates, such as integer and declaration parameters. |
1308 | void DiffNonTypes(const TSTiterator &FromIter, const TSTiterator &ToIter, |
1309 | NonTypeTemplateParmDecl *FromDefaultNonTypeDecl, |
1310 | NonTypeTemplateParmDecl *ToDefaultNonTypeDecl) { |
1311 | Expr *FromExpr = nullptr, *ToExpr = nullptr; |
1312 | llvm::APSInt FromInt, ToInt; |
1313 | QualType FromIntType, ToIntType; |
1314 | ValueDecl *FromValueDecl = nullptr, *ToValueDecl = nullptr; |
1315 | bool HasFromInt = false, HasToInt = false, FromNullPtr = false, |
1316 | ToNullPtr = false, NeedFromAddressOf = false, NeedToAddressOf = false; |
1317 | InitializeNonTypeDiffVariables( |
1318 | Context, Iter: FromIter, Default: FromDefaultNonTypeDecl, Value&: FromInt, HasInt&: HasFromInt, |
1319 | IntType&: FromIntType, IsNullPtr&: FromNullPtr, E&: FromExpr, VD&: FromValueDecl, NeedAddressOf&: NeedFromAddressOf); |
1320 | InitializeNonTypeDiffVariables(Context, Iter: ToIter, Default: ToDefaultNonTypeDecl, Value&: ToInt, |
1321 | HasInt&: HasToInt, IntType&: ToIntType, IsNullPtr&: ToNullPtr, E&: ToExpr, |
1322 | VD&: ToValueDecl, NeedAddressOf&: NeedToAddressOf); |
1323 | |
1324 | bool FromDefault = FromIter.isEnd() && |
1325 | (FromExpr || FromValueDecl || HasFromInt || FromNullPtr); |
1326 | bool ToDefault = ToIter.isEnd() && |
1327 | (ToExpr || ToValueDecl || HasToInt || ToNullPtr); |
1328 | |
1329 | bool FromDeclaration = FromValueDecl || FromNullPtr; |
1330 | bool ToDeclaration = ToValueDecl || ToNullPtr; |
1331 | |
1332 | if (FromDeclaration && HasToInt) { |
1333 | Tree.SetFromDeclarationAndToIntegerDiff( |
1334 | FromValueDecl, FromAddressOf: NeedFromAddressOf, FromNullPtr, FromExpr, ToInt, |
1335 | IsValidToInt: HasToInt, ToIntType, ToExpr, FromDefault, ToDefault); |
1336 | Tree.SetSame(false); |
1337 | return; |
1338 | |
1339 | } |
1340 | |
1341 | if (HasFromInt && ToDeclaration) { |
1342 | Tree.SetFromIntegerAndToDeclarationDiff( |
1343 | FromInt, IsValidFromInt: HasFromInt, FromIntType, FromExpr, ToValueDecl, |
1344 | ToAddressOf: NeedToAddressOf, ToNullPtr, ToExpr, FromDefault, ToDefault); |
1345 | Tree.SetSame(false); |
1346 | return; |
1347 | } |
1348 | |
1349 | if (HasFromInt || HasToInt) { |
1350 | Tree.SetIntegerDiff(FromInt, ToInt, IsValidFromInt: HasFromInt, IsValidToInt: HasToInt, FromIntType, |
1351 | ToIntType, FromExpr, ToExpr, FromDefault, ToDefault); |
1352 | if (HasFromInt && HasToInt) { |
1353 | Tree.SetSame(Context.hasSameType(T1: FromIntType, T2: ToIntType) && |
1354 | FromInt == ToInt); |
1355 | } |
1356 | return; |
1357 | } |
1358 | |
1359 | if (FromDeclaration || ToDeclaration) { |
1360 | Tree.SetDeclarationDiff(FromValueDecl, ToValueDecl, FromAddressOf: NeedFromAddressOf, |
1361 | ToAddressOf: NeedToAddressOf, FromNullPtr, ToNullPtr, FromExpr, |
1362 | ToExpr, FromDefault, ToDefault); |
1363 | bool BothNull = FromNullPtr && ToNullPtr; |
1364 | bool SameValueDecl = |
1365 | FromValueDecl && ToValueDecl && |
1366 | NeedFromAddressOf == NeedToAddressOf && |
1367 | FromValueDecl->getCanonicalDecl() == ToValueDecl->getCanonicalDecl(); |
1368 | Tree.SetSame(BothNull || SameValueDecl); |
1369 | return; |
1370 | } |
1371 | |
1372 | assert((FromExpr || ToExpr) && "Both template arguments cannot be empty."); |
1373 | Tree.SetExpressionDiff(FromExpr, ToExpr, FromDefault, ToDefault); |
1374 | Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr)); |
1375 | } |
1376 | |
1377 | /// DiffTemplate - recursively visits template arguments and stores the |
1378 | /// argument info into a tree. |
1379 | void DiffTemplate(const TemplateSpecializationType *FromTST, |
1380 | const TemplateSpecializationType *ToTST) { |
1381 | // FIXME: With P3310R0, A TST formed from a DeducedTemplateName might |
1382 | // differ in template arguments which were not written. |
1383 | // Begin descent into diffing template tree. |
1384 | TemplateParameterList *ParamsFrom = |
1385 | FromTST->getTemplateName() |
1386 | .getAsTemplateDecl(/*IgnoreDeduced=*/true) |
1387 | ->getTemplateParameters(); |
1388 | TemplateParameterList *ParamsTo = |
1389 | ToTST->getTemplateName() |
1390 | .getAsTemplateDecl(/*IgnoreDeduced=*/true) |
1391 | ->getTemplateParameters(); |
1392 | unsigned TotalArgs = 0; |
1393 | for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST); |
1394 | !FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) { |
1395 | Tree.AddNode(); |
1396 | |
1397 | // Get the parameter at index TotalArgs. If index is larger |
1398 | // than the total number of parameters, then there is an |
1399 | // argument pack, so re-use the last parameter. |
1400 | unsigned FromParamIndex = std::min(a: TotalArgs, b: ParamsFrom->size() - 1); |
1401 | unsigned ToParamIndex = std::min(a: TotalArgs, b: ParamsTo->size() - 1); |
1402 | NamedDecl *FromParamND = ParamsFrom->getParam(Idx: FromParamIndex); |
1403 | NamedDecl *ToParamND = ParamsTo->getParam(Idx: ToParamIndex); |
1404 | |
1405 | assert(FromParamND->getKind() == ToParamND->getKind() && |
1406 | "Parameter Decl are not the same kind."); |
1407 | |
1408 | if (isa<TemplateTypeParmDecl>(Val: FromParamND)) { |
1409 | DiffTypes(FromIter, ToIter); |
1410 | } else if (isa<TemplateTemplateParmDecl>(Val: FromParamND)) { |
1411 | DiffTemplateTemplates(FromIter, ToIter); |
1412 | } else if (isa<NonTypeTemplateParmDecl>(Val: FromParamND)) { |
1413 | NonTypeTemplateParmDecl *FromDefaultNonTypeDecl = |
1414 | cast<NonTypeTemplateParmDecl>(Val: FromParamND); |
1415 | NonTypeTemplateParmDecl *ToDefaultNonTypeDecl = |
1416 | cast<NonTypeTemplateParmDecl>(Val: ToParamND); |
1417 | DiffNonTypes(FromIter, ToIter, FromDefaultNonTypeDecl, |
1418 | ToDefaultNonTypeDecl); |
1419 | } else { |
1420 | llvm_unreachable("Unexpected Decl type."); |
1421 | } |
1422 | |
1423 | ++FromIter; |
1424 | ++ToIter; |
1425 | Tree.Up(); |
1426 | } |
1427 | } |
1428 | |
1429 | /// makeTemplateList - Dump every template alias into the vector. |
1430 | static void makeTemplateList( |
1431 | SmallVectorImpl<const TemplateSpecializationType *> &TemplateList, |
1432 | const TemplateSpecializationType *TST) { |
1433 | while (TST) { |
1434 | TemplateList.push_back(Elt: TST); |
1435 | if (!TST->isTypeAlias()) |
1436 | return; |
1437 | TST = TST->getAliasedType()->getAs<TemplateSpecializationType>(); |
1438 | } |
1439 | } |
1440 | |
1441 | /// hasSameBaseTemplate - Returns true when the base templates are the same, |
1442 | /// even if the template arguments are not. |
1443 | static bool hasSameBaseTemplate(ASTContext &Context, |
1444 | const TemplateSpecializationType *FromTST, |
1445 | const TemplateSpecializationType *ToTST) { |
1446 | return Context.getCanonicalTemplateName(Name: FromTST->getTemplateName(), |
1447 | /*IgnoreDeduced=*/true) == |
1448 | Context.getCanonicalTemplateName(Name: ToTST->getTemplateName(), |
1449 | /*IgnoreDeduced=*/true); |
1450 | } |
1451 | |
1452 | /// hasSameTemplate - Returns true if both types are specialized from the |
1453 | /// same template declaration. If they come from different template aliases, |
1454 | /// do a parallel ascension search to determine the highest template alias in |
1455 | /// common and set the arguments to them. |
1456 | static bool hasSameTemplate(ASTContext &Context, |
1457 | const TemplateSpecializationType *&FromTST, |
1458 | const TemplateSpecializationType *&ToTST) { |
1459 | // Check the top templates if they are the same. |
1460 | if (hasSameBaseTemplate(Context, FromTST, ToTST)) |
1461 | return true; |
1462 | |
1463 | // Create vectors of template aliases. |
1464 | SmallVector<const TemplateSpecializationType*, 1> FromTemplateList, |
1465 | ToTemplateList; |
1466 | |
1467 | makeTemplateList(TemplateList&: FromTemplateList, TST: FromTST); |
1468 | makeTemplateList(TemplateList&: ToTemplateList, TST: ToTST); |
1469 | |
1470 | SmallVectorImpl<const TemplateSpecializationType *>::reverse_iterator |
1471 | FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(), |
1472 | ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend(); |
1473 | |
1474 | // Check if the lowest template types are the same. If not, return. |
1475 | if (!hasSameBaseTemplate(Context, FromTST: *FromIter, ToTST: *ToIter)) |
1476 | return false; |
1477 | |
1478 | // Begin searching up the template aliases. The bottom most template |
1479 | // matches so move up until one pair does not match. Use the template |
1480 | // right before that one. |
1481 | for (; FromIter != FromEnd && ToIter != ToEnd; ++FromIter, ++ToIter) { |
1482 | if (!hasSameBaseTemplate(Context, FromTST: *FromIter, ToTST: *ToIter)) |
1483 | break; |
1484 | } |
1485 | |
1486 | FromTST = FromIter[-1]; |
1487 | ToTST = ToIter[-1]; |
1488 | |
1489 | return true; |
1490 | } |
1491 | |
1492 | /// GetType - Retrieves the template type arguments, including default |
1493 | /// arguments. |
1494 | static QualType GetType(const TSTiterator &Iter) { |
1495 | if (!Iter.isEnd()) |
1496 | return Iter->getAsType(); |
1497 | if (Iter.hasDesugaredTA()) |
1498 | return Iter.getDesugaredTA().getAsType(); |
1499 | return QualType(); |
1500 | } |
1501 | |
1502 | /// GetTemplateDecl - Retrieves the template template arguments, including |
1503 | /// default arguments. |
1504 | static TemplateDecl *GetTemplateDecl(const TSTiterator &Iter) { |
1505 | if (!Iter.isEnd()) |
1506 | return Iter->getAsTemplate().getAsTemplateDecl(); |
1507 | if (Iter.hasDesugaredTA()) |
1508 | return Iter.getDesugaredTA().getAsTemplate().getAsTemplateDecl(); |
1509 | return nullptr; |
1510 | } |
1511 | |
1512 | /// IsEqualExpr - Returns true if the expressions are the same in regards to |
1513 | /// template arguments. These expressions are dependent, so profile them |
1514 | /// instead of trying to evaluate them. |
1515 | static bool IsEqualExpr(ASTContext &Context, Expr *FromExpr, Expr *ToExpr) { |
1516 | if (FromExpr == ToExpr) |
1517 | return true; |
1518 | |
1519 | if (!FromExpr || !ToExpr) |
1520 | return false; |
1521 | |
1522 | llvm::FoldingSetNodeID FromID, ToID; |
1523 | FromExpr->Profile(FromID, Context, true); |
1524 | ToExpr->Profile(ToID, Context, true); |
1525 | return FromID == ToID; |
1526 | } |
1527 | |
1528 | // These functions converts the tree representation of the template |
1529 | // differences into the internal character vector. |
1530 | |
1531 | /// TreeToString - Converts the Tree object into a character stream which |
1532 | /// will later be turned into the output string. |
1533 | void TreeToString(int Indent = 1) { |
1534 | if (PrintTree) { |
1535 | OS << '\n'; |
1536 | OS.indent(NumSpaces: 2 * Indent); |
1537 | ++Indent; |
1538 | } |
1539 | |
1540 | // Handle cases where the difference is not templates with different |
1541 | // arguments. |
1542 | switch (Tree.GetKind()) { |
1543 | case DiffTree::Invalid: |
1544 | llvm_unreachable("Template diffing failed with bad DiffNode"); |
1545 | case DiffTree::Type: { |
1546 | QualType FromType, ToType; |
1547 | Tree.GetTypeDiff(FromType, ToType); |
1548 | PrintTypeNames(FromType, ToType, FromDefault: Tree.FromDefault(), ToDefault: Tree.ToDefault(), |
1549 | Same: Tree.NodeIsSame()); |
1550 | return; |
1551 | } |
1552 | case DiffTree::Expression: { |
1553 | Expr *FromExpr, *ToExpr; |
1554 | Tree.GetExpressionDiff(FromExpr, ToExpr); |
1555 | PrintExpr(FromExpr, ToExpr, FromDefault: Tree.FromDefault(), ToDefault: Tree.ToDefault(), |
1556 | Same: Tree.NodeIsSame()); |
1557 | return; |
1558 | } |
1559 | case DiffTree::TemplateTemplate: { |
1560 | TemplateDecl *FromTD, *ToTD; |
1561 | Tree.GetTemplateTemplateDiff(FromTD, ToTD); |
1562 | PrintTemplateTemplate(FromTD, ToTD, FromDefault: Tree.FromDefault(), |
1563 | ToDefault: Tree.ToDefault(), Same: Tree.NodeIsSame()); |
1564 | return; |
1565 | } |
1566 | case DiffTree::Integer: { |
1567 | llvm::APSInt FromInt, ToInt; |
1568 | Expr *FromExpr, *ToExpr; |
1569 | bool IsValidFromInt, IsValidToInt; |
1570 | QualType FromIntType, ToIntType; |
1571 | Tree.GetIntegerDiff(FromInt, ToInt, IsValidFromInt, IsValidToInt, |
1572 | FromIntType, ToIntType, FromExpr, ToExpr); |
1573 | PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt, FromIntType, |
1574 | ToIntType, FromExpr, ToExpr, FromDefault: Tree.FromDefault(), |
1575 | ToDefault: Tree.ToDefault(), Same: Tree.NodeIsSame()); |
1576 | return; |
1577 | } |
1578 | case DiffTree::Declaration: { |
1579 | ValueDecl *FromValueDecl, *ToValueDecl; |
1580 | bool FromAddressOf, ToAddressOf; |
1581 | bool FromNullPtr, ToNullPtr; |
1582 | Expr *FromExpr, *ToExpr; |
1583 | Tree.GetDeclarationDiff(FromValueDecl, ToValueDecl, FromAddressOf, |
1584 | ToAddressOf, FromNullPtr, ToNullPtr, FromExpr, |
1585 | ToExpr); |
1586 | PrintValueDecl(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf, |
1587 | FromNullPtr, ToNullPtr, FromExpr, ToExpr, |
1588 | FromDefault: Tree.FromDefault(), ToDefault: Tree.ToDefault(), Same: Tree.NodeIsSame()); |
1589 | return; |
1590 | } |
1591 | case DiffTree::FromDeclarationAndToInteger: { |
1592 | ValueDecl *FromValueDecl; |
1593 | bool FromAddressOf; |
1594 | bool FromNullPtr; |
1595 | Expr *FromExpr; |
1596 | llvm::APSInt ToInt; |
1597 | bool IsValidToInt; |
1598 | QualType ToIntType; |
1599 | Expr *ToExpr; |
1600 | Tree.GetFromDeclarationAndToIntegerDiff( |
1601 | FromValueDecl, FromAddressOf, FromNullPtr, FromExpr, ToInt, |
1602 | IsValidToInt, ToIntType, ToExpr); |
1603 | assert((FromValueDecl || FromNullPtr) && IsValidToInt); |
1604 | PrintValueDeclAndInteger(VD: FromValueDecl, NeedAddressOf: FromAddressOf, IsNullPtr: FromNullPtr, |
1605 | VDExpr: FromExpr, DefaultDecl: Tree.FromDefault(), Val: ToInt, IntType: ToIntType, |
1606 | IntExpr: ToExpr, DefaultInt: Tree.ToDefault()); |
1607 | return; |
1608 | } |
1609 | case DiffTree::FromIntegerAndToDeclaration: { |
1610 | llvm::APSInt FromInt; |
1611 | bool IsValidFromInt; |
1612 | QualType FromIntType; |
1613 | Expr *FromExpr; |
1614 | ValueDecl *ToValueDecl; |
1615 | bool ToAddressOf; |
1616 | bool ToNullPtr; |
1617 | Expr *ToExpr; |
1618 | Tree.GetFromIntegerAndToDeclarationDiff( |
1619 | FromInt, IsValidFromInt, FromIntType, FromExpr, ToValueDecl, |
1620 | ToAddressOf, ToNullPtr, ToExpr); |
1621 | assert(IsValidFromInt && (ToValueDecl || ToNullPtr)); |
1622 | PrintIntegerAndValueDecl(Val: FromInt, IntType: FromIntType, IntExpr: FromExpr, |
1623 | DefaultInt: Tree.FromDefault(), VD: ToValueDecl, NeedAddressOf: ToAddressOf, |
1624 | IsNullPtr: ToNullPtr, VDExpr: ToExpr, DefaultDecl: Tree.ToDefault()); |
1625 | return; |
1626 | } |
1627 | case DiffTree::Template: { |
1628 | // Node is root of template. Recurse on children. |
1629 | TemplateDecl *FromTD, *ToTD; |
1630 | Qualifiers FromQual, ToQual; |
1631 | Tree.GetTemplateDiff(FromTD, ToTD, FromQual, ToQual); |
1632 | |
1633 | PrintQualifiers(FromQual, ToQual); |
1634 | |
1635 | if (!Tree.HasChildren()) { |
1636 | // If we're dealing with a template specialization with zero |
1637 | // arguments, there are no children; special-case this. |
1638 | OS << FromTD->getDeclName() << "<>"; |
1639 | return; |
1640 | } |
1641 | |
1642 | OS << FromTD->getDeclName() << '<'; |
1643 | Tree.MoveToChild(); |
1644 | unsigned NumElideArgs = 0; |
1645 | bool AllArgsElided = true; |
1646 | do { |
1647 | if (ElideType) { |
1648 | if (Tree.NodeIsSame()) { |
1649 | ++NumElideArgs; |
1650 | continue; |
1651 | } |
1652 | AllArgsElided = false; |
1653 | if (NumElideArgs > 0) { |
1654 | PrintElideArgs(NumElideArgs, Indent); |
1655 | NumElideArgs = 0; |
1656 | OS << ", "; |
1657 | } |
1658 | } |
1659 | TreeToString(Indent); |
1660 | if (Tree.HasNextSibling()) |
1661 | OS << ", "; |
1662 | } while (Tree.AdvanceSibling()); |
1663 | if (NumElideArgs > 0) { |
1664 | if (AllArgsElided) |
1665 | OS << "..."; |
1666 | else |
1667 | PrintElideArgs(NumElideArgs, Indent); |
1668 | } |
1669 | |
1670 | Tree.Parent(); |
1671 | OS << ">"; |
1672 | return; |
1673 | } |
1674 | } |
1675 | } |
1676 | |
1677 | // To signal to the text printer that a certain text needs to be bolded, |
1678 | // a special character is injected into the character stream which the |
1679 | // text printer will later strip out. |
1680 | |
1681 | /// Bold - Start bolding text. |
1682 | void Bold() { |
1683 | assert(!IsBold && "Attempting to bold text that is already bold."); |
1684 | IsBold = true; |
1685 | if (ShowColor) |
1686 | OS << ToggleHighlight; |
1687 | } |
1688 | |
1689 | /// Unbold - Stop bolding text. |
1690 | void Unbold() { |
1691 | assert(IsBold && "Attempting to remove bold from unbold text."); |
1692 | IsBold = false; |
1693 | if (ShowColor) |
1694 | OS << ToggleHighlight; |
1695 | } |
1696 | |
1697 | // Functions to print out the arguments and highlighting the difference. |
1698 | |
1699 | /// PrintTypeNames - prints the typenames, bolding differences. Will detect |
1700 | /// typenames that are the same and attempt to disambiguate them by using |
1701 | /// canonical typenames. |
1702 | void PrintTypeNames(QualType FromType, QualType ToType, |
1703 | bool FromDefault, bool ToDefault, bool Same) { |
1704 | assert((!FromType.isNull() || !ToType.isNull()) && |
1705 | "Only one template argument may be missing."); |
1706 | |
1707 | if (Same) { |
1708 | OS << FromType.getAsString(Policy); |
1709 | return; |
1710 | } |
1711 | |
1712 | if (!FromType.isNull() && !ToType.isNull() && |
1713 | FromType.getLocalUnqualifiedType() == |
1714 | ToType.getLocalUnqualifiedType()) { |
1715 | Qualifiers FromQual = FromType.getLocalQualifiers(), |
1716 | ToQual = ToType.getLocalQualifiers(); |
1717 | PrintQualifiers(FromQual, ToQual); |
1718 | FromType.getLocalUnqualifiedType().print(OS, Policy); |
1719 | return; |
1720 | } |
1721 | |
1722 | std::string FromTypeStr = FromType.isNull() ? "(no argument)" |
1723 | : FromType.getAsString(Policy); |
1724 | std::string ToTypeStr = ToType.isNull() ? "(no argument)" |
1725 | : ToType.getAsString(Policy); |
1726 | // Print without ElaboratedType sugar if it is better. |
1727 | // TODO: merge this with other aka printing above. |
1728 | if (FromTypeStr == ToTypeStr) { |
1729 | const auto *FromElTy = dyn_cast<ElaboratedType>(Val&: FromType), |
1730 | *ToElTy = dyn_cast<ElaboratedType>(Val&: ToType); |
1731 | if (FromElTy || ToElTy) { |
1732 | std::string FromNamedTypeStr = |
1733 | FromElTy ? FromElTy->getNamedType().getAsString(Policy) |
1734 | : FromTypeStr; |
1735 | std::string ToNamedTypeStr = |
1736 | ToElTy ? ToElTy->getNamedType().getAsString(Policy) : ToTypeStr; |
1737 | if (FromNamedTypeStr != ToNamedTypeStr) { |
1738 | FromTypeStr = FromNamedTypeStr; |
1739 | ToTypeStr = ToNamedTypeStr; |
1740 | goto PrintTypes; |
1741 | } |
1742 | } |
1743 | // Switch to canonical typename if it is better. |
1744 | std::string FromCanTypeStr = |
1745 | FromType.getCanonicalType().getAsString(Policy); |
1746 | std::string ToCanTypeStr = ToType.getCanonicalType().getAsString(Policy); |
1747 | if (FromCanTypeStr != ToCanTypeStr) { |
1748 | FromTypeStr = FromCanTypeStr; |
1749 | ToTypeStr = ToCanTypeStr; |
1750 | } |
1751 | } |
1752 | |
1753 | PrintTypes: |
1754 | if (PrintTree) OS << '['; |
1755 | OS << (FromDefault ? "(default) ": ""); |
1756 | Bold(); |
1757 | OS << FromTypeStr; |
1758 | Unbold(); |
1759 | if (PrintTree) { |
1760 | OS << " != "<< (ToDefault ? "(default) ": ""); |
1761 | Bold(); |
1762 | OS << ToTypeStr; |
1763 | Unbold(); |
1764 | OS << "]"; |
1765 | } |
1766 | } |
1767 | |
1768 | /// PrintExpr - Prints out the expr template arguments, highlighting argument |
1769 | /// differences. |
1770 | void PrintExpr(const Expr *FromExpr, const Expr *ToExpr, bool FromDefault, |
1771 | bool ToDefault, bool Same) { |
1772 | assert((FromExpr || ToExpr) && |
1773 | "Only one template argument may be missing."); |
1774 | if (Same) { |
1775 | PrintExpr(E: FromExpr); |
1776 | } else if (!PrintTree) { |
1777 | OS << (FromDefault ? "(default) ": ""); |
1778 | Bold(); |
1779 | PrintExpr(E: FromExpr); |
1780 | Unbold(); |
1781 | } else { |
1782 | OS << (FromDefault ? "[(default) ": "["); |
1783 | Bold(); |
1784 | PrintExpr(E: FromExpr); |
1785 | Unbold(); |
1786 | OS << " != "<< (ToDefault ? "(default) ": ""); |
1787 | Bold(); |
1788 | PrintExpr(E: ToExpr); |
1789 | Unbold(); |
1790 | OS << ']'; |
1791 | } |
1792 | } |
1793 | |
1794 | /// PrintExpr - Actual formatting and printing of expressions. |
1795 | void PrintExpr(const Expr *E) { |
1796 | if (E) { |
1797 | E->printPretty(OS, nullptr, Policy); |
1798 | return; |
1799 | } |
1800 | OS << "(no argument)"; |
1801 | } |
1802 | |
1803 | /// PrintTemplateTemplate - Handles printing of template template arguments, |
1804 | /// highlighting argument differences. |
1805 | void PrintTemplateTemplate(TemplateDecl *FromTD, TemplateDecl *ToTD, |
1806 | bool FromDefault, bool ToDefault, bool Same) { |
1807 | assert((FromTD || ToTD) && "Only one template argument may be missing."); |
1808 | |
1809 | std::string FromName = |
1810 | std::string(FromTD ? FromTD->getName() : "(no argument)"); |
1811 | std::string ToName = std::string(ToTD ? ToTD->getName() : "(no argument)"); |
1812 | if (FromTD && ToTD && FromName == ToName) { |
1813 | FromName = FromTD->getQualifiedNameAsString(); |
1814 | ToName = ToTD->getQualifiedNameAsString(); |
1815 | } |
1816 | |
1817 | if (Same) { |
1818 | OS << "template "<< FromTD->getDeclName(); |
1819 | } else if (!PrintTree) { |
1820 | OS << (FromDefault ? "(default) template ": "template "); |
1821 | Bold(); |
1822 | OS << FromName; |
1823 | Unbold(); |
1824 | } else { |
1825 | OS << (FromDefault ? "[(default) template ": "[template "); |
1826 | Bold(); |
1827 | OS << FromName; |
1828 | Unbold(); |
1829 | OS << " != "<< (ToDefault ? "(default) template ": "template "); |
1830 | Bold(); |
1831 | OS << ToName; |
1832 | Unbold(); |
1833 | OS << ']'; |
1834 | } |
1835 | } |
1836 | |
1837 | /// PrintAPSInt - Handles printing of integral arguments, highlighting |
1838 | /// argument differences. |
1839 | void PrintAPSInt(const llvm::APSInt &FromInt, const llvm::APSInt &ToInt, |
1840 | bool IsValidFromInt, bool IsValidToInt, QualType FromIntType, |
1841 | QualType ToIntType, Expr *FromExpr, Expr *ToExpr, |
1842 | bool FromDefault, bool ToDefault, bool Same) { |
1843 | assert((IsValidFromInt || IsValidToInt) && |
1844 | "Only one integral argument may be missing."); |
1845 | |
1846 | if (Same) { |
1847 | if (FromIntType->isBooleanType()) { |
1848 | OS << ((FromInt == 0) ? "false": "true"); |
1849 | } else { |
1850 | OS << toString(I: FromInt, Radix: 10); |
1851 | } |
1852 | return; |
1853 | } |
1854 | |
1855 | bool PrintType = IsValidFromInt && IsValidToInt && |
1856 | !Context.hasSameType(T1: FromIntType, T2: ToIntType); |
1857 | |
1858 | if (!PrintTree) { |
1859 | OS << (FromDefault ? "(default) ": ""); |
1860 | PrintAPSInt(Val: FromInt, E: FromExpr, Valid: IsValidFromInt, IntType: FromIntType, PrintType); |
1861 | } else { |
1862 | OS << (FromDefault ? "[(default) ": "["); |
1863 | PrintAPSInt(Val: FromInt, E: FromExpr, Valid: IsValidFromInt, IntType: FromIntType, PrintType); |
1864 | OS << " != "<< (ToDefault ? "(default) ": ""); |
1865 | PrintAPSInt(Val: ToInt, E: ToExpr, Valid: IsValidToInt, IntType: ToIntType, PrintType); |
1866 | OS << ']'; |
1867 | } |
1868 | } |
1869 | |
1870 | /// PrintAPSInt - If valid, print the APSInt. If the expression is |
1871 | /// gives more information, print it too. |
1872 | void PrintAPSInt(const llvm::APSInt &Val, Expr *E, bool Valid, |
1873 | QualType IntType, bool PrintType) { |
1874 | Bold(); |
1875 | if (Valid) { |
1876 | if (HasExtraInfo(E)) { |
1877 | PrintExpr(E); |
1878 | Unbold(); |
1879 | OS << " aka "; |
1880 | Bold(); |
1881 | } |
1882 | if (PrintType) { |
1883 | Unbold(); |
1884 | OS << "("; |
1885 | Bold(); |
1886 | IntType.print(OS, Policy: Context.getPrintingPolicy()); |
1887 | Unbold(); |
1888 | OS << ") "; |
1889 | Bold(); |
1890 | } |
1891 | if (IntType->isBooleanType()) { |
1892 | OS << ((Val == 0) ? "false": "true"); |
1893 | } else { |
1894 | OS << toString(I: Val, Radix: 10); |
1895 | } |
1896 | } else if (E) { |
1897 | PrintExpr(E); |
1898 | } else { |
1899 | OS << "(no argument)"; |
1900 | } |
1901 | Unbold(); |
1902 | } |
1903 | |
1904 | /// HasExtraInfo - Returns true if E is not an integer literal, the |
1905 | /// negation of an integer literal, or a boolean literal. |
1906 | bool HasExtraInfo(Expr *E) { |
1907 | if (!E) return false; |
1908 | |
1909 | E = E->IgnoreImpCasts(); |
1910 | |
1911 | auto CheckIntegerLiteral = [](Expr *E) { |
1912 | if (auto *TemplateExpr = dyn_cast<SubstNonTypeTemplateParmExpr>(Val: E)) |
1913 | E = TemplateExpr->getReplacement(); |
1914 | return isa<IntegerLiteral>(Val: E); |
1915 | }; |
1916 | |
1917 | if (CheckIntegerLiteral(E)) return false; |
1918 | |
1919 | if (UnaryOperator *UO = dyn_cast<UnaryOperator>(Val: E)) |
1920 | if (UO->getOpcode() == UO_Minus) |
1921 | if (CheckIntegerLiteral(UO->getSubExpr())) |
1922 | return false; |
1923 | |
1924 | if (isa<CXXBoolLiteralExpr>(Val: E)) |
1925 | return false; |
1926 | |
1927 | return true; |
1928 | } |
1929 | |
1930 | void PrintValueDecl(ValueDecl *VD, bool AddressOf, Expr *E, bool NullPtr) { |
1931 | if (VD) { |
1932 | if (AddressOf) |
1933 | OS << "&"; |
1934 | else if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(Val: VD)) { |
1935 | // FIXME: Diffing the APValue would be neat. |
1936 | // FIXME: Suppress this and use the full name of the declaration if the |
1937 | // parameter is a pointer or reference. |
1938 | TPO->getType().getUnqualifiedType().print(OS, Policy); |
1939 | TPO->printAsInit(OS, Policy); |
1940 | return; |
1941 | } |
1942 | VD->printName(OS, Policy); |
1943 | return; |
1944 | } |
1945 | |
1946 | if (NullPtr) { |
1947 | if (E && !isa<CXXNullPtrLiteralExpr>(Val: E)) { |
1948 | PrintExpr(E); |
1949 | if (IsBold) { |
1950 | Unbold(); |
1951 | OS << " aka "; |
1952 | Bold(); |
1953 | } else { |
1954 | OS << " aka "; |
1955 | } |
1956 | } |
1957 | |
1958 | OS << "nullptr"; |
1959 | return; |
1960 | } |
1961 | |
1962 | if (E) { |
1963 | PrintExpr(E); |
1964 | return; |
1965 | } |
1966 | |
1967 | OS << "(no argument)"; |
1968 | } |
1969 | |
1970 | /// PrintDecl - Handles printing of Decl arguments, highlighting |
1971 | /// argument differences. |
1972 | void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl, |
1973 | bool FromAddressOf, bool ToAddressOf, bool FromNullPtr, |
1974 | bool ToNullPtr, Expr *FromExpr, Expr *ToExpr, |
1975 | bool FromDefault, bool ToDefault, bool Same) { |
1976 | assert((FromValueDecl || FromNullPtr || ToValueDecl || ToNullPtr) && |
1977 | "Only one Decl argument may be NULL"); |
1978 | |
1979 | if (Same) { |
1980 | PrintValueDecl(VD: FromValueDecl, AddressOf: FromAddressOf, E: FromExpr, NullPtr: FromNullPtr); |
1981 | } else if (!PrintTree) { |
1982 | OS << (FromDefault ? "(default) ": ""); |
1983 | Bold(); |
1984 | PrintValueDecl(VD: FromValueDecl, AddressOf: FromAddressOf, E: FromExpr, NullPtr: FromNullPtr); |
1985 | Unbold(); |
1986 | } else { |
1987 | OS << (FromDefault ? "[(default) ": "["); |
1988 | Bold(); |
1989 | PrintValueDecl(VD: FromValueDecl, AddressOf: FromAddressOf, E: FromExpr, NullPtr: FromNullPtr); |
1990 | Unbold(); |
1991 | OS << " != "<< (ToDefault ? "(default) ": ""); |
1992 | Bold(); |
1993 | PrintValueDecl(VD: ToValueDecl, AddressOf: ToAddressOf, E: ToExpr, NullPtr: ToNullPtr); |
1994 | Unbold(); |
1995 | OS << ']'; |
1996 | } |
1997 | } |
1998 | |
1999 | /// PrintValueDeclAndInteger - Uses the print functions for ValueDecl and |
2000 | /// APSInt to print a mixed difference. |
2001 | void PrintValueDeclAndInteger(ValueDecl *VD, bool NeedAddressOf, |
2002 | bool IsNullPtr, Expr *VDExpr, bool DefaultDecl, |
2003 | const llvm::APSInt &Val, QualType IntType, |
2004 | Expr *IntExpr, bool DefaultInt) { |
2005 | if (!PrintTree) { |
2006 | OS << (DefaultDecl ? "(default) ": ""); |
2007 | Bold(); |
2008 | PrintValueDecl(VD, AddressOf: NeedAddressOf, E: VDExpr, NullPtr: IsNullPtr); |
2009 | Unbold(); |
2010 | } else { |
2011 | OS << (DefaultDecl ? "[(default) ": "["); |
2012 | Bold(); |
2013 | PrintValueDecl(VD, AddressOf: NeedAddressOf, E: VDExpr, NullPtr: IsNullPtr); |
2014 | Unbold(); |
2015 | OS << " != "<< (DefaultInt ? "(default) ": ""); |
2016 | PrintAPSInt(Val, E: IntExpr, Valid: true /*Valid*/, IntType, PrintType: false /*PrintType*/); |
2017 | OS << ']'; |
2018 | } |
2019 | } |
2020 | |
2021 | /// PrintIntegerAndValueDecl - Uses the print functions for APSInt and |
2022 | /// ValueDecl to print a mixed difference. |
2023 | void PrintIntegerAndValueDecl(const llvm::APSInt &Val, QualType IntType, |
2024 | Expr *IntExpr, bool DefaultInt, ValueDecl *VD, |
2025 | bool NeedAddressOf, bool IsNullPtr, |
2026 | Expr *VDExpr, bool DefaultDecl) { |
2027 | if (!PrintTree) { |
2028 | OS << (DefaultInt ? "(default) ": ""); |
2029 | PrintAPSInt(Val, E: IntExpr, Valid: true /*Valid*/, IntType, PrintType: false /*PrintType*/); |
2030 | } else { |
2031 | OS << (DefaultInt ? "[(default) ": "["); |
2032 | PrintAPSInt(Val, E: IntExpr, Valid: true /*Valid*/, IntType, PrintType: false /*PrintType*/); |
2033 | OS << " != "<< (DefaultDecl ? "(default) ": ""); |
2034 | Bold(); |
2035 | PrintValueDecl(VD, AddressOf: NeedAddressOf, E: VDExpr, NullPtr: IsNullPtr); |
2036 | Unbold(); |
2037 | OS << ']'; |
2038 | } |
2039 | } |
2040 | |
2041 | // Prints the appropriate placeholder for elided template arguments. |
2042 | void PrintElideArgs(unsigned NumElideArgs, unsigned Indent) { |
2043 | if (PrintTree) { |
2044 | OS << '\n'; |
2045 | for (unsigned i = 0; i < Indent; ++i) |
2046 | OS << " "; |
2047 | } |
2048 | if (NumElideArgs == 0) return; |
2049 | if (NumElideArgs == 1) |
2050 | OS << "[...]"; |
2051 | else |
2052 | OS << "["<< NumElideArgs << " * ...]"; |
2053 | } |
2054 | |
2055 | // Prints and highlights differences in Qualifiers. |
2056 | void PrintQualifiers(Qualifiers FromQual, Qualifiers ToQual) { |
2057 | // Both types have no qualifiers |
2058 | if (FromQual.empty() && ToQual.empty()) |
2059 | return; |
2060 | |
2061 | // Both types have same qualifiers |
2062 | if (FromQual == ToQual) { |
2063 | PrintQualifier(Q: FromQual, /*ApplyBold*/false); |
2064 | return; |
2065 | } |
2066 | |
2067 | // Find common qualifiers and strip them from FromQual and ToQual. |
2068 | Qualifiers CommonQual = Qualifiers::removeCommonQualifiers(L&: FromQual, |
2069 | R&: ToQual); |
2070 | |
2071 | // The qualifiers are printed before the template name. |
2072 | // Inline printing: |
2073 | // The common qualifiers are printed. Then, qualifiers only in this type |
2074 | // are printed and highlighted. Finally, qualifiers only in the other |
2075 | // type are printed and highlighted inside parentheses after "missing". |
2076 | // Tree printing: |
2077 | // Qualifiers are printed next to each other, inside brackets, and |
2078 | // separated by "!=". The printing order is: |
2079 | // common qualifiers, highlighted from qualifiers, "!=", |
2080 | // common qualifiers, highlighted to qualifiers |
2081 | if (PrintTree) { |
2082 | OS << "["; |
2083 | if (CommonQual.empty() && FromQual.empty()) { |
2084 | Bold(); |
2085 | OS << "(no qualifiers) "; |
2086 | Unbold(); |
2087 | } else { |
2088 | PrintQualifier(Q: CommonQual, /*ApplyBold*/false); |
2089 | PrintQualifier(Q: FromQual, /*ApplyBold*/true); |
2090 | } |
2091 | OS << "!= "; |
2092 | if (CommonQual.empty() && ToQual.empty()) { |
2093 | Bold(); |
2094 | OS << "(no qualifiers)"; |
2095 | Unbold(); |
2096 | } else { |
2097 | PrintQualifier(Q: CommonQual, /*ApplyBold*/false, |
2098 | /*appendSpaceIfNonEmpty*/AppendSpaceIfNonEmpty: !ToQual.empty()); |
2099 | PrintQualifier(Q: ToQual, /*ApplyBold*/true, |
2100 | /*appendSpaceIfNonEmpty*/AppendSpaceIfNonEmpty: false); |
2101 | } |
2102 | OS << "] "; |
2103 | } else { |
2104 | PrintQualifier(Q: CommonQual, /*ApplyBold*/false); |
2105 | PrintQualifier(Q: FromQual, /*ApplyBold*/true); |
2106 | } |
2107 | } |
2108 | |
2109 | void PrintQualifier(Qualifiers Q, bool ApplyBold, |
2110 | bool AppendSpaceIfNonEmpty = true) { |
2111 | if (Q.empty()) return; |
2112 | if (ApplyBold) Bold(); |
2113 | Q.print(OS, Policy, appendSpaceIfNonEmpty: AppendSpaceIfNonEmpty); |
2114 | if (ApplyBold) Unbold(); |
2115 | } |
2116 | |
2117 | public: |
2118 | |
2119 | TemplateDiff(raw_ostream &OS, ASTContext &Context, QualType FromType, |
2120 | QualType ToType, bool PrintTree, bool PrintFromType, |
2121 | bool ElideType, bool ShowColor) |
2122 | : Context(Context), |
2123 | Policy(Context.getLangOpts()), |
2124 | ElideType(ElideType), |
2125 | PrintTree(PrintTree), |
2126 | ShowColor(ShowColor), |
2127 | // When printing a single type, the FromType is the one printed. |
2128 | FromTemplateType(PrintFromType ? FromType : ToType), |
2129 | ToTemplateType(PrintFromType ? ToType : FromType), |
2130 | OS(OS), |
2131 | IsBold(false) { |
2132 | } |
2133 | |
2134 | /// DiffTemplate - Start the template type diffing. |
2135 | void DiffTemplate() { |
2136 | Qualifiers FromQual = FromTemplateType.getQualifiers(), |
2137 | ToQual = ToTemplateType.getQualifiers(); |
2138 | |
2139 | const TemplateSpecializationType *FromOrigTST = |
2140 | GetTemplateSpecializationType(Context, FromTemplateType); |
2141 | const TemplateSpecializationType *ToOrigTST = |
2142 | GetTemplateSpecializationType(Context, ToTemplateType); |
2143 | |
2144 | // Only checking templates. |
2145 | if (!FromOrigTST || !ToOrigTST) |
2146 | return; |
2147 | |
2148 | // Different base templates. |
2149 | if (!hasSameTemplate(Context, FromTST&: FromOrigTST, ToTST&: ToOrigTST)) { |
2150 | return; |
2151 | } |
2152 | |
2153 | FromQual -= QualType(FromOrigTST, 0).getQualifiers(); |
2154 | ToQual -= QualType(ToOrigTST, 0).getQualifiers(); |
2155 | |
2156 | // Same base template, but different arguments. |
2157 | Tree.SetTemplateDiff( |
2158 | FromTD: FromOrigTST->getTemplateName().getAsTemplateDecl( |
2159 | /*IgnoreDeduced=*/true), |
2160 | ToTD: ToOrigTST->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true), |
2161 | FromQual, ToQual, FromDefault: false /*FromDefault*/, ToDefault: false /*ToDefault*/); |
2162 | |
2163 | DiffTemplate(FromTST: FromOrigTST, ToTST: ToOrigTST); |
2164 | } |
2165 | |
2166 | /// Emit - When the two types given are templated types with the same |
2167 | /// base template, a string representation of the type difference will be |
2168 | /// emitted to the stream and return true. Otherwise, return false. |
2169 | bool Emit() { |
2170 | Tree.StartTraverse(); |
2171 | if (Tree.Empty()) |
2172 | return false; |
2173 | |
2174 | TreeToString(); |
2175 | assert(!IsBold && "Bold is applied to end of string."); |
2176 | return true; |
2177 | } |
2178 | }; // end class TemplateDiff |
2179 | } // end anonymous namespace |
2180 | |
2181 | /// FormatTemplateTypeDiff - A helper static function to start the template |
2182 | /// diff and return the properly formatted string. Returns true if the diff |
2183 | /// is successful. |
2184 | static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType, |
2185 | QualType ToType, bool PrintTree, |
2186 | bool PrintFromType, bool ElideType, |
2187 | bool ShowColors, raw_ostream &OS) { |
2188 | if (PrintTree) |
2189 | PrintFromType = true; |
2190 | TemplateDiff TD(OS, Context, FromType, ToType, PrintTree, PrintFromType, |
2191 | ElideType, ShowColors); |
2192 | TD.DiffTemplate(); |
2193 | return TD.Emit(); |
2194 | } |
2195 | |
2196 | std::string clang::FormatUTFCodeUnitAsCodepoint(unsigned Value, QualType T) { |
2197 | auto IsSingleCodeUnitCP = [](unsigned Value, QualType T) { |
2198 | if (T->isChar8Type()) { |
2199 | assert(Value <= 0xFF && "not a valid UTF-8 code unit"); |
2200 | return Value <= 0x7F; |
2201 | } |
2202 | if (T->isChar16Type()) { |
2203 | assert(Value <= 0xFFFF && "not a valid UTF-16 code unit"); |
2204 | return llvm::IsSingleCodeUnitUTF16Codepoint(Value); |
2205 | } |
2206 | assert(T->isChar32Type()); |
2207 | return llvm::IsSingleCodeUnitUTF32Codepoint(Value); |
2208 | }; |
2209 | llvm::SmallVector<char, 16> Str; |
2210 | if (!IsSingleCodeUnitCP(Value, T)) { |
2211 | llvm::raw_svector_ostream OS(Str); |
2212 | OS << "<"<< llvm::format_hex(N: Value, Width: 1, /*Upper=*/true) << ">"; |
2213 | return std::string(Str.begin(), Str.end()); |
2214 | } |
2215 | |
2216 | char Buffer[UNI_MAX_UTF8_BYTES_PER_CODE_POINT]; |
2217 | char *Ptr = Buffer; |
2218 | [[maybe_unused]] bool Converted = llvm::ConvertCodePointToUTF8(Source: Value, ResultPtr&: Ptr); |
2219 | assert(Converted && "trying to encode invalid code unit"); |
2220 | EscapeStringForDiagnostic(Str: StringRef(Buffer, Ptr - Buffer), OutStr&: Str); |
2221 | return std::string(Str.begin(), Str.end()); |
2222 | } |
2223 |
Definitions
- desugarForDiagnostic
- ConvertTypeToDiagnosticString
- FormatASTNodeDiagnosticArgument
- TemplateDiff
- DiffTree
- DiffKind
- TemplateArgumentInfo
- DiffNode
- DiffNode
- DiffTree
- SetTemplateDiff
- SetTypeDiff
- SetExpressionDiff
- SetTemplateTemplateDiff
- SetIntegerDiff
- SetDeclarationDiff
- SetFromDeclarationAndToIntegerDiff
- SetFromIntegerAndToDeclarationDiff
- SetDefault
- SetSame
- SetKind
- Up
- AddNode
- StartTraverse
- Parent
- GetTemplateDiff
- GetTypeDiff
- GetExpressionDiff
- GetTemplateTemplateDiff
- GetIntegerDiff
- GetDeclarationDiff
- GetFromDeclarationAndToIntegerDiff
- GetFromIntegerAndToDeclarationDiff
- FromDefault
- ToDefault
- NodeIsSame
- HasChildren
- MoveToChild
- AdvanceSibling
- HasNextSibling
- Empty
- GetKind
- TSTiterator
- InternalIterator
- InternalIterator
- isValid
- isEnd
- operator++
- operator*
- operator->
- TSTiterator
- operator++
- operator*
- operator->
- isEnd
- hasDesugaredTA
- getDesugaredTA
- GetTemplateSpecializationType
- OnlyPerformTypeDiff
- DiffTypes
- DiffTemplateTemplates
- InitializeNonTypeDiffVariables
- DiffNonTypes
- DiffTemplate
- makeTemplateList
- hasSameBaseTemplate
- hasSameTemplate
- GetType
- GetTemplateDecl
- IsEqualExpr
- TreeToString
- Bold
- Unbold
- PrintTypeNames
- PrintExpr
- PrintExpr
- PrintTemplateTemplate
- PrintAPSInt
- PrintAPSInt
- HasExtraInfo
- PrintValueDecl
- PrintValueDecl
- PrintValueDeclAndInteger
- PrintIntegerAndValueDecl
- PrintElideArgs
- PrintQualifiers
- PrintQualifier
- TemplateDiff
- DiffTemplate
- Emit
- FormatTemplateTypeDiff
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more