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