Bug Summary

File:clang/include/clang/Basic/Diagnostic.h
Warning:line 1196, column 5
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name EasilySwappableParametersCheck.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/clang/tools/extra/clang-tidy/bugprone -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/clang-tools-extra/clang-tidy/bugprone -I tools/clang/tools/extra/clang-tidy -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/clang/include -I tools/clang/include -I include -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/= -O3 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-01-19-134126-35450-1 -x c++ /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp

/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp

1//===--- EasilySwappableParametersCheck.cpp - clang-tidy ------------------===//
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#include "EasilySwappableParametersCheck.h"
10#include "../utils/OptionsUtils.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/AST/RecursiveASTVisitor.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "clang/Lex/Lexer.h"
15#include "llvm/ADT/SmallSet.h"
16
17#define DEBUG_TYPE"EasilySwappableParametersCheck" "EasilySwappableParametersCheck"
18#include "llvm/Support/Debug.h"
19
20namespace optutils = clang::tidy::utils::options;
21
22/// The default value for the MinimumLength check option.
23static constexpr std::size_t DefaultMinimumLength = 2;
24
25/// The default value for ignored parameter names.
26static const std::string DefaultIgnoredParameterNames =
27 optutils::serializeStringList({"\"\"", "iterator", "Iterator", "begin",
28 "Begin", "end", "End", "first", "First",
29 "last", "Last", "lhs", "LHS", "rhs", "RHS"});
30
31/// The default value for ignored parameter type suffixes.
32static const std::string DefaultIgnoredParameterTypeSuffixes =
33 optutils::serializeStringList({"bool",
34 "Bool",
35 "_Bool",
36 "it",
37 "It",
38 "iterator",
39 "Iterator",
40 "inputit",
41 "InputIt",
42 "forwardit",
43 "ForwardIt",
44 "bidirit",
45 "BidirIt",
46 "constiterator",
47 "const_iterator",
48 "Const_Iterator",
49 "Constiterator",
50 "ConstIterator",
51 "RandomIt",
52 "randomit",
53 "random_iterator",
54 "ReverseIt",
55 "reverse_iterator",
56 "reverse_const_iterator",
57 "ConstReverseIterator",
58 "Const_Reverse_Iterator",
59 "const_reverse_iterator",
60 "Constreverseiterator",
61 "constreverseiterator"});
62
63/// The default value for the QualifiersMix check option.
64static constexpr bool DefaultQualifiersMix = false;
65
66/// The default value for the ModelImplicitConversions check option.
67static constexpr bool DefaultModelImplicitConversions = true;
68
69/// The default value for suppressing diagnostics about parameters that are
70/// used together.
71static constexpr bool DefaultSuppressParametersUsedTogether = true;
72
73/// The default value for the NamePrefixSuffixSilenceDissimilarityTreshold
74/// check option.
75static constexpr std::size_t
76 DefaultNamePrefixSuffixSilenceDissimilarityTreshold = 1;
77
78using namespace clang::ast_matchers;
79
80namespace clang {
81namespace tidy {
82namespace bugprone {
83
84using TheCheck = EasilySwappableParametersCheck;
85
86namespace filter {
87class SimilarlyUsedParameterPairSuppressor;
88
89static bool isIgnoredParameter(const TheCheck &Check, const ParmVarDecl *Node);
90static inline bool
91isSimilarlyUsedParameter(const SimilarlyUsedParameterPairSuppressor &Suppressor,
92 const ParmVarDecl *Param1, const ParmVarDecl *Param2);
93static bool prefixSuffixCoverUnderThreshold(std::size_t Threshold,
94 StringRef Str1, StringRef Str2);
95} // namespace filter
96
97namespace model {
98
99/// The language features involved in allowing the mix between two parameters.
100enum class MixFlags : unsigned char {
101 Invalid = 0, ///< Sentinel bit pattern. DO NOT USE!
102
103 /// Certain constructs (such as pointers to noexcept/non-noexcept functions)
104 /// have the same CanonicalType, which would result in false positives.
105 /// During the recursive modelling call, this flag is set if a later diagnosed
106 /// canonical type equivalence should be thrown away.
107 WorkaroundDisableCanonicalEquivalence = 1,
108
109 None = 2, ///< Mix between the two parameters is not possible.
110 Trivial = 4, ///< The two mix trivially, and are the exact same type.
111 Canonical = 8, ///< The two mix because the types refer to the same
112 /// CanonicalType, but we do not elaborate as to how.
113 TypeAlias = 16, ///< The path from one type to the other involves
114 /// desugaring type aliases.
115 ReferenceBind = 32, ///< The mix involves the binding power of "const &".
116 Qualifiers = 64, ///< The mix involves change in the qualifiers.
117 ImplicitConversion = 128, ///< The mixing of the parameters is possible
118 /// through implicit conversions between the types.
119
120 LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue =*/ImplicitConversion)LLVM_BITMASK_LARGEST_ENUMERATOR = ImplicitConversion
121};
122LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE()using ::llvm::BitmaskEnumDetail::operator~; using ::llvm::BitmaskEnumDetail
::operator|; using ::llvm::BitmaskEnumDetail::operator&; using
::llvm::BitmaskEnumDetail::operator^; using ::llvm::BitmaskEnumDetail
::operator|=; using ::llvm::BitmaskEnumDetail::operator&=
; using ::llvm::BitmaskEnumDetail::operator^=
;
123
124/// Returns whether the SearchedFlag is turned on in the Data.
125static inline bool hasFlag(MixFlags Data, MixFlags SearchedFlag) {
126 assert(SearchedFlag != MixFlags::Invalid &&(static_cast <bool> (SearchedFlag != MixFlags::Invalid &&
"can't be used to detect lack of all bits!") ? void (0) : __assert_fail
("SearchedFlag != MixFlags::Invalid && \"can't be used to detect lack of all bits!\""
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 127, __extension__ __PRETTY_FUNCTION__))
127 "can't be used to detect lack of all bits!")(static_cast <bool> (SearchedFlag != MixFlags::Invalid &&
"can't be used to detect lack of all bits!") ? void (0) : __assert_fail
("SearchedFlag != MixFlags::Invalid && \"can't be used to detect lack of all bits!\""
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 127, __extension__ __PRETTY_FUNCTION__))
;
128
129 // "Data & SearchedFlag" would need static_cast<bool>() in conditions.
130 return (Data & SearchedFlag) == SearchedFlag;
131}
132
133#ifndef NDEBUG
134
135// The modelling logic of this check is more complex than usual, and
136// potentially hard to understand without the ability to see into the
137// representation during the recursive descent. This debug code is only
138// compiled in 'Debug' mode, or if LLVM_ENABLE_ASSERTIONS config is turned on.
139
140/// Formats the MixFlags enum into a useful, user-readable representation.
141static inline std::string formatMixFlags(MixFlags F) {
142 if (F == MixFlags::Invalid)
143 return "#Inv!";
144
145 SmallString<8> Str{"-------"};
146
147 if (hasFlag(F, MixFlags::None))
148 // Shows the None bit explicitly, as it can be applied in the recursion
149 // even if other bits are set.
150 Str[0] = '!';
151 if (hasFlag(F, MixFlags::Trivial))
152 Str[1] = 'T';
153 if (hasFlag(F, MixFlags::Canonical))
154 Str[2] = 'C';
155 if (hasFlag(F, MixFlags::TypeAlias))
156 Str[3] = 't';
157 if (hasFlag(F, MixFlags::ReferenceBind))
158 Str[4] = '&';
159 if (hasFlag(F, MixFlags::Qualifiers))
160 Str[5] = 'Q';
161 if (hasFlag(F, MixFlags::ImplicitConversion))
162 Str[6] = 'i';
163
164 if (hasFlag(F, MixFlags::WorkaroundDisableCanonicalEquivalence))
165 Str.append("(~C)");
166
167 return Str.str().str();
168}
169
170#endif // NDEBUG
171
172/// The results of the steps of an Implicit Conversion Sequence is saved in
173/// an instance of this record.
174///
175/// A ConversionSequence maps the steps of the conversion with a member for
176/// each type involved in the conversion. Imagine going from a hypothetical
177/// Complex class to projecting it to the real part as a const double.
178///
179/// I.e., given:
180///
181/// struct Complex {
182/// operator double() const;
183/// };
184///
185/// void functionBeingAnalysed(Complex C, const double R);
186///
187/// we will get the following sequence:
188///
189/// (Begin=) Complex
190///
191/// The first standard conversion is a qualification adjustment.
192/// (AfterFirstStandard=) const Complex
193///
194/// Then the user-defined conversion is executed.
195/// (UDConvOp.ConversionOperatorResultType=) double
196///
197/// Then this 'double' is qualifier-adjusted to 'const double'.
198/// (AfterSecondStandard=) double
199///
200/// The conversion's result has now been calculated, so it ends here.
201/// (End=) double.
202///
203/// Explicit storing of Begin and End in this record is needed, because
204/// getting to what Begin and End here are needs further resolution of types,
205/// e.g. in the case of typedefs:
206///
207/// using Comp = Complex;
208/// using CD = const double;
209/// void functionBeingAnalysed2(Comp C, CD R);
210///
211/// In this case, the user will be diagnosed with a potential conversion
212/// between the two typedefs as written in the code, but to elaborate the
213/// reasoning behind this conversion, we also need to show what the typedefs
214/// mean. See FormattedConversionSequence towards the bottom of this file!
215struct ConversionSequence {
216 enum UserDefinedConversionKind { UDCK_None, UDCK_Ctor, UDCK_Oper };
217
218 struct UserDefinedConvertingConstructor {
219 const CXXConstructorDecl *Fun;
220 QualType ConstructorParameterType;
221 QualType UserDefinedType;
222 };
223
224 struct UserDefinedConversionOperator {
225 const CXXConversionDecl *Fun;
226 QualType UserDefinedType;
227 QualType ConversionOperatorResultType;
228 };
229
230 /// The type the conversion stared from.
231 QualType Begin;
232
233 /// The intermediate type after the first Standard Conversion Sequence.
234 QualType AfterFirstStandard;
235
236 /// The details of the user-defined conversion involved, as a tagged union.
237 union {
238 char None;
239 UserDefinedConvertingConstructor UDConvCtor;
240 UserDefinedConversionOperator UDConvOp;
241 };
242 UserDefinedConversionKind UDConvKind;
243
244 /// The intermediate type after performing the second Standard Conversion
245 /// Sequence.
246 QualType AfterSecondStandard;
247
248 /// The result type the conversion targeted.
249 QualType End;
250
251 ConversionSequence() : None(0), UDConvKind(UDCK_None) {}
252 ConversionSequence(QualType From, QualType To)
253 : Begin(From), None(0), UDConvKind(UDCK_None), End(To) {}
254
255 explicit operator bool() const {
256 return !AfterFirstStandard.isNull() || UDConvKind != UDCK_None ||
257 !AfterSecondStandard.isNull();
258 }
259
260 /// Returns all the "steps" (non-unique and non-similar) types involved in
261 /// the conversion sequence. This method does **NOT** return Begin and End.
262 SmallVector<QualType, 4> getInvolvedTypesInSequence() const {
263 SmallVector<QualType, 4> Ret;
264 auto EmplaceIfDifferent = [&Ret](QualType QT) {
265 if (QT.isNull())
266 return;
267 if (Ret.empty())
268 Ret.emplace_back(QT);
269 else if (Ret.back() != QT)
270 Ret.emplace_back(QT);
271 };
272
273 EmplaceIfDifferent(AfterFirstStandard);
274 switch (UDConvKind) {
275 case UDCK_Ctor:
276 EmplaceIfDifferent(UDConvCtor.ConstructorParameterType);
277 EmplaceIfDifferent(UDConvCtor.UserDefinedType);
278 break;
279 case UDCK_Oper:
280 EmplaceIfDifferent(UDConvOp.UserDefinedType);
281 EmplaceIfDifferent(UDConvOp.ConversionOperatorResultType);
282 break;
283 case UDCK_None:
284 break;
285 }
286 EmplaceIfDifferent(AfterSecondStandard);
287
288 return Ret;
289 }
290
291 /// Updates the steps of the conversion sequence with the steps from the
292 /// other instance.
293 ///
294 /// \note This method does not check if the resulting conversion sequence is
295 /// sensible!
296 ConversionSequence &update(const ConversionSequence &RHS) {
297 if (!RHS.AfterFirstStandard.isNull())
298 AfterFirstStandard = RHS.AfterFirstStandard;
299 switch (RHS.UDConvKind) {
300 case UDCK_Ctor:
301 UDConvKind = UDCK_Ctor;
302 UDConvCtor = RHS.UDConvCtor;
303 break;
304 case UDCK_Oper:
305 UDConvKind = UDCK_Oper;
306 UDConvOp = RHS.UDConvOp;
307 break;
308 case UDCK_None:
309 break;
310 }
311 if (!RHS.AfterSecondStandard.isNull())
312 AfterSecondStandard = RHS.AfterSecondStandard;
313
314 return *this;
315 }
316
317 /// Sets the user-defined conversion to the given constructor.
318 void setConversion(const UserDefinedConvertingConstructor &UDCC) {
319 UDConvKind = UDCK_Ctor;
320 UDConvCtor = UDCC;
321 }
322
323 /// Sets the user-defined conversion to the given operator.
324 void setConversion(const UserDefinedConversionOperator &UDCO) {
325 UDConvKind = UDCK_Oper;
326 UDConvOp = UDCO;
327 }
328
329 /// Returns the type in the conversion that's formally "in our hands" once
330 /// the user-defined conversion is executed.
331 QualType getTypeAfterUserDefinedConversion() const {
332 switch (UDConvKind) {
333 case UDCK_Ctor:
334 return UDConvCtor.UserDefinedType;
335 case UDCK_Oper:
336 return UDConvOp.ConversionOperatorResultType;
337 case UDCK_None:
338 return {};
339 }
340 llvm_unreachable("Invalid UDConv kind.")::llvm::llvm_unreachable_internal("Invalid UDConv kind.", "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 340)
;
341 }
342
343 const CXXMethodDecl *getUserDefinedConversionFunction() const {
344 switch (UDConvKind) {
345 case UDCK_Ctor:
346 return UDConvCtor.Fun;
347 case UDCK_Oper:
348 return UDConvOp.Fun;
349 case UDCK_None:
350 return {};
351 }
352 llvm_unreachable("Invalid UDConv kind.")::llvm::llvm_unreachable_internal("Invalid UDConv kind.", "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 352)
;
353 }
354
355 /// Returns the SourceRange in the text that corresponds to the interesting
356 /// part of the user-defined conversion. This is either the parameter type
357 /// in a converting constructor, or the conversion result type in a conversion
358 /// operator.
359 SourceRange getUserDefinedConversionHighlight() const {
360 switch (UDConvKind) {
361 case UDCK_Ctor:
362 return UDConvCtor.Fun->getParamDecl(0)->getSourceRange();
363 case UDCK_Oper:
364 // getReturnTypeSourceRange() does not work for CXXConversionDecls as the
365 // returned type is physically behind the declaration's name ("operator").
366 if (const FunctionTypeLoc FTL = UDConvOp.Fun->getFunctionTypeLoc())
367 if (const TypeLoc RetLoc = FTL.getReturnLoc())
368 return RetLoc.getSourceRange();
369 return {};
370 case UDCK_None:
371 return {};
372 }
373 llvm_unreachable("Invalid UDConv kind.")::llvm::llvm_unreachable_internal("Invalid UDConv kind.", "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 373)
;
374 }
375};
376
377/// Contains the metadata for the mixability result between two types,
378/// independently of which parameters they were calculated from.
379struct MixData {
380 /// The flag bits of the mix indicating what language features allow for it.
381 MixFlags Flags = MixFlags::Invalid;
382
383 /// A potentially calculated common underlying type after desugaring, that
384 /// both sides of the mix can originate from.
385 QualType CommonType;
386
387 /// The steps an implicit conversion performs to get from one type to the
388 /// other.
389 ConversionSequence Conversion, ConversionRTL;
390
391 /// True if the MixData was specifically created with only a one-way
392 /// conversion modelled.
393 bool CreatedFromOneWayConversion = false;
394
395 MixData(MixFlags Flags) : Flags(Flags) {}
396 MixData(MixFlags Flags, QualType CommonType)
397 : Flags(Flags), CommonType(CommonType) {}
398 MixData(MixFlags Flags, ConversionSequence Conv)
399 : Flags(Flags), Conversion(Conv), CreatedFromOneWayConversion(true) {}
400 MixData(MixFlags Flags, ConversionSequence LTR, ConversionSequence RTL)
401 : Flags(Flags), Conversion(LTR), ConversionRTL(RTL) {}
402 MixData(MixFlags Flags, QualType CommonType, ConversionSequence LTR,
403 ConversionSequence RTL)
404 : Flags(Flags), CommonType(CommonType), Conversion(LTR),
405 ConversionRTL(RTL) {}
406
407 void sanitize() {
408 assert(Flags != MixFlags::Invalid && "sanitize() called on invalid bitvec")(static_cast <bool> (Flags != MixFlags::Invalid &&
"sanitize() called on invalid bitvec") ? void (0) : __assert_fail
("Flags != MixFlags::Invalid && \"sanitize() called on invalid bitvec\""
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 408, __extension__ __PRETTY_FUNCTION__))
;
409
410 MixFlags CanonicalAndWorkaround =
411 MixFlags::Canonical | MixFlags::WorkaroundDisableCanonicalEquivalence;
412 if ((Flags & CanonicalAndWorkaround) == CanonicalAndWorkaround) {
413 // A workaround for too eagerly equivalent canonical types was requested,
414 // and a canonical equivalence was proven. Fulfill the request and throw
415 // this result away.
416 Flags = MixFlags::None;
417 return;
418 }
419
420 if (hasFlag(Flags, MixFlags::None)) {
421 // If anywhere down the recursion a potential mix "path" is deemed
422 // impossible, throw away all the other bits because the mix is not
423 // possible.
424 Flags = MixFlags::None;
425 return;
426 }
427
428 if (Flags == MixFlags::Trivial)
429 return;
430
431 if (static_cast<bool>(Flags ^ MixFlags::Trivial))
432 // If the mix involves somewhere trivial equivalence but down the
433 // recursion other bit(s) were set, remove the trivial bit, as it is not
434 // trivial.
435 Flags &= ~MixFlags::Trivial;
436
437 bool ShouldHaveImplicitConvFlag = false;
438 if (CreatedFromOneWayConversion && Conversion)
439 ShouldHaveImplicitConvFlag = true;
440 else if (!CreatedFromOneWayConversion && Conversion && ConversionRTL)
441 // Only say that we have implicit conversion mix possibility if it is
442 // bidirectional. Otherwise, the compiler would report an *actual* swap
443 // at a call site...
444 ShouldHaveImplicitConvFlag = true;
445
446 if (ShouldHaveImplicitConvFlag)
447 Flags |= MixFlags::ImplicitConversion;
448 else
449 Flags &= ~MixFlags::ImplicitConversion;
450 }
451
452 bool isValid() const { return Flags >= MixFlags::None; }
453
454 bool indicatesMixability() const { return Flags > MixFlags::None; }
455
456 /// Add the specified flag bits to the flags.
457 MixData operator|(MixFlags EnableFlags) const {
458 if (CreatedFromOneWayConversion) {
459 MixData M{Flags | EnableFlags, Conversion};
460 M.CommonType = CommonType;
461 return M;
462 }
463 return {Flags | EnableFlags, CommonType, Conversion, ConversionRTL};
464 }
465
466 /// Add the specified flag bits to the flags.
467 MixData &operator|=(MixFlags EnableFlags) {
468 Flags |= EnableFlags;
469 return *this;
470 }
471
472 template <class F> MixData withCommonTypeTransformed(F &&Func) const {
473 if (CommonType.isNull())
474 return *this;
475
476 QualType NewCommonType = Func(CommonType);
477
478 if (CreatedFromOneWayConversion) {
479 MixData M{Flags, Conversion};
480 M.CommonType = NewCommonType;
481 return M;
482 }
483
484 return {Flags, NewCommonType, Conversion, ConversionRTL};
485 }
486};
487
488/// A named tuple that contains the information for a mix between two concrete
489/// parameters.
490struct Mix {
491 const ParmVarDecl *First, *Second;
492 MixData Data;
493
494 Mix(const ParmVarDecl *F, const ParmVarDecl *S, MixData Data)
495 : First(F), Second(S), Data(std::move(Data)) {}
496
497 void sanitize() { Data.sanitize(); }
498 MixFlags flags() const { return Data.Flags; }
499 bool flagsValid() const { return Data.isValid(); }
500 bool mixable() const { return Data.indicatesMixability(); }
501 QualType commonUnderlyingType() const { return Data.CommonType; }
502 const ConversionSequence &leftToRightConversionSequence() const {
503 return Data.Conversion;
504 }
505 const ConversionSequence &rightToLeftConversionSequence() const {
506 return Data.ConversionRTL;
507 }
508};
509
510// NOLINTNEXTLINE(misc-redundant-expression): Seems to be a bogus warning.
511static_assert(std::is_trivially_copyable<Mix>::value &&
512 std::is_trivially_move_constructible<Mix>::value &&
513 std::is_trivially_move_assignable<Mix>::value,
514 "Keep frequently used data simple!");
515
516struct MixableParameterRange {
517 /// A container for Mixes.
518 using MixVector = SmallVector<Mix, 8>;
519
520 /// The number of parameters iterated to build the instance.
521 std::size_t NumParamsChecked = 0;
522
523 /// The individual flags and supporting information for the mixes.
524 MixVector Mixes;
525
526 /// Gets the leftmost parameter of the range.
527 const ParmVarDecl *getFirstParam() const {
528 // The first element is the LHS of the very first mix in the range.
529 assert(!Mixes.empty())(static_cast <bool> (!Mixes.empty()) ? void (0) : __assert_fail
("!Mixes.empty()", "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 529, __extension__ __PRETTY_FUNCTION__))
;
530 return Mixes.front().First;
531 }
532
533 /// Gets the rightmost parameter of the range.
534 const ParmVarDecl *getLastParam() const {
535 // The builder function breaks building an instance of this type if it
536 // finds something that can not be mixed with the rest, by going *forward*
537 // in the list of parameters. So at any moment of break, the RHS of the last
538 // element of the mix vector is also the last element of the mixing range.
539 assert(!Mixes.empty())(static_cast <bool> (!Mixes.empty()) ? void (0) : __assert_fail
("!Mixes.empty()", "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 539, __extension__ __PRETTY_FUNCTION__))
;
540 return Mixes.back().Second;
541 }
542};
543
544/// Helper enum for the recursive calls in the modelling that toggle what kinds
545/// of implicit conversions are to be modelled.
546enum class ImplicitConversionModellingMode : unsigned char {
547 ///< No implicit conversions are modelled.
548 None,
549
550 ///< The full implicit conversion sequence is modelled.
551 All,
552
553 ///< Only model a unidirectional implicit conversion and within it only one
554 /// standard conversion sequence.
555 OneWaySingleStandardOnly
556};
557
558static MixData
559isLRefEquallyBindingToType(const TheCheck &Check,
560 const LValueReferenceType *LRef, QualType Ty,
561 const ASTContext &Ctx, bool IsRefRHS,
562 ImplicitConversionModellingMode ImplicitMode);
563
564static MixData
565approximateImplicitConversion(const TheCheck &Check, QualType LType,
566 QualType RType, const ASTContext &Ctx,
567 ImplicitConversionModellingMode ImplicitMode);
568
569static inline bool isUselessSugar(const Type *T) {
570 return isa<AttributedType, DecayedType, ElaboratedType, ParenType>(T);
571}
572
573namespace {
574
575struct NonCVRQualifiersResult {
576 /// True if the types are qualified in a way that even after equating or
577 /// removing local CVR qualification, even if the unqualified types
578 /// themselves would mix, the qualified ones don't, because there are some
579 /// other local qualifiers that are not equal.
580 bool HasMixabilityBreakingQualifiers;
581
582 /// The set of equal qualifiers between the two types.
583 Qualifiers CommonQualifiers;
584};
585
586} // namespace
587
588/// Returns if the two types are qualified in a way that ever after equating or
589/// removing local CVR qualification, even if the unqualified types would mix,
590/// the qualified ones don't, because there are some other local qualifiers
591/// that aren't equal.
592static NonCVRQualifiersResult
593getNonCVRQualifiers(const ASTContext &Ctx, QualType LType, QualType RType) {
594 LLVM_DEBUG(llvm::dbgs() << ">>> getNonCVRQualifiers for LType:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> getNonCVRQualifiers for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';;
} } while (false)
595 LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> getNonCVRQualifiers for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';;
} } while (false)
596 RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> getNonCVRQualifiers for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';;
} } while (false)
;
597 Qualifiers LQual = LType.getLocalQualifiers(),
598 RQual = RType.getLocalQualifiers();
599
600 // Strip potential CVR. That is handled by the check option QualifiersMix.
601 LQual.removeCVRQualifiers();
602 RQual.removeCVRQualifiers();
603
604 NonCVRQualifiersResult Ret;
605 Ret.CommonQualifiers = Qualifiers::removeCommonQualifiers(LQual, RQual);
606
607 LLVM_DEBUG(llvm::dbgs() << "--- hasNonCVRMixabilityBreakingQualifiers. "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- hasNonCVRMixabilityBreakingQualifiers. "
"Removed common qualifiers: "; Ret.CommonQualifiers.print(llvm
::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() << "\n\tremaining on LType: "
; LQual.print(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs
() << "\n\tremaining on RType: "; RQual.print(llvm::dbgs
(), Ctx.getPrintingPolicy()); llvm::dbgs() << '\n';; } }
while (false)
608 "Removed common qualifiers: ";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- hasNonCVRMixabilityBreakingQualifiers. "
"Removed common qualifiers: "; Ret.CommonQualifiers.print(llvm
::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() << "\n\tremaining on LType: "
; LQual.print(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs
() << "\n\tremaining on RType: "; RQual.print(llvm::dbgs
(), Ctx.getPrintingPolicy()); llvm::dbgs() << '\n';; } }
while (false)
609 Ret.CommonQualifiers.print(llvm::dbgs(), Ctx.getPrintingPolicy());do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- hasNonCVRMixabilityBreakingQualifiers. "
"Removed common qualifiers: "; Ret.CommonQualifiers.print(llvm
::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() << "\n\tremaining on LType: "
; LQual.print(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs
() << "\n\tremaining on RType: "; RQual.print(llvm::dbgs
(), Ctx.getPrintingPolicy()); llvm::dbgs() << '\n';; } }
while (false)
610 llvm::dbgs() << "\n\tremaining on LType: ";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- hasNonCVRMixabilityBreakingQualifiers. "
"Removed common qualifiers: "; Ret.CommonQualifiers.print(llvm
::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() << "\n\tremaining on LType: "
; LQual.print(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs
() << "\n\tremaining on RType: "; RQual.print(llvm::dbgs
(), Ctx.getPrintingPolicy()); llvm::dbgs() << '\n';; } }
while (false)
611 LQual.print(llvm::dbgs(), Ctx.getPrintingPolicy());do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- hasNonCVRMixabilityBreakingQualifiers. "
"Removed common qualifiers: "; Ret.CommonQualifiers.print(llvm
::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() << "\n\tremaining on LType: "
; LQual.print(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs
() << "\n\tremaining on RType: "; RQual.print(llvm::dbgs
(), Ctx.getPrintingPolicy()); llvm::dbgs() << '\n';; } }
while (false)
612 llvm::dbgs() << "\n\tremaining on RType: ";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- hasNonCVRMixabilityBreakingQualifiers. "
"Removed common qualifiers: "; Ret.CommonQualifiers.print(llvm
::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() << "\n\tremaining on LType: "
; LQual.print(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs
() << "\n\tremaining on RType: "; RQual.print(llvm::dbgs
(), Ctx.getPrintingPolicy()); llvm::dbgs() << '\n';; } }
while (false)
613 RQual.print(llvm::dbgs(), Ctx.getPrintingPolicy());do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- hasNonCVRMixabilityBreakingQualifiers. "
"Removed common qualifiers: "; Ret.CommonQualifiers.print(llvm
::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() << "\n\tremaining on LType: "
; LQual.print(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs
() << "\n\tremaining on RType: "; RQual.print(llvm::dbgs
(), Ctx.getPrintingPolicy()); llvm::dbgs() << '\n';; } }
while (false)
614 llvm::dbgs() << '\n';)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- hasNonCVRMixabilityBreakingQualifiers. "
"Removed common qualifiers: "; Ret.CommonQualifiers.print(llvm
::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() << "\n\tremaining on LType: "
; LQual.print(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs
() << "\n\tremaining on RType: "; RQual.print(llvm::dbgs
(), Ctx.getPrintingPolicy()); llvm::dbgs() << '\n';; } }
while (false)
;
615
616 // If there are no other non-cvr non-common qualifiers left, we can deduce
617 // that mixability isn't broken.
618 Ret.HasMixabilityBreakingQualifiers =
619 LQual.hasQualifiers() || RQual.hasQualifiers();
620
621 return Ret;
622}
623
624/// Approximate the way how LType and RType might refer to "essentially the
625/// same" type, in a sense that at a particular call site, an expression of
626/// type LType and RType might be successfully passed to a variable (in our
627/// specific case, a parameter) of type RType and LType, respectively.
628/// Note the swapped order!
629///
630/// The returned data structure is not guaranteed to be properly set, as this
631/// function is potentially recursive. It is the caller's responsibility to
632/// call sanitize() on the result once the recursion is over.
633static MixData
634calculateMixability(const TheCheck &Check, QualType LType, QualType RType,
635 const ASTContext &Ctx,
636 ImplicitConversionModellingMode ImplicitMode) {
637 LLVM_DEBUG(llvm::dbgs() << ">>> calculateMixability for LType:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> calculateMixability for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';;
} } while (false)
638 LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> calculateMixability for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';;
} } while (false)
639 RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> calculateMixability for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';;
} } while (false)
;
640 if (LType == RType) {
641 LLVM_DEBUG(llvm::dbgs() << "<<< calculateMixability. Trivial equality.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. Trivial equality.\n"
; } } while (false)
;
642 return {MixFlags::Trivial, LType};
643 }
644
645 // Dissolve certain type sugars that do not affect the mixability of one type
646 // with the other, and also do not require any sort of elaboration for the
647 // user to understand.
648 if (isUselessSugar(LType.getTypePtr())) {
649 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. LHS is useless sugar.\n"
; } } while (false)
650 << "--- calculateMixability. LHS is useless sugar.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. LHS is useless sugar.\n"
; } } while (false)
;
651 return calculateMixability(Check, LType.getSingleStepDesugaredType(Ctx),
652 RType, Ctx, ImplicitMode);
653 }
654 if (isUselessSugar(RType.getTypePtr())) {
655 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. RHS is useless sugar.\n"
; } } while (false)
656 << "--- calculateMixability. RHS is useless sugar.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. RHS is useless sugar.\n"
; } } while (false)
;
657 return calculateMixability(
658 Check, LType, RType.getSingleStepDesugaredType(Ctx), Ctx, ImplicitMode);
659 }
660
661 const auto *LLRef = LType->getAs<LValueReferenceType>();
662 const auto *RLRef = RType->getAs<LValueReferenceType>();
663 if (LLRef && RLRef) {
664 LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. LHS and RHS are &.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. LHS and RHS are &.\n"
; } } while (false)
;
665
666 return calculateMixability(Check, LLRef->getPointeeType(),
667 RLRef->getPointeeType(), Ctx, ImplicitMode)
668 .withCommonTypeTransformed(
669 [&Ctx](QualType QT) { return Ctx.getLValueReferenceType(QT); });
670 }
671 // At a particular call site, what could be passed to a 'T' or 'const T' might
672 // also be passed to a 'const T &' without the call site putting a direct
673 // side effect on the passed expressions.
674 if (LLRef) {
675 LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. LHS is &.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. LHS is &.\n"
; } } while (false)
;
676 return isLRefEquallyBindingToType(Check, LLRef, RType, Ctx, false,
677 ImplicitMode) |
678 MixFlags::ReferenceBind;
679 }
680 if (RLRef) {
681 LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. RHS is &.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. RHS is &.\n"
; } } while (false)
;
682 return isLRefEquallyBindingToType(Check, RLRef, LType, Ctx, true,
683 ImplicitMode) |
684 MixFlags::ReferenceBind;
685 }
686
687 if (LType->getAs<TypedefType>()) {
688 LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. LHS is typedef.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. LHS is typedef.\n"
; } } while (false)
;
689 return calculateMixability(Check, LType.getSingleStepDesugaredType(Ctx),
690 RType, Ctx, ImplicitMode) |
691 MixFlags::TypeAlias;
692 }
693 if (RType->getAs<TypedefType>()) {
694 LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. RHS is typedef.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. RHS is typedef.\n"
; } } while (false)
;
695 return calculateMixability(Check, LType,
696 RType.getSingleStepDesugaredType(Ctx), Ctx,
697 ImplicitMode) |
698 MixFlags::TypeAlias;
699 }
700
701 // A parameter of type 'cvr1 T' and another of potentially differently
702 // qualified 'cvr2 T' may bind with the same power, if the user so requested.
703 //
704 // Whether to do this check for the inner unqualified types.
705 bool CompareUnqualifiedTypes = false;
706 if (LType.getLocalCVRQualifiers() != RType.getLocalCVRQualifiers()) {
707 LLVM_DEBUG(if (LType.getLocalCVRQualifiers()) {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (LType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. LHS has CVR-Qualifiers: "
; Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
708 llvm::dbgs() << "--- calculateMixability. LHS has CVR-Qualifiers: ";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (LType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. LHS has CVR-Qualifiers: "
; Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
709 Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers())do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (LType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. LHS has CVR-Qualifiers: "
; Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
710 .print(llvm::dbgs(), Ctx.getPrintingPolicy());do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (LType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. LHS has CVR-Qualifiers: "
; Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
711 llvm::dbgs() << '\n';do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (LType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. LHS has CVR-Qualifiers: "
; Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
712 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (LType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. LHS has CVR-Qualifiers: "
; Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
;
713 LLVM_DEBUG(if (RType.getLocalCVRQualifiers()) {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (RType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. RHS has CVR-Qualifiers: "
; Qualifiers::fromCVRMask(RType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
714 llvm::dbgs() << "--- calculateMixability. RHS has CVR-Qualifiers: ";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (RType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. RHS has CVR-Qualifiers: "
; Qualifiers::fromCVRMask(RType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
715 Qualifiers::fromCVRMask(RType.getLocalCVRQualifiers())do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (RType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. RHS has CVR-Qualifiers: "
; Qualifiers::fromCVRMask(RType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
716 .print(llvm::dbgs(), Ctx.getPrintingPolicy());do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (RType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. RHS has CVR-Qualifiers: "
; Qualifiers::fromCVRMask(RType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
717 llvm::dbgs() << '\n';do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (RType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. RHS has CVR-Qualifiers: "
; Qualifiers::fromCVRMask(RType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
718 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (RType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. RHS has CVR-Qualifiers: "
; Qualifiers::fromCVRMask(RType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
;
719
720 if (!Check.QualifiersMix) {
721 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. QualifiersMix turned off - not "
"mixable.\n"; } } while (false)
722 << "<<< calculateMixability. QualifiersMix turned off - not "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. QualifiersMix turned off - not "
"mixable.\n"; } } while (false)
723 "mixable.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. QualifiersMix turned off - not "
"mixable.\n"; } } while (false)
;
724 return {MixFlags::None};
725 }
726
727 CompareUnqualifiedTypes = true;
728 }
729 // Whether the two types had the same CVR qualifiers.
730 bool OriginallySameQualifiers = false;
731 if (LType.getLocalCVRQualifiers() == RType.getLocalCVRQualifiers() &&
732 LType.getLocalCVRQualifiers() != 0) {
733 LLVM_DEBUG(if (LType.getLocalCVRQualifiers()) {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (LType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. LHS and RHS have same CVR-Qualifiers: "
; Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
734 llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (LType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. LHS and RHS have same CVR-Qualifiers: "
; Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
735 << "--- calculateMixability. LHS and RHS have same CVR-Qualifiers: ";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (LType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. LHS and RHS have same CVR-Qualifiers: "
; Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
736 Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers())do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (LType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. LHS and RHS have same CVR-Qualifiers: "
; Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
737 .print(llvm::dbgs(), Ctx.getPrintingPolicy());do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (LType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. LHS and RHS have same CVR-Qualifiers: "
; Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
738 llvm::dbgs() << '\n';do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (LType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. LHS and RHS have same CVR-Qualifiers: "
; Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
739 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (LType.getLocalCVRQualifiers
()) { llvm::dbgs() << "--- calculateMixability. LHS and RHS have same CVR-Qualifiers: "
; Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) .print
(llvm::dbgs(), Ctx.getPrintingPolicy()); llvm::dbgs() <<
'\n'; }; } } while (false)
;
740
741 CompareUnqualifiedTypes = true;
742 OriginallySameQualifiers = true;
743 }
744
745 if (CompareUnqualifiedTypes) {
746 NonCVRQualifiersResult AdditionalQuals =
747 getNonCVRQualifiers(Ctx, LType, RType);
748 if (AdditionalQuals.HasMixabilityBreakingQualifiers) {
749 LLVM_DEBUG(llvm::dbgs() << "<<< calculateMixability. Additional "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. Additional "
"non-equal incompatible qualifiers.\n"; } } while (false)
750 "non-equal incompatible qualifiers.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. Additional "
"non-equal incompatible qualifiers.\n"; } } while (false)
;
751 return {MixFlags::None};
752 }
753
754 MixData UnqualifiedMixability =
755 calculateMixability(Check, LType.getLocalUnqualifiedType(),
756 RType.getLocalUnqualifiedType(), Ctx, ImplicitMode)
757 .withCommonTypeTransformed([&AdditionalQuals, &Ctx](QualType QT) {
758 // Once the mixability was deduced, apply the qualifiers common
759 // to the two type back onto the diagnostic printout.
760 return Ctx.getQualifiedType(QT, AdditionalQuals.CommonQualifiers);
761 });
762
763 if (!OriginallySameQualifiers)
764 // User-enabled qualifier change modelled for the mix.
765 return UnqualifiedMixability | MixFlags::Qualifiers;
766
767 // Apply the same qualifier back into the found common type if they were
768 // the same.
769 return UnqualifiedMixability.withCommonTypeTransformed(
770 [&Ctx, LType](QualType QT) {
771 return Ctx.getQualifiedType(QT, LType.getLocalQualifiers());
772 });
773 }
774
775 // Certain constructs match on the last catch-all getCanonicalType() equality,
776 // which is perhaps something not what we want. If this variable is true,
777 // the canonical type equality will be ignored.
778 bool RecursiveReturnDiscardingCanonicalType = false;
779
780 if (LType->isPointerType() && RType->isPointerType()) {
781 // If both types are pointers, and pointed to the exact same type,
782 // LType == RType took care of that. Try to see if the pointee type has
783 // some other match. However, this must not consider implicit conversions.
784 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. LHS and RHS are Ptrs.\n"
; } } while (false)
785 << "--- calculateMixability. LHS and RHS are Ptrs.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. LHS and RHS are Ptrs.\n"
; } } while (false)
;
786 MixData MixOfPointee =
787 calculateMixability(Check, LType->getPointeeType(),
788 RType->getPointeeType(), Ctx,
789 ImplicitConversionModellingMode::None)
790 .withCommonTypeTransformed(
791 [&Ctx](QualType QT) { return Ctx.getPointerType(QT); });
792 if (hasFlag(MixOfPointee.Flags,
793 MixFlags::WorkaroundDisableCanonicalEquivalence))
794 RecursiveReturnDiscardingCanonicalType = true;
795
796 MixOfPointee.sanitize();
797 if (MixOfPointee.indicatesMixability()) {
798 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. Pointees are mixable.\n"
; } } while (false)
799 << "<<< calculateMixability. Pointees are mixable.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. Pointees are mixable.\n"
; } } while (false)
;
800 return MixOfPointee;
801 }
802 }
803
804 if (ImplicitMode > ImplicitConversionModellingMode::None) {
805 LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. Start implicit...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. Start implicit...\n"
; } } while (false)
;
806 MixData MixLTR =
807 approximateImplicitConversion(Check, LType, RType, Ctx, ImplicitMode);
808 LLVM_DEBUG(do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (hasFlag(MixLTR.Flags
, MixFlags::ImplicitConversion)) llvm::dbgs() << "--- calculateMixability. Implicit Left -> Right found.\n"
;; } } while (false)
809 if (hasFlag(MixLTR.Flags, MixFlags::ImplicitConversion)) llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (hasFlag(MixLTR.Flags
, MixFlags::ImplicitConversion)) llvm::dbgs() << "--- calculateMixability. Implicit Left -> Right found.\n"
;; } } while (false)
810 << "--- calculateMixability. Implicit Left -> Right found.\n";)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (hasFlag(MixLTR.Flags
, MixFlags::ImplicitConversion)) llvm::dbgs() << "--- calculateMixability. Implicit Left -> Right found.\n"
;; } } while (false)
;
811
812 if (ImplicitMode ==
813 ImplicitConversionModellingMode::OneWaySingleStandardOnly &&
814 MixLTR.Conversion && !MixLTR.Conversion.AfterFirstStandard.isNull() &&
815 MixLTR.Conversion.UDConvKind == ConversionSequence::UDCK_None &&
816 MixLTR.Conversion.AfterSecondStandard.isNull()) {
817 // The invoker of the method requested only modelling a single standard
818 // conversion, in only the forward direction, and they got just that.
819 LLVM_DEBUG(llvm::dbgs() << "<<< calculateMixability. Implicit "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. Implicit "
"conversion, one-way, standard-only.\n"; } } while (false)
820 "conversion, one-way, standard-only.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. Implicit "
"conversion, one-way, standard-only.\n"; } } while (false)
;
821 return {MixFlags::ImplicitConversion, MixLTR.Conversion};
822 }
823
824 // Otherwise if the invoker requested a full modelling, do the other
825 // direction as well.
826 MixData MixRTL =
827 approximateImplicitConversion(Check, RType, LType, Ctx, ImplicitMode);
828 LLVM_DEBUG(do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (hasFlag(MixRTL.Flags
, MixFlags::ImplicitConversion)) llvm::dbgs() << "--- calculateMixability. Implicit Right -> Left found.\n"
;; } } while (false)
829 if (hasFlag(MixRTL.Flags, MixFlags::ImplicitConversion)) llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (hasFlag(MixRTL.Flags
, MixFlags::ImplicitConversion)) llvm::dbgs() << "--- calculateMixability. Implicit Right -> Left found.\n"
;; } } while (false)
830 << "--- calculateMixability. Implicit Right -> Left found.\n";)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (hasFlag(MixRTL.Flags
, MixFlags::ImplicitConversion)) llvm::dbgs() << "--- calculateMixability. Implicit Right -> Left found.\n"
;; } } while (false)
;
831
832 if (MixLTR.Conversion && MixRTL.Conversion) {
833 LLVM_DEBUG(do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. Implicit conversion, bidirectional.\n"
; } } while (false)
834 llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. Implicit conversion, bidirectional.\n"
; } } while (false)
835 << "<<< calculateMixability. Implicit conversion, bidirectional.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. Implicit conversion, bidirectional.\n"
; } } while (false)
;
836 return {MixFlags::ImplicitConversion, MixLTR.Conversion,
837 MixRTL.Conversion};
838 }
839 }
840
841 if (RecursiveReturnDiscardingCanonicalType)
842 LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. Before CanonicalType, "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. Before CanonicalType, "
"Discard was enabled.\n"; } } while (false)
843 "Discard was enabled.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. Before CanonicalType, "
"Discard was enabled.\n"; } } while (false)
;
844
845 // Certain kinds unfortunately need to be side-stepped for canonical type
846 // matching.
847 if (LType->getAs<FunctionProtoType>() || RType->getAs<FunctionProtoType>()) {
848 // Unfortunately, the canonical type of a function pointer becomes the
849 // same even if exactly one is "noexcept" and the other isn't, making us
850 // give a false positive report irrespective of implicit conversions.
851 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. Discarding potential canonical "
"equivalence on FunctionProtoTypes.\n"; } } while (false)
852 << "--- calculateMixability. Discarding potential canonical "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. Discarding potential canonical "
"equivalence on FunctionProtoTypes.\n"; } } while (false)
853 "equivalence on FunctionProtoTypes.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- calculateMixability. Discarding potential canonical "
"equivalence on FunctionProtoTypes.\n"; } } while (false)
;
854 RecursiveReturnDiscardingCanonicalType = true;
855 }
856
857 MixData MixToReturn{MixFlags::None};
858
859 // If none of the previous logic found a match, try if Clang otherwise
860 // believes the types to be the same.
861 QualType LCanonical = LType.getCanonicalType();
862 if (LCanonical == RType.getCanonicalType()) {
863 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. Same CanonicalType.\n"
; } } while (false)
864 << "<<< calculateMixability. Same CanonicalType.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< calculateMixability. Same CanonicalType.\n"
; } } while (false)
;
865 MixToReturn = {MixFlags::Canonical, LCanonical};
866 }
867
868 if (RecursiveReturnDiscardingCanonicalType)
869 MixToReturn |= MixFlags::WorkaroundDisableCanonicalEquivalence;
870
871 LLVM_DEBUG(if (MixToReturn.Flags == MixFlags::None) llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (MixToReturn.Flags ==
MixFlags::None) llvm::dbgs() << "<<< calculateMixability. No match found.\n"
; } } while (false)
872 << "<<< calculateMixability. No match found.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { if (MixToReturn.Flags ==
MixFlags::None) llvm::dbgs() << "<<< calculateMixability. No match found.\n"
; } } while (false)
;
873 return MixToReturn;
874}
875
876/// Calculates if the reference binds an expression of the given type. This is
877/// true iff 'LRef' is some 'const T &' type, and the 'Ty' is 'T' or 'const T'.
878///
879/// \param ImplicitMode is forwarded in the possible recursive call to
880/// calculateMixability.
881static MixData
882isLRefEquallyBindingToType(const TheCheck &Check,
883 const LValueReferenceType *LRef, QualType Ty,
884 const ASTContext &Ctx, bool IsRefRHS,
885 ImplicitConversionModellingMode ImplicitMode) {
886 LLVM_DEBUG(llvm::dbgs() << ">>> isLRefEquallyBindingToType for LRef:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> isLRefEquallyBindingToType for LRef:\n"
; LRef->dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand Type:\n"
; Ty.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';; } }
while (false)
887 LRef->dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand Type:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> isLRefEquallyBindingToType for LRef:\n"
; LRef->dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand Type:\n"
; Ty.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';; } }
while (false)
888 Ty.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> isLRefEquallyBindingToType for LRef:\n"
; LRef->dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand Type:\n"
; Ty.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';; } }
while (false)
;
889
890 QualType ReferredType = LRef->getPointeeType();
891 if (!ReferredType.isLocalConstQualified() &&
892 ReferredType->getAs<TypedefType>()) {
893 LLVM_DEBUG(do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- isLRefEquallyBindingToType. Non-const LRef to Typedef.\n"
; } } while (false)
894 llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- isLRefEquallyBindingToType. Non-const LRef to Typedef.\n"
; } } while (false)
895 << "--- isLRefEquallyBindingToType. Non-const LRef to Typedef.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- isLRefEquallyBindingToType. Non-const LRef to Typedef.\n"
; } } while (false)
;
896 ReferredType = ReferredType.getDesugaredType(Ctx);
897 if (!ReferredType.isLocalConstQualified()) {
898 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< isLRefEquallyBindingToType. Typedef is not const.\n"
; } } while (false)
899 << "<<< isLRefEquallyBindingToType. Typedef is not const.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< isLRefEquallyBindingToType. Typedef is not const.\n"
; } } while (false)
;
900 return {MixFlags::None};
901 }
902
903 LLVM_DEBUG(llvm::dbgs() << "--- isLRefEquallyBindingToType. Typedef is "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- isLRefEquallyBindingToType. Typedef is "
"const, considering as const LRef.\n"; } } while (false)
904 "const, considering as const LRef.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- isLRefEquallyBindingToType. Typedef is "
"const, considering as const LRef.\n"; } } while (false)
;
905 } else if (!ReferredType.isLocalConstQualified()) {
906 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< isLRefEquallyBindingToType. Not const LRef.\n"
; } } while (false)
907 << "<<< isLRefEquallyBindingToType. Not const LRef.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< isLRefEquallyBindingToType. Not const LRef.\n"
; } } while (false)
;
908 return {MixFlags::None};
909 };
910
911 assert(ReferredType.isLocalConstQualified() &&(static_cast <bool> (ReferredType.isLocalConstQualified
() && "Reaching this point means we are sure LRef is effectively a const&."
) ? void (0) : __assert_fail ("ReferredType.isLocalConstQualified() && \"Reaching this point means we are sure LRef is effectively a const&.\""
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 912, __extension__ __PRETTY_FUNCTION__))
912 "Reaching this point means we are sure LRef is effectively a const&.")(static_cast <bool> (ReferredType.isLocalConstQualified
() && "Reaching this point means we are sure LRef is effectively a const&."
) ? void (0) : __assert_fail ("ReferredType.isLocalConstQualified() && \"Reaching this point means we are sure LRef is effectively a const&.\""
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 912, __extension__ __PRETTY_FUNCTION__))
;
913
914 if (ReferredType == Ty) {
915 LLVM_DEBUG(do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< isLRefEquallyBindingToType. Type of referred matches.\n"
; } } while (false)
916 llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< isLRefEquallyBindingToType. Type of referred matches.\n"
; } } while (false)
917 << "<<< isLRefEquallyBindingToType. Type of referred matches.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< isLRefEquallyBindingToType. Type of referred matches.\n"
; } } while (false)
;
918 return {MixFlags::Trivial, ReferredType};
919 }
920
921 QualType NonConstReferredType = ReferredType;
922 NonConstReferredType.removeLocalConst();
923 if (NonConstReferredType == Ty) {
924 LLVM_DEBUG(llvm::dbgs() << "<<< isLRefEquallyBindingToType. Type of "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< isLRefEquallyBindingToType. Type of "
"referred matches to non-const qualified.\n"; } } while (false
)
925 "referred matches to non-const qualified.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< isLRefEquallyBindingToType. Type of "
"referred matches to non-const qualified.\n"; } } while (false
)
;
926 return {MixFlags::Trivial, NonConstReferredType};
927 }
928
929 LLVM_DEBUG(do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- isLRefEquallyBindingToType. Checking mix for underlying type.\n"
; } } while (false)
930 llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- isLRefEquallyBindingToType. Checking mix for underlying type.\n"
; } } while (false)
931 << "--- isLRefEquallyBindingToType. Checking mix for underlying type.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- isLRefEquallyBindingToType. Checking mix for underlying type.\n"
; } } while (false)
;
932 return IsRefRHS ? calculateMixability(Check, Ty, NonConstReferredType, Ctx,
933 ImplicitMode)
934 : calculateMixability(Check, NonConstReferredType, Ty, Ctx,
935 ImplicitMode);
936}
937
938static inline bool isDerivedToBase(const CXXRecordDecl *Derived,
939 const CXXRecordDecl *Base) {
940 return Derived && Base && Derived->isCompleteDefinition() &&
941 Base->isCompleteDefinition() && Derived->isDerivedFrom(Base);
942}
943
944static Optional<QualType>
945approximateStandardConversionSequence(const TheCheck &Check, QualType From,
946 QualType To, const ASTContext &Ctx) {
947 LLVM_DEBUG(llvm::dbgs() << ">>> approximateStdConv for LType:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateStdConv for LType:\n"
; From.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; To.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';; } }
while (false)
948 From.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateStdConv for LType:\n"
; From.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; To.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';; } }
while (false)
949 To.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateStdConv for LType:\n"
; From.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; To.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';; } }
while (false)
;
950
951 // A standard conversion sequence consists of the following, in order:
952 // * Maybe either LValue->RValue conv., Array->Ptr conv., Function->Ptr conv.
953 // * Maybe Numeric promotion or conversion.
954 // * Maybe function pointer conversion.
955 // * Maybe qualifier adjustments.
956 QualType WorkType = From;
957 // Get out the qualifiers of the original type. This will always be
958 // re-applied to the WorkType to ensure it is the same qualification as the
959 // original From was.
960 auto QualifiersToApply = From.split().Quals.getAsOpaqueValue();
961
962 // LValue->RValue is irrelevant for the check, because it is a thing to be
963 // done at a call site, and will be performed if need be performed.
964
965 // Array->Pointer decay is handled by the main method in desugaring
966 // the parameter's DecayedType as "useless sugar".
967
968 // Function->Pointer conversions are also irrelevant, because a
969 // "FunctionType" cannot be the type of a parameter variable, so this
970 // conversion is only meaningful at call sites.
971
972 // Numeric promotions and conversions.
973 const auto *FromBuiltin = WorkType->getAs<BuiltinType>();
974 const auto *ToBuiltin = To->getAs<BuiltinType>();
975 bool FromNumeric = FromBuiltin && (FromBuiltin->isIntegerType() ||
976 FromBuiltin->isFloatingType());
977 bool ToNumeric =
978 ToBuiltin && (ToBuiltin->isIntegerType() || ToBuiltin->isFloatingType());
979 if (FromNumeric && ToNumeric) {
980 // If both are integral types, the numeric conversion is performed.
981 // Reapply the qualifiers of the original type, however, so
982 // "const int -> double" in this case moves over to
983 // "const double -> double".
984 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateStdConv. Conversion between numerics.\n"
; } } while (false)
985 << "--- approximateStdConv. Conversion between numerics.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateStdConv. Conversion between numerics.\n"
; } } while (false)
;
986 WorkType = QualType{ToBuiltin, QualifiersToApply};
987 }
988
989 const auto *FromEnum = WorkType->getAs<EnumType>();
990 const auto *ToEnum = To->getAs<EnumType>();
991 if (FromEnum && ToNumeric && FromEnum->isUnscopedEnumerationType()) {
992 // Unscoped enumerations (or enumerations in C) convert to numerics.
993 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateStdConv. Unscoped enum to numeric.\n"
; } } while (false)
994 << "--- approximateStdConv. Unscoped enum to numeric.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateStdConv. Unscoped enum to numeric.\n"
; } } while (false)
;
995 WorkType = QualType{ToBuiltin, QualifiersToApply};
996 } else if (FromNumeric && ToEnum && ToEnum->isUnscopedEnumerationType()) {
997 // Numeric types convert to enumerations only in C.
998 if (Ctx.getLangOpts().CPlusPlus) {
999 LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Numeric to unscoped "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< approximateStdConv. Numeric to unscoped "
"enum, not possible in C++!\n"; } } while (false)
1000 "enum, not possible in C++!\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< approximateStdConv. Numeric to unscoped "
"enum, not possible in C++!\n"; } } while (false)
;
1001 return {};
1002 }
1003
1004 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateStdConv. Numeric to unscoped enum.\n"
; } } while (false)
1005 << "--- approximateStdConv. Numeric to unscoped enum.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateStdConv. Numeric to unscoped enum.\n"
; } } while (false)
;
1006 WorkType = QualType{ToEnum, QualifiersToApply};
1007 }
1008
1009 // Check for pointer conversions.
1010 const auto *FromPtr = WorkType->getAs<PointerType>();
1011 const auto *ToPtr = To->getAs<PointerType>();
1012 if (FromPtr && ToPtr) {
1013 if (ToPtr->isVoidPointerType()) {
1014 LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. To void pointer.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateStdConv. To void pointer.\n"
; } } while (false)
;
1015 WorkType = QualType{ToPtr, QualifiersToApply};
1016 }
1017
1018 const auto *FromRecordPtr = FromPtr->getPointeeCXXRecordDecl();
1019 const auto *ToRecordPtr = ToPtr->getPointeeCXXRecordDecl();
1020 if (isDerivedToBase(FromRecordPtr, ToRecordPtr)) {
1021 LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Derived* to Base*\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateStdConv. Derived* to Base*\n"
; } } while (false)
;
1022 WorkType = QualType{ToPtr, QualifiersToApply};
1023 }
1024 }
1025
1026 // Model the slicing Derived-to-Base too, as "BaseT temporary = derived;"
1027 // can also be compiled.
1028 const auto *FromRecord = WorkType->getAsCXXRecordDecl();
1029 const auto *ToRecord = To->getAsCXXRecordDecl();
1030 if (isDerivedToBase(FromRecord, ToRecord)) {
1031 LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Derived To Base.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateStdConv. Derived To Base.\n"
; } } while (false)
;
1032 WorkType = QualType{ToRecord->getTypeForDecl(), QualifiersToApply};
1033 }
1034
1035 if (Ctx.getLangOpts().CPlusPlus17 && FromPtr && ToPtr) {
1036 // Function pointer conversion: A noexcept function pointer can be passed
1037 // to a non-noexcept one.
1038 const auto *FromFunctionPtr =
1039 FromPtr->getPointeeType()->getAs<FunctionProtoType>();
1040 const auto *ToFunctionPtr =
1041 ToPtr->getPointeeType()->getAs<FunctionProtoType>();
1042 if (FromFunctionPtr && ToFunctionPtr &&
1043 FromFunctionPtr->hasNoexceptExceptionSpec() &&
1044 !ToFunctionPtr->hasNoexceptExceptionSpec()) {
1045 LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. noexcept function "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateStdConv. noexcept function "
"pointer to non-noexcept.\n"; } } while (false)
1046 "pointer to non-noexcept.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateStdConv. noexcept function "
"pointer to non-noexcept.\n"; } } while (false)
;
1047 WorkType = QualType{ToPtr, QualifiersToApply};
1048 }
1049 }
1050
1051 // Qualifier adjustments are modelled according to the user's request in
1052 // the QualifiersMix check config.
1053 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateStdConv. Trying qualifier adjustment...\n"
; } } while (false)
1054 << "--- approximateStdConv. Trying qualifier adjustment...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateStdConv. Trying qualifier adjustment...\n"
; } } while (false)
;
1055 MixData QualConv = calculateMixability(Check, WorkType, To, Ctx,
1056 ImplicitConversionModellingMode::None);
1057 QualConv.sanitize();
1058 if (hasFlag(QualConv.Flags, MixFlags::Qualifiers)) {
1059 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< approximateStdConv. Qualifiers adjusted.\n"
; } } while (false)
1060 << "<<< approximateStdConv. Qualifiers adjusted.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< approximateStdConv. Qualifiers adjusted.\n"
; } } while (false)
;
1061 WorkType = To;
1062 }
1063
1064 if (WorkType == To) {
1065 LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Reached 'To' type.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< approximateStdConv. Reached 'To' type.\n"
; } } while (false)
;
1066 return {WorkType};
1067 }
1068
1069 LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Did not reach 'To'.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< approximateStdConv. Did not reach 'To'.\n"
; } } while (false)
;
1070 return {};
1071}
1072
1073namespace {
1074
1075/// Helper class for storing possible user-defined conversion calls that
1076/// *could* take place in an implicit conversion, and selecting the one that
1077/// most likely *does*, if any.
1078class UserDefinedConversionSelector {
1079public:
1080 /// The conversion associated with a conversion function, together with the
1081 /// mixability flags of the conversion function's parameter or return type
1082 /// to the rest of the sequence the selector is used in, and the sequence
1083 /// that applied through the conversion itself.
1084 struct PreparedConversion {
1085 const CXXMethodDecl *ConversionFun;
1086 MixFlags Flags;
1087 ConversionSequence Seq;
1088
1089 PreparedConversion(const CXXMethodDecl *CMD, MixFlags F,
1090 ConversionSequence S)
1091 : ConversionFun(CMD), Flags(F), Seq(S) {}
1092 };
1093
1094 UserDefinedConversionSelector(const TheCheck &Check) : Check(Check) {}
1095
1096 /// Adds the conversion between the two types for the given function into
1097 /// the possible implicit conversion set. FromType and ToType is either:
1098 /// * the result of a standard sequence and a converting ctor parameter
1099 /// * the return type of a conversion operator and the expected target of
1100 /// an implicit conversion.
1101 void addConversion(const CXXMethodDecl *ConvFun, QualType FromType,
1102 QualType ToType) {
1103 // Try to go from the FromType to the ToType with only a single implicit
1104 // conversion, to see if the conversion function is applicable.
1105 MixData Mix = calculateMixability(
1106 Check, FromType, ToType, ConvFun->getASTContext(),
1107 ImplicitConversionModellingMode::OneWaySingleStandardOnly);
1108 Mix.sanitize();
1109 if (!Mix.indicatesMixability())
1110 return;
1111
1112 LLVM_DEBUG(llvm::dbgs() << "--- tryConversion. Found viable with flags: "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- tryConversion. Found viable with flags: "
<< formatMixFlags(Mix.Flags) << '\n'; } } while (
false)
1113 << formatMixFlags(Mix.Flags) << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- tryConversion. Found viable with flags: "
<< formatMixFlags(Mix.Flags) << '\n'; } } while (
false)
;
1114 FlaggedConversions.emplace_back(ConvFun, Mix.Flags, Mix.Conversion);
1115 }
1116
1117 /// Selects the best conversion function that is applicable from the
1118 /// prepared set of potential conversion functions taken.
1119 Optional<PreparedConversion> operator()() const {
1120 if (FlaggedConversions.empty()) {
1121 LLVM_DEBUG(llvm::dbgs() << "--- selectUserDefinedConv. Empty.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- selectUserDefinedConv. Empty.\n"
; } } while (false)
;
1122 return {};
1123 }
1124 if (FlaggedConversions.size() == 1) {
1125 LLVM_DEBUG(llvm::dbgs() << "--- selectUserDefinedConv. Single.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- selectUserDefinedConv. Single.\n"
; } } while (false)
;
1126 return FlaggedConversions.front();
1127 }
1128
1129 Optional<PreparedConversion> BestConversion;
1130 unsigned short HowManyGoodConversions = 0;
1131 for (const auto &Prepared : FlaggedConversions) {
1132 LLVM_DEBUG(llvm::dbgs() << "--- selectUserDefinedConv. Candidate flags: "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- selectUserDefinedConv. Candidate flags: "
<< formatMixFlags(Prepared.Flags) << '\n'; } } while
(false)
1133 << formatMixFlags(Prepared.Flags) << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- selectUserDefinedConv. Candidate flags: "
<< formatMixFlags(Prepared.Flags) << '\n'; } } while
(false)
;
1134 if (!BestConversion) {
1135 BestConversion = Prepared;
1136 ++HowManyGoodConversions;
1137 continue;
1138 }
1139
1140 bool BestConversionHasImplicit =
1141 hasFlag(BestConversion->Flags, MixFlags::ImplicitConversion);
1142 bool ThisConversionHasImplicit =
1143 hasFlag(Prepared.Flags, MixFlags::ImplicitConversion);
1144 if (!BestConversionHasImplicit && ThisConversionHasImplicit)
1145 // This is a worse conversion, because a better one was found earlier.
1146 continue;
1147
1148 if (BestConversionHasImplicit && !ThisConversionHasImplicit) {
1149 // If the so far best selected conversion needs a previous implicit
1150 // conversion to match the user-defined converting function, but this
1151 // conversion does not, this is a better conversion, and we can throw
1152 // away the previously selected conversion(s).
1153 BestConversion = Prepared;
1154 HowManyGoodConversions = 1;
1155 continue;
1156 }
1157
1158 if (BestConversionHasImplicit == ThisConversionHasImplicit)
1159 // The current conversion is the same in term of goodness than the
1160 // already selected one.
1161 ++HowManyGoodConversions;
1162 }
1163
1164 if (HowManyGoodConversions == 1) {
1165 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- selectUserDefinedConv. Unique result. Flags: "
<< formatMixFlags(BestConversion->Flags) << '\n'
; } } while (false)
1166 << "--- selectUserDefinedConv. Unique result. Flags: "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- selectUserDefinedConv. Unique result. Flags: "
<< formatMixFlags(BestConversion->Flags) << '\n'
; } } while (false)
1167 << formatMixFlags(BestConversion->Flags) << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- selectUserDefinedConv. Unique result. Flags: "
<< formatMixFlags(BestConversion->Flags) << '\n'
; } } while (false)
;
1168 return BestConversion;
1169 }
1170
1171 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- selectUserDefinedConv. No, or ambiguous.\n"
; } } while (false)
1172 << "--- selectUserDefinedConv. No, or ambiguous.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- selectUserDefinedConv. No, or ambiguous.\n"
; } } while (false)
;
1173 return {};
1174 }
1175
1176private:
1177 llvm::SmallVector<PreparedConversion, 2> FlaggedConversions;
1178 const TheCheck &Check;
1179};
1180
1181} // namespace
1182
1183static Optional<ConversionSequence>
1184tryConversionOperators(const TheCheck &Check, const CXXRecordDecl *RD,
1185 QualType ToType) {
1186 if (!RD || !RD->isCompleteDefinition())
1187 return {};
1188 RD = RD->getDefinition();
1189
1190 LLVM_DEBUG(llvm::dbgs() << ">>> tryConversionOperators: " << RD->getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> tryConversionOperators: "
<< RD->getName() << " to:\n"; ToType.dump(llvm
::dbgs(), RD->getASTContext()); llvm::dbgs() << '\n'
;; } } while (false)
1191 << " to:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> tryConversionOperators: "
<< RD->getName() << " to:\n"; ToType.dump(llvm
::dbgs(), RD->getASTContext()); llvm::dbgs() << '\n'
;; } } while (false)
1192 ToType.dump(llvm::dbgs(), RD->getASTContext());do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> tryConversionOperators: "
<< RD->getName() << " to:\n"; ToType.dump(llvm
::dbgs(), RD->getASTContext()); llvm::dbgs() << '\n'
;; } } while (false)
1193 llvm::dbgs() << '\n';)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> tryConversionOperators: "
<< RD->getName() << " to:\n"; ToType.dump(llvm
::dbgs(), RD->getASTContext()); llvm::dbgs() << '\n'
;; } } while (false)
;
1194
1195 UserDefinedConversionSelector ConversionSet{Check};
1196
1197 for (const NamedDecl *Method : RD->getVisibleConversionFunctions()) {
1198 const auto *Con = dyn_cast<CXXConversionDecl>(Method);
1199 if (!Con || Con->isExplicit())
1200 continue;
1201 LLVM_DEBUG(llvm::dbgs() << "--- tryConversionOperators. Trying:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- tryConversionOperators. Trying:\n"
; Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';; } }
while (false)
1202 Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- tryConversionOperators. Trying:\n"
; Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';; } }
while (false)
;
1203
1204 // Try to go from the result of conversion operator to the expected type,
1205 // without calculating another user-defined conversion.
1206 ConversionSet.addConversion(Con, Con->getConversionType(), ToType);
1207 }
1208
1209 if (Optional<UserDefinedConversionSelector::PreparedConversion>
1210 SelectedConversion = ConversionSet()) {
1211 QualType RecordType{RD->getTypeForDecl(), 0};
1212
1213 ConversionSequence Result{RecordType, ToType};
1214 // The conversion from the operator call's return type to ToType was
1215 // modelled as a "pre-conversion" in the operator call, but it is the
1216 // "post-conversion" from the point of view of the original conversion
1217 // we are modelling.
1218 Result.AfterSecondStandard = SelectedConversion->Seq.AfterFirstStandard;
1219
1220 ConversionSequence::UserDefinedConversionOperator ConvOp;
1221 ConvOp.Fun = cast<CXXConversionDecl>(SelectedConversion->ConversionFun);
1222 ConvOp.UserDefinedType = RecordType;
1223 ConvOp.ConversionOperatorResultType = ConvOp.Fun->getConversionType();
1224 Result.setConversion(ConvOp);
1225
1226 LLVM_DEBUG(llvm::dbgs() << "<<< tryConversionOperators. Found result.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< tryConversionOperators. Found result.\n"
; } } while (false)
;
1227 return Result;
1228 }
1229
1230 LLVM_DEBUG(llvm::dbgs() << "<<< tryConversionOperators. No conversion.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< tryConversionOperators. No conversion.\n"
; } } while (false)
;
1231 return {};
1232}
1233
1234static Optional<ConversionSequence>
1235tryConvertingConstructors(const TheCheck &Check, QualType FromType,
1236 const CXXRecordDecl *RD) {
1237 if (!RD || !RD->isCompleteDefinition())
1238 return {};
1239 RD = RD->getDefinition();
1240
1241 LLVM_DEBUG(llvm::dbgs() << ">>> tryConveringConstructors: " << RD->getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> tryConveringConstructors: "
<< RD->getName() << " from:\n"; FromType.dump
(llvm::dbgs(), RD->getASTContext()); llvm::dbgs() <<
'\n';; } } while (false)
1242 << " from:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> tryConveringConstructors: "
<< RD->getName() << " from:\n"; FromType.dump
(llvm::dbgs(), RD->getASTContext()); llvm::dbgs() <<
'\n';; } } while (false)
1243 FromType.dump(llvm::dbgs(), RD->getASTContext());do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> tryConveringConstructors: "
<< RD->getName() << " from:\n"; FromType.dump
(llvm::dbgs(), RD->getASTContext()); llvm::dbgs() <<
'\n';; } } while (false)
1244 llvm::dbgs() << '\n';)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> tryConveringConstructors: "
<< RD->getName() << " from:\n"; FromType.dump
(llvm::dbgs(), RD->getASTContext()); llvm::dbgs() <<
'\n';; } } while (false)
;
1245
1246 UserDefinedConversionSelector ConversionSet{Check};
1247
1248 for (const CXXConstructorDecl *Con : RD->ctors()) {
1249 if (Con->isCopyOrMoveConstructor() ||
1250 !Con->isConvertingConstructor(/* AllowExplicit =*/false))
1251 continue;
1252 LLVM_DEBUG(llvm::dbgs() << "--- tryConvertingConstructors. Trying:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- tryConvertingConstructors. Trying:\n"
; Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';; } }
while (false)
1253 Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- tryConvertingConstructors. Trying:\n"
; Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';; } }
while (false)
;
1254
1255 // Try to go from the original FromType to the converting constructor's
1256 // parameter type without another user-defined conversion.
1257 ConversionSet.addConversion(Con, FromType, Con->getParamDecl(0)->getType());
1258 }
1259
1260 if (Optional<UserDefinedConversionSelector::PreparedConversion>
1261 SelectedConversion = ConversionSet()) {
1262 QualType RecordType{RD->getTypeForDecl(), 0};
1263
1264 ConversionSequence Result{FromType, RecordType};
1265 Result.AfterFirstStandard = SelectedConversion->Seq.AfterFirstStandard;
1266
1267 ConversionSequence::UserDefinedConvertingConstructor Ctor;
1268 Ctor.Fun = cast<CXXConstructorDecl>(SelectedConversion->ConversionFun);
1269 Ctor.ConstructorParameterType = Ctor.Fun->getParamDecl(0)->getType();
1270 Ctor.UserDefinedType = RecordType;
1271 Result.setConversion(Ctor);
1272
1273 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< tryConvertingConstructors. Found result.\n"
; } } while (false)
1274 << "<<< tryConvertingConstructors. Found result.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< tryConvertingConstructors. Found result.\n"
; } } while (false)
;
1275 return Result;
1276 }
1277
1278 LLVM_DEBUG(llvm::dbgs() << "<<< tryConvertingConstructors. No conversion.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< tryConvertingConstructors. No conversion.\n"
; } } while (false)
;
1279 return {};
1280}
1281
1282/// Returns whether an expression of LType can be used in an RType context, as
1283/// per the implicit conversion rules.
1284///
1285/// Note: the result of this operation, unlike that of calculateMixability, is
1286/// **NOT** symmetric.
1287static MixData
1288approximateImplicitConversion(const TheCheck &Check, QualType LType,
1289 QualType RType, const ASTContext &Ctx,
1290 ImplicitConversionModellingMode ImplicitMode) {
1291 LLVM_DEBUG(llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
1292 LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
1293 RType.dump(llvm::dbgs(), Ctx);do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
1294 llvm::dbgs() << "\nimplicit mode: "; switch (ImplicitMode) {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
1295 case ImplicitConversionModellingMode::None:do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
1296 llvm::dbgs() << "None";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
1297 break;do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
1298 case ImplicitConversionModellingMode::All:do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
1299 llvm::dbgs() << "All";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
1300 break;do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
1301 case ImplicitConversionModellingMode::OneWaySingleStandardOnly:do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
1302 llvm::dbgs() << "OneWay, Single, STD Only";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
1303 break;do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
1304 } llvm::dbgs() << '\n';)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n"
; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"
; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nimplicit mode: "
; switch (ImplicitMode) { case ImplicitConversionModellingMode
::None: llvm::dbgs() << "None"; break; case ImplicitConversionModellingMode
::All: llvm::dbgs() << "All"; break; case ImplicitConversionModellingMode
::OneWaySingleStandardOnly: llvm::dbgs() << "OneWay, Single, STD Only"
; break; } llvm::dbgs() << '\n';; } } while (false)
;
1305 if (LType == RType)
1306 return {MixFlags::Trivial, LType};
1307
1308 // An implicit conversion sequence consists of the following, in order:
1309 // * Maybe standard conversion sequence.
1310 // * Maybe user-defined conversion.
1311 // * Maybe standard conversion sequence.
1312 ConversionSequence ImplicitSeq{LType, RType};
1313 QualType WorkType = LType;
1314
1315 Optional<QualType> AfterFirstStdConv =
1316 approximateStandardConversionSequence(Check, LType, RType, Ctx);
1317 if (AfterFirstStdConv) {
1318 LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Standard "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateImplicitConversion. Standard "
"Pre-Conversion found!\n"; } } while (false)
1319 "Pre-Conversion found!\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateImplicitConversion. Standard "
"Pre-Conversion found!\n"; } } while (false)
;
1320 ImplicitSeq.AfterFirstStandard = AfterFirstStdConv.getValue();
1321 WorkType = ImplicitSeq.AfterFirstStandard;
1322 }
1323
1324 if (ImplicitMode == ImplicitConversionModellingMode::OneWaySingleStandardOnly)
1325 // If the caller only requested modelling of a standard conversion, bail.
1326 return {ImplicitSeq.AfterFirstStandard.isNull()
1327 ? MixFlags::None
1328 : MixFlags::ImplicitConversion,
1329 ImplicitSeq};
1330
1331 if (Ctx.getLangOpts().CPlusPlus) {
1332 bool FoundConversionOperator = false, FoundConvertingCtor = false;
1333
1334 if (const auto *LRD = WorkType->getAsCXXRecordDecl()) {
1335 Optional<ConversionSequence> ConversionOperatorResult =
1336 tryConversionOperators(Check, LRD, RType);
1337 if (ConversionOperatorResult) {
1338 LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Found "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateImplicitConversion. Found "
"conversion operator.\n"; } } while (false)
1339 "conversion operator.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateImplicitConversion. Found "
"conversion operator.\n"; } } while (false)
;
1340 ImplicitSeq.update(ConversionOperatorResult.getValue());
1341 WorkType = ImplicitSeq.getTypeAfterUserDefinedConversion();
1342 FoundConversionOperator = true;
1343 }
1344 }
1345
1346 if (const auto *RRD = RType->getAsCXXRecordDecl()) {
1347 // Use the original "LType" here, and not WorkType, because the
1348 // conversion to the converting constructors' parameters will be
1349 // modelled in the recursive call.
1350 Optional<ConversionSequence> ConvCtorResult =
1351 tryConvertingConstructors(Check, LType, RRD);
1352 if (ConvCtorResult) {
1353 LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Found "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateImplicitConversion. Found "
"converting constructor.\n"; } } while (false)
1354 "converting constructor.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateImplicitConversion. Found "
"converting constructor.\n"; } } while (false)
;
1355 ImplicitSeq.update(ConvCtorResult.getValue());
1356 WorkType = ImplicitSeq.getTypeAfterUserDefinedConversion();
1357 FoundConvertingCtor = true;
1358 }
1359 }
1360
1361 if (FoundConversionOperator && FoundConvertingCtor) {
1362 // If both an operator and a ctor matches, the sequence is ambiguous.
1363 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< approximateImplicitConversion. Found both "
"user-defined conversion kinds in the same sequence!\n"; } }
while (false)
1364 << "<<< approximateImplicitConversion. Found both "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< approximateImplicitConversion. Found both "
"user-defined conversion kinds in the same sequence!\n"; } }
while (false)
1365 "user-defined conversion kinds in the same sequence!\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< approximateImplicitConversion. Found both "
"user-defined conversion kinds in the same sequence!\n"; } }
while (false)
;
1366 return {MixFlags::None};
1367 }
1368 }
1369
1370 // After the potential user-defined conversion, another standard conversion
1371 // sequence might exist.
1372 LLVM_DEBUG(do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateImplicitConversion. Try to find post-conversion.\n"
; } } while (false)
1373 llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateImplicitConversion. Try to find post-conversion.\n"
; } } while (false)
1374 << "--- approximateImplicitConversion. Try to find post-conversion.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateImplicitConversion. Try to find post-conversion.\n"
; } } while (false)
;
1375 MixData SecondStdConv = approximateImplicitConversion(
1376 Check, WorkType, RType, Ctx,
1377 ImplicitConversionModellingMode::OneWaySingleStandardOnly);
1378 if (SecondStdConv.indicatesMixability()) {
1379 LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Standard "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateImplicitConversion. Standard "
"Post-Conversion found!\n"; } } while (false)
1380 "Post-Conversion found!\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "--- approximateImplicitConversion. Standard "
"Post-Conversion found!\n"; } } while (false)
;
1381
1382 // The single-step modelling puts the modelled conversion into the "PreStd"
1383 // variable in the recursive call, but from the PoV of this function, it is
1384 // the post-conversion.
1385 ImplicitSeq.AfterSecondStandard =
1386 SecondStdConv.Conversion.AfterFirstStandard;
1387 WorkType = ImplicitSeq.AfterSecondStandard;
1388 }
1389
1390 if (ImplicitSeq) {
1391 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< approximateImplicitConversion. Found a conversion.\n"
; } } while (false)
1392 << "<<< approximateImplicitConversion. Found a conversion.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< approximateImplicitConversion. Found a conversion.\n"
; } } while (false)
;
1393 return {MixFlags::ImplicitConversion, ImplicitSeq};
1394 }
1395
1396 LLVM_DEBUG(do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< approximateImplicitConversion. No match found.\n"
; } } while (false)
1397 llvm::dbgs() << "<<< approximateImplicitConversion. No match found.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "<<< approximateImplicitConversion. No match found.\n"
; } } while (false)
;
1398 return {MixFlags::None};
1399}
1400
1401static MixableParameterRange modelMixingRange(
1402 const TheCheck &Check, const FunctionDecl *FD, std::size_t StartIndex,
1403 const filter::SimilarlyUsedParameterPairSuppressor &UsageBasedSuppressor) {
1404 std::size_t NumParams = FD->getNumParams();
1405 assert(StartIndex < NumParams && "out of bounds for start")(static_cast <bool> (StartIndex < NumParams &&
"out of bounds for start") ? void (0) : __assert_fail ("StartIndex < NumParams && \"out of bounds for start\""
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 1405, __extension__ __PRETTY_FUNCTION__))
;
1406 const ASTContext &Ctx = FD->getASTContext();
1407
1408 MixableParameterRange Ret;
1409 // A parameter at index 'StartIndex' had been trivially "checked".
1410 Ret.NumParamsChecked = 1;
1411
1412 for (std::size_t I = StartIndex + 1; I < NumParams; ++I) {
1413 const ParmVarDecl *Ith = FD->getParamDecl(I);
1414 StringRef ParamName = Ith->getName();
1415 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Check param #"
<< I << " '" << ParamName << "'...\n"
; } } while (false)
1416 << "Check param #" << I << " '" << ParamName << "'...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Check param #"
<< I << " '" << ParamName << "'...\n"
; } } while (false)
;
1417 if (filter::isIgnoredParameter(Check, Ith)) {
1418 LLVM_DEBUG(llvm::dbgs() << "Param #" << I << " is ignored. Break!\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Param #"
<< I << " is ignored. Break!\n"; } } while (false
)
;
1419 break;
1420 }
1421
1422 StringRef PrevParamName = FD->getParamDecl(I - 1)->getName();
1423 if (!ParamName.empty() && !PrevParamName.empty() &&
1424 filter::prefixSuffixCoverUnderThreshold(
1425 Check.NamePrefixSuffixSilenceDissimilarityTreshold, PrevParamName,
1426 ParamName)) {
1427 LLVM_DEBUG(llvm::dbgs() << "Parameter '" << ParamNamedo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Parameter '"
<< ParamName << "' follows a pattern with previous parameter '"
<< PrevParamName << "'. Break!\n"; } } while (false
)
1428 << "' follows a pattern with previous parameter '"do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Parameter '"
<< ParamName << "' follows a pattern with previous parameter '"
<< PrevParamName << "'. Break!\n"; } } while (false
)
1429 << PrevParamName << "'. Break!\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Parameter '"
<< ParamName << "' follows a pattern with previous parameter '"
<< PrevParamName << "'. Break!\n"; } } while (false
)
;
1430 break;
1431 }
1432
1433 // Now try to go forward and build the range of [Start, ..., I, I + 1, ...]
1434 // parameters that can be messed up at a call site.
1435 MixableParameterRange::MixVector MixesOfIth;
1436 for (std::size_t J = StartIndex; J < I; ++J) {
1437 const ParmVarDecl *Jth = FD->getParamDecl(J);
1438 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Check mix of #"
<< J << " against #" << I << "...\n"
; } } while (false)
1439 << "Check mix of #" << J << " against #" << I << "...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Check mix of #"
<< J << " against #" << I << "...\n"
; } } while (false)
;
1440
1441 if (isSimilarlyUsedParameter(UsageBasedSuppressor, Ith, Jth)) {
1442 // Consider the two similarly used parameters to not be possible in a
1443 // mix-up at the user's request, if they enabled this heuristic.
1444 LLVM_DEBUG(llvm::dbgs() << "Parameters #" << I << " and #" << Jdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Parameters #"
<< I << " and #" << J << " deemed related, ignoring...\n"
; } } while (false)
1445 << " deemed related, ignoring...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Parameters #"
<< I << " and #" << J << " deemed related, ignoring...\n"
; } } while (false)
;
1446
1447 // If the parameter #I and #J mixes, then I is mixable with something
1448 // in the current range, so the range has to be broken and I not
1449 // included.
1450 MixesOfIth.clear();
1451 break;
1452 }
1453
1454 Mix M{Jth, Ith,
1455 calculateMixability(Check, Jth->getType(), Ith->getType(), Ctx,
1456 Check.ModelImplicitConversions
1457 ? ImplicitConversionModellingMode::All
1458 : ImplicitConversionModellingMode::None)};
1459 LLVM_DEBUG(llvm::dbgs() << "Mix flags (raw) : "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Mix flags (raw) : "
<< formatMixFlags(M.flags()) << '\n'; } } while (
false)
1460 << formatMixFlags(M.flags()) << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Mix flags (raw) : "
<< formatMixFlags(M.flags()) << '\n'; } } while (
false)
;
1461 M.sanitize();
1462 LLVM_DEBUG(llvm::dbgs() << "Mix flags (after sanitize): "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Mix flags (after sanitize): "
<< formatMixFlags(M.flags()) << '\n'; } } while (
false)
1463 << formatMixFlags(M.flags()) << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Mix flags (after sanitize): "
<< formatMixFlags(M.flags()) << '\n'; } } while (
false)
;
1464
1465 assert(M.flagsValid() && "All flags decayed!")(static_cast <bool> (M.flagsValid() && "All flags decayed!"
) ? void (0) : __assert_fail ("M.flagsValid() && \"All flags decayed!\""
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 1465, __extension__ __PRETTY_FUNCTION__))
;
1466
1467 if (M.mixable())
1468 MixesOfIth.emplace_back(std::move(M));
1469 }
1470
1471 if (MixesOfIth.empty()) {
1472 // If there weren't any new mixes stored for Ith, the range is
1473 // [Start, ..., I].
1474 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Param #"
<< I << " does not mix with any in the current range. Break!\n"
; } } while (false)
1475 << "Param #" << Ido { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Param #"
<< I << " does not mix with any in the current range. Break!\n"
; } } while (false)
1476 << " does not mix with any in the current range. Break!\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Param #"
<< I << " does not mix with any in the current range. Break!\n"
; } } while (false)
;
1477 break;
1478 }
1479
1480 Ret.Mixes.insert(Ret.Mixes.end(), MixesOfIth.begin(), MixesOfIth.end());
1481 ++Ret.NumParamsChecked; // Otherwise a new param was iterated.
1482 }
1483
1484 return Ret;
1485}
1486
1487} // namespace model
1488
1489/// Matches DeclRefExprs and their ignorable wrappers to ParmVarDecls.
1490AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<Stmt>, paramRefExpr)inline ast_matchers::internal::Matcher<Stmt> paramRefExpr_getInstance
(); inline ast_matchers::internal::Matcher<Stmt> paramRefExpr
() { return ::clang::ast_matchers::internal::MemoizedMatcher<
ast_matchers::internal::Matcher<Stmt>, paramRefExpr_getInstance
>::getInstance(); } inline ast_matchers::internal::Matcher
<Stmt> paramRefExpr_getInstance()
{
1491 return expr(ignoringParenImpCasts(ignoringElidableConstructorCall(
1492 declRefExpr(to(parmVarDecl().bind("param"))))));
1493}
1494
1495namespace filter {
1496
1497/// Returns whether the parameter's name or the parameter's type's name is
1498/// configured by the user to be ignored from analysis and diagnostic.
1499static bool isIgnoredParameter(const TheCheck &Check, const ParmVarDecl *Node) {
1500 LLVM_DEBUG(llvm::dbgs() << "Checking if '" << Node->getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Checking if '"
<< Node->getName() << "' is ignored.\n"; } } while
(false)
1501 << "' is ignored.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Checking if '"
<< Node->getName() << "' is ignored.\n"; } } while
(false)
;
1502
1503 if (!Node->getIdentifier())
1504 return llvm::find(Check.IgnoredParameterNames, "\"\"") !=
1505 Check.IgnoredParameterNames.end();
1506
1507 StringRef NodeName = Node->getName();
1508 if (llvm::find(Check.IgnoredParameterNames, NodeName) !=
1509 Check.IgnoredParameterNames.end()) {
1510 LLVM_DEBUG(llvm::dbgs() << "\tName ignored.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "\tName ignored.\n"
; } } while (false)
;
1511 return true;
1512 }
1513
1514 StringRef NodeTypeName = [Node] {
1515 const ASTContext &Ctx = Node->getASTContext();
1516 const SourceManager &SM = Ctx.getSourceManager();
1517 SourceLocation B = Node->getTypeSpecStartLoc();
1518 SourceLocation E = Node->getTypeSpecEndLoc();
1519 LangOptions LO;
1520
1521 LLVM_DEBUG(llvm::dbgs() << "\tType name code is '"do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "\tType name code is '"
<< Lexer::getSourceText( CharSourceRange::getTokenRange
(B, E), SM, LO) << "'...\n"; } } while (false)
1522 << Lexer::getSourceText(do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "\tType name code is '"
<< Lexer::getSourceText( CharSourceRange::getTokenRange
(B, E), SM, LO) << "'...\n"; } } while (false)
1523 CharSourceRange::getTokenRange(B, E), SM, LO)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "\tType name code is '"
<< Lexer::getSourceText( CharSourceRange::getTokenRange
(B, E), SM, LO) << "'...\n"; } } while (false)
1524 << "'...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "\tType name code is '"
<< Lexer::getSourceText( CharSourceRange::getTokenRange
(B, E), SM, LO) << "'...\n"; } } while (false)
;
1525 if (B.isMacroID()) {
1526 LLVM_DEBUG(llvm::dbgs() << "\t\tBeginning is macro.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "\t\tBeginning is macro.\n"
; } } while (false)
;
1527 B = SM.getTopMacroCallerLoc(B);
1528 }
1529 if (E.isMacroID()) {
1530 LLVM_DEBUG(llvm::dbgs() << "\t\tEnding is macro.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "\t\tEnding is macro.\n"
; } } while (false)
;
1531 E = Lexer::getLocForEndOfToken(SM.getTopMacroCallerLoc(E), 0, SM, LO);
1532 }
1533 LLVM_DEBUG(llvm::dbgs() << "\tType name code is '"do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "\tType name code is '"
<< Lexer::getSourceText( CharSourceRange::getTokenRange
(B, E), SM, LO) << "'...\n"; } } while (false)
1534 << Lexer::getSourceText(do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "\tType name code is '"
<< Lexer::getSourceText( CharSourceRange::getTokenRange
(B, E), SM, LO) << "'...\n"; } } while (false)
1535 CharSourceRange::getTokenRange(B, E), SM, LO)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "\tType name code is '"
<< Lexer::getSourceText( CharSourceRange::getTokenRange
(B, E), SM, LO) << "'...\n"; } } while (false)
1536 << "'...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "\tType name code is '"
<< Lexer::getSourceText( CharSourceRange::getTokenRange
(B, E), SM, LO) << "'...\n"; } } while (false)
;
1537
1538 return Lexer::getSourceText(CharSourceRange::getTokenRange(B, E), SM, LO);
1539 }();
1540
1541 LLVM_DEBUG(llvm::dbgs() << "\tType name is '" << NodeTypeName << "'\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "\tType name is '"
<< NodeTypeName << "'\n"; } } while (false)
;
1542 if (!NodeTypeName.empty()) {
1543 if (llvm::any_of(Check.IgnoredParameterTypeSuffixes,
1544 [NodeTypeName](const std::string &E) {
1545 return !E.empty() && NodeTypeName.endswith(E);
1546 })) {
1547 LLVM_DEBUG(llvm::dbgs() << "\tType suffix ignored.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "\tType suffix ignored.\n"
; } } while (false)
;
1548 return true;
1549 }
1550 }
1551
1552 return false;
1553}
1554
1555/// This namespace contains the implementations for the suppression of
1556/// diagnostics from similarly-used ("related") parameters.
1557namespace relatedness_heuristic {
1558
1559static constexpr std::size_t SmallDataStructureSize = 4;
1560
1561template <typename T, std::size_t N = SmallDataStructureSize>
1562using ParamToSmallSetMap =
1563 llvm::DenseMap<const ParmVarDecl *, llvm::SmallSet<T, N>>;
1564
1565/// Returns whether the sets mapped to the two elements in the map have at
1566/// least one element in common.
1567template <typename MapTy, typename ElemTy>
1568bool lazyMapOfSetsIntersectionExists(const MapTy &Map, const ElemTy &E1,
1569 const ElemTy &E2) {
1570 auto E1Iterator = Map.find(E1);
1571 auto E2Iterator = Map.find(E2);
1572 if (E1Iterator == Map.end() || E2Iterator == Map.end())
1573 return false;
1574
1575 for (const auto &E1SetElem : E1Iterator->second)
1576 if (llvm::find(E2Iterator->second, E1SetElem) != E2Iterator->second.end())
1577 return true;
1578
1579 return false;
1580}
1581
1582/// Implements the heuristic that marks two parameters related if there is
1583/// a usage for both in the same strict expression subtree. A strict
1584/// expression subtree is a tree which only includes Expr nodes, i.e. no
1585/// Stmts and no Decls.
1586class AppearsInSameExpr : public RecursiveASTVisitor<AppearsInSameExpr> {
1587 using Base = RecursiveASTVisitor<AppearsInSameExpr>;
1588
1589 const FunctionDecl *FD;
1590 const Expr *CurrentExprOnlyTreeRoot = nullptr;
1591 llvm::DenseMap<const ParmVarDecl *,
1592 llvm::SmallPtrSet<const Expr *, SmallDataStructureSize>>
1593 ParentExprsForParamRefs;
1594
1595public:
1596 void setup(const FunctionDecl *FD) {
1597 this->FD = FD;
1598 TraverseFunctionDecl(const_cast<FunctionDecl *>(FD));
1599 }
1600
1601 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1602 return lazyMapOfSetsIntersectionExists(ParentExprsForParamRefs, Param1,
1603 Param2);
1604 }
1605
1606 bool TraverseDecl(Decl *D) {
1607 CurrentExprOnlyTreeRoot = nullptr;
1608 return Base::TraverseDecl(D);
1609 }
1610
1611 bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue = nullptr) {
1612 if (auto *E = dyn_cast_or_null<Expr>(S)) {
1613 bool RootSetInCurrentStackFrame = false;
1614 if (!CurrentExprOnlyTreeRoot) {
1615 CurrentExprOnlyTreeRoot = E;
1616 RootSetInCurrentStackFrame = true;
1617 }
1618
1619 bool Ret = Base::TraverseStmt(S);
1620
1621 if (RootSetInCurrentStackFrame)
1622 CurrentExprOnlyTreeRoot = nullptr;
1623
1624 return Ret;
1625 }
1626
1627 // A Stmt breaks the strictly Expr subtree.
1628 CurrentExprOnlyTreeRoot = nullptr;
1629 return Base::TraverseStmt(S);
1630 }
1631
1632 bool VisitDeclRefExpr(DeclRefExpr *DRE) {
1633 if (!CurrentExprOnlyTreeRoot)
1634 return true;
1635
1636 if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
1637 if (llvm::find(FD->parameters(), PVD))
1638 ParentExprsForParamRefs[PVD].insert(CurrentExprOnlyTreeRoot);
1639
1640 return true;
1641 }
1642};
1643
1644/// Implements the heuristic that marks two parameters related if there are
1645/// two separate calls to the same function (overload) and the parameters are
1646/// passed to the same index in both calls, i.e f(a, b) and f(a, c) passes
1647/// b and c to the same index (2) of f(), marking them related.
1648class PassedToSameFunction {
1649 ParamToSmallSetMap<std::pair<const FunctionDecl *, unsigned>> TargetParams;
1650
1651public:
1652 void setup(const FunctionDecl *FD) {
1653 auto ParamsAsArgsInFnCalls =
1654 match(functionDecl(forEachDescendant(
1655 callExpr(forEachArgumentWithParam(
1656 paramRefExpr(), parmVarDecl().bind("passed-to")))
1657 .bind("call-expr"))),
1658 *FD, FD->getASTContext());
1659 for (const auto &Match : ParamsAsArgsInFnCalls) {
1660 const auto *PassedParamOfThisFn = Match.getNodeAs<ParmVarDecl>("param");
1661 const auto *CE = Match.getNodeAs<CallExpr>("call-expr");
1662 const auto *PassedToParam = Match.getNodeAs<ParmVarDecl>("passed-to");
1663 assert(PassedParamOfThisFn && CE && PassedToParam)(static_cast <bool> (PassedParamOfThisFn && CE &&
PassedToParam) ? void (0) : __assert_fail ("PassedParamOfThisFn && CE && PassedToParam"
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 1663, __extension__ __PRETTY_FUNCTION__))
;
1664
1665 const FunctionDecl *CalledFn = CE->getDirectCallee();
1666 if (!CalledFn)
1667 continue;
1668
1669 llvm::Optional<unsigned> TargetIdx;
1670 unsigned NumFnParams = CalledFn->getNumParams();
1671 for (unsigned Idx = 0; Idx < NumFnParams; ++Idx)
1672 if (CalledFn->getParamDecl(Idx) == PassedToParam)
1673 TargetIdx.emplace(Idx);
1674
1675 assert(TargetIdx.hasValue() && "Matched, but didn't find index?")(static_cast <bool> (TargetIdx.hasValue() && "Matched, but didn't find index?"
) ? void (0) : __assert_fail ("TargetIdx.hasValue() && \"Matched, but didn't find index?\""
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 1675, __extension__ __PRETTY_FUNCTION__))
;
1676 TargetParams[PassedParamOfThisFn].insert(
1677 {CalledFn->getCanonicalDecl(), *TargetIdx});
1678 }
1679 }
1680
1681 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1682 return lazyMapOfSetsIntersectionExists(TargetParams, Param1, Param2);
1683 }
1684};
1685
1686/// Implements the heuristic that marks two parameters related if the same
1687/// member is accessed (referred to) inside the current function's body.
1688class AccessedSameMemberOf {
1689 ParamToSmallSetMap<const Decl *> AccessedMembers;
1690
1691public:
1692 void setup(const FunctionDecl *FD) {
1693 auto MembersCalledOnParams = match(
1694 functionDecl(forEachDescendant(
1695 memberExpr(hasObjectExpression(paramRefExpr())).bind("mem-expr"))),
1696 *FD, FD->getASTContext());
1697
1698 for (const auto &Match : MembersCalledOnParams) {
1699 const auto *AccessedParam = Match.getNodeAs<ParmVarDecl>("param");
1700 const auto *ME = Match.getNodeAs<MemberExpr>("mem-expr");
1701 assert(AccessedParam && ME)(static_cast <bool> (AccessedParam && ME) ? void
(0) : __assert_fail ("AccessedParam && ME", "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 1701, __extension__ __PRETTY_FUNCTION__))
;
1702 AccessedMembers[AccessedParam].insert(
1703 ME->getMemberDecl()->getCanonicalDecl());
1704 }
1705 }
1706
1707 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1708 return lazyMapOfSetsIntersectionExists(AccessedMembers, Param1, Param2);
1709 }
1710};
1711
1712/// Implements the heuristic that marks two parameters related if different
1713/// ReturnStmts return them from the function.
1714class Returned {
1715 llvm::SmallVector<const ParmVarDecl *, SmallDataStructureSize> ReturnedParams;
1716
1717public:
1718 void setup(const FunctionDecl *FD) {
1719 // TODO: Handle co_return.
1720 auto ParamReturns = match(functionDecl(forEachDescendant(
1721 returnStmt(hasReturnValue(paramRefExpr())))),
1722 *FD, FD->getASTContext());
1723 for (const auto &Match : ParamReturns) {
1724 const auto *ReturnedParam = Match.getNodeAs<ParmVarDecl>("param");
1725 assert(ReturnedParam)(static_cast <bool> (ReturnedParam) ? void (0) : __assert_fail
("ReturnedParam", "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 1725, __extension__ __PRETTY_FUNCTION__))
;
1726
1727 if (find(FD->parameters(), ReturnedParam) == FD->param_end())
1728 // Inside the subtree of a FunctionDecl there might be ReturnStmts of
1729 // a parameter that isn't the parameter of the function, e.g. in the
1730 // case of lambdas.
1731 continue;
1732
1733 ReturnedParams.emplace_back(ReturnedParam);
1734 }
1735 }
1736
1737 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1738 return llvm::find(ReturnedParams, Param1) != ReturnedParams.end() &&
1739 llvm::find(ReturnedParams, Param2) != ReturnedParams.end();
1740 }
1741};
1742
1743} // namespace relatedness_heuristic
1744
1745/// Helper class that is used to detect if two parameters of the same function
1746/// are used in a similar fashion, to suppress the result.
1747class SimilarlyUsedParameterPairSuppressor {
1748 const bool Enabled;
1749 relatedness_heuristic::AppearsInSameExpr SameExpr;
1750 relatedness_heuristic::PassedToSameFunction PassToFun;
1751 relatedness_heuristic::AccessedSameMemberOf SameMember;
1752 relatedness_heuristic::Returned Returns;
1753
1754public:
1755 SimilarlyUsedParameterPairSuppressor(const FunctionDecl *FD, bool Enable)
1756 : Enabled(Enable) {
1757 if (!Enable)
1758 return;
1759
1760 SameExpr.setup(FD);
1761 PassToFun.setup(FD);
1762 SameMember.setup(FD);
1763 Returns.setup(FD);
1764 }
1765
1766 /// Returns whether the specified two parameters are deemed similarly used
1767 /// or related by the heuristics.
1768 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1769 if (!Enabled)
1770 return false;
1771
1772 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "::: Matching similar usage / relatedness heuristic...\n"
; } } while (false)
1773 << "::: Matching similar usage / relatedness heuristic...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "::: Matching similar usage / relatedness heuristic...\n"
; } } while (false)
;
1774
1775 if (SameExpr(Param1, Param2)) {
1776 LLVM_DEBUG(llvm::dbgs() << "::: Used in the same expression.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "::: Used in the same expression.\n"
; } } while (false)
;
1777 return true;
1778 }
1779
1780 if (PassToFun(Param1, Param2)) {
1781 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "::: Passed to same function in different calls.\n"
; } } while (false)
1782 << "::: Passed to same function in different calls.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "::: Passed to same function in different calls.\n"
; } } while (false)
;
1783 return true;
1784 }
1785
1786 if (SameMember(Param1, Param2)) {
1787 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "::: Same member field access or method called.\n"
; } } while (false)
1788 << "::: Same member field access or method called.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "::: Same member field access or method called.\n"
; } } while (false)
;
1789 return true;
1790 }
1791
1792 if (Returns(Param1, Param2)) {
1793 LLVM_DEBUG(llvm::dbgs() << "::: Both parameter returned.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "::: Both parameter returned.\n"
; } } while (false)
;
1794 return true;
1795 }
1796
1797 LLVM_DEBUG(llvm::dbgs() << "::: None.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "::: None.\n"
; } } while (false)
;
1798 return false;
1799 }
1800};
1801
1802// (This function hoists the call to operator() of the wrapper, so we do not
1803// need to define the previous class at the top of the file.)
1804static inline bool
1805isSimilarlyUsedParameter(const SimilarlyUsedParameterPairSuppressor &Suppressor,
1806 const ParmVarDecl *Param1, const ParmVarDecl *Param2) {
1807 return Suppressor(Param1, Param2);
1808}
1809
1810static void padStringAtEnd(SmallVectorImpl<char> &Str, std::size_t ToLen) {
1811 while (Str.size() < ToLen)
1812 Str.emplace_back('\0');
1813}
1814
1815static void padStringAtBegin(SmallVectorImpl<char> &Str, std::size_t ToLen) {
1816 while (Str.size() < ToLen)
1817 Str.insert(Str.begin(), '\0');
1818}
1819
1820static bool isCommonPrefixWithoutSomeCharacters(std::size_t N, StringRef S1,
1821 StringRef S2) {
1822 assert(S1.size() >= N && S2.size() >= N)(static_cast <bool> (S1.size() >= N && S2.size
() >= N) ? void (0) : __assert_fail ("S1.size() >= N && S2.size() >= N"
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 1822, __extension__ __PRETTY_FUNCTION__))
;
1823 StringRef S1Prefix = S1.take_front(S1.size() - N),
1824 S2Prefix = S2.take_front(S2.size() - N);
1825 return S1Prefix == S2Prefix && !S1Prefix.empty();
1826}
1827
1828static bool isCommonSuffixWithoutSomeCharacters(std::size_t N, StringRef S1,
1829 StringRef S2) {
1830 assert(S1.size() >= N && S2.size() >= N)(static_cast <bool> (S1.size() >= N && S2.size
() >= N) ? void (0) : __assert_fail ("S1.size() >= N && S2.size() >= N"
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 1830, __extension__ __PRETTY_FUNCTION__))
;
1831 StringRef S1Suffix = S1.take_back(S1.size() - N),
1832 S2Suffix = S2.take_back(S2.size() - N);
1833 return S1Suffix == S2Suffix && !S1Suffix.empty();
1834}
1835
1836/// Returns whether the two strings are prefixes or suffixes of each other with
1837/// at most Threshold characters differing on the non-common end.
1838static bool prefixSuffixCoverUnderThreshold(std::size_t Threshold,
1839 StringRef Str1, StringRef Str2) {
1840 if (Threshold == 0)
1841 return false;
1842
1843 // Pad the two strings to the longer length.
1844 std::size_t BiggerLength = std::max(Str1.size(), Str2.size());
1845
1846 if (BiggerLength <= Threshold)
1847 // If the length of the strings is still smaller than the threshold, they
1848 // would be covered by an empty prefix/suffix with the rest differing.
1849 // (E.g. "A" and "X" with Threshold = 1 would mean we think they are
1850 // similar and do not warn about them, which is a too eager assumption.)
1851 return false;
1852
1853 SmallString<32> S1PadE{Str1}, S2PadE{Str2};
1854 padStringAtEnd(S1PadE, BiggerLength);
1855 padStringAtEnd(S2PadE, BiggerLength);
1856
1857 if (isCommonPrefixWithoutSomeCharacters(
1858 Threshold, StringRef{S1PadE.begin(), BiggerLength},
1859 StringRef{S2PadE.begin(), BiggerLength}))
1860 return true;
1861
1862 SmallString<32> S1PadB{Str1}, S2PadB{Str2};
1863 padStringAtBegin(S1PadB, BiggerLength);
1864 padStringAtBegin(S2PadB, BiggerLength);
1865
1866 if (isCommonSuffixWithoutSomeCharacters(
1867 Threshold, StringRef{S1PadB.begin(), BiggerLength},
1868 StringRef{S2PadB.begin(), BiggerLength}))
1869 return true;
1870
1871 return false;
1872}
1873
1874} // namespace filter
1875
1876/// Matches functions that have at least the specified amount of parameters.
1877AST_MATCHER_P(FunctionDecl, parameterCountGE, unsigned, N)namespace internal { class matcher_parameterCountGE0Matcher :
public ::clang::ast_matchers::internal::MatcherInterface<
FunctionDecl> { public: explicit matcher_parameterCountGE0Matcher
( unsigned const &AN) : N(AN) {} bool matches(const FunctionDecl
&Node, ::clang::ast_matchers::internal::ASTMatchFinder *
Finder, ::clang::ast_matchers::internal::BoundNodesTreeBuilder
*Builder) const override; private: unsigned N; }; } inline ::
clang::ast_matchers::internal::Matcher<FunctionDecl> parameterCountGE
( unsigned const &N) { return ::clang::ast_matchers::internal
::makeMatcher( new internal::matcher_parameterCountGE0Matcher
(N)); } typedef ::clang::ast_matchers::internal::Matcher<FunctionDecl
> ( &parameterCountGE_Type0)(unsigned const &N); inline
bool internal::matcher_parameterCountGE0Matcher::matches( const
FunctionDecl &Node, ::clang::ast_matchers::internal::ASTMatchFinder
*Finder, ::clang::ast_matchers::internal::BoundNodesTreeBuilder
*Builder) const
{
1878 return Node.getNumParams() >= N;
1879}
1880
1881/// Matches *any* overloaded unary and binary operators.
1882AST_MATCHER(FunctionDecl, isOverloadedUnaryOrBinaryOperator)namespace internal { class matcher_isOverloadedUnaryOrBinaryOperatorMatcher
: public ::clang::ast_matchers::internal::MatcherInterface<
FunctionDecl> { public: explicit matcher_isOverloadedUnaryOrBinaryOperatorMatcher
() = default; bool matches(const FunctionDecl &Node, ::clang
::ast_matchers::internal::ASTMatchFinder *Finder, ::clang::ast_matchers
::internal::BoundNodesTreeBuilder *Builder) const override; }
; } inline ::clang::ast_matchers::internal::Matcher<FunctionDecl
> isOverloadedUnaryOrBinaryOperator() { return ::clang::ast_matchers
::internal::makeMatcher( new internal::matcher_isOverloadedUnaryOrBinaryOperatorMatcher
()); } inline bool internal::matcher_isOverloadedUnaryOrBinaryOperatorMatcher
::matches( const FunctionDecl &Node, ::clang::ast_matchers
::internal::ASTMatchFinder *Finder, ::clang::ast_matchers::internal
::BoundNodesTreeBuilder *Builder) const
{
1883 switch (Node.getOverloadedOperator()) {
1884 case OO_None:
1885 case OO_New:
1886 case OO_Delete:
1887 case OO_Array_New:
1888 case OO_Array_Delete:
1889 case OO_Conditional:
1890 case OO_Coawait:
1891 return false;
1892
1893 default:
1894 return Node.getNumParams() <= 2;
1895 }
1896}
1897
1898/// Returns the DefaultMinimumLength if the Value of requested minimum length
1899/// is less than 2. Minimum lengths of 0 or 1 are not accepted.
1900static inline unsigned clampMinimumLength(const unsigned Value) {
1901 return Value < 2 ? DefaultMinimumLength : Value;
1902}
1903
1904// FIXME: Maybe unneeded, getNameForDiagnostic() is expected to change to return
1905// a crafted location when the node itself is unnamed. (See D84658, D85033.)
1906/// Returns the diagnostic-friendly name of the node, or empty string.
1907static SmallString<64> getName(const NamedDecl *ND) {
1908 SmallString<64> Name;
1909 llvm::raw_svector_ostream OS{Name};
1910 ND->getNameForDiagnostic(OS, ND->getASTContext().getPrintingPolicy(), false);
1911 return Name;
1912}
1913
1914/// Returns the diagnostic-friendly name of the node, or a constant value.
1915static SmallString<64> getNameOrUnnamed(const NamedDecl *ND) {
1916 auto Name = getName(ND);
1917 if (Name.empty())
1918 Name = "<unnamed>";
1919 return Name;
1920}
1921
1922/// Returns whether a particular Mix between two parameters should have the
1923/// types involved diagnosed to the user. This is only a flag check.
1924static inline bool needsToPrintTypeInDiagnostic(const model::Mix &M) {
1925 using namespace model;
1926 return static_cast<bool>(
1927 M.flags() &
1928 (MixFlags::TypeAlias | MixFlags::ReferenceBind | MixFlags::Qualifiers));
1929}
1930
1931/// Returns whether a particular Mix between the two parameters should have
1932/// implicit conversions elaborated.
1933static inline bool needsToElaborateImplicitConversion(const model::Mix &M) {
1934 return hasFlag(M.flags(), model::MixFlags::ImplicitConversion);
1935}
1936
1937namespace {
1938
1939/// This class formats a conversion sequence into a "Ty1 -> Ty2 -> Ty3" line
1940/// that can be used in diagnostics.
1941struct FormattedConversionSequence {
1942 std::string DiagnosticText;
1943
1944 /// The formatted sequence is trivial if it is "Ty1 -> Ty2", but Ty1 and
1945 /// Ty2 are the types that are shown in the code. A trivial diagnostic
1946 /// does not need to be printed.
1947 bool Trivial;
1948
1949 FormattedConversionSequence(const PrintingPolicy &PP,
1950 StringRef StartTypeAsDiagnosed,
1951 const model::ConversionSequence &Conv,
1952 StringRef DestinationTypeAsDiagnosed) {
1953 Trivial = true;
1954 llvm::raw_string_ostream OS{DiagnosticText};
1955
1956 // Print the type name as it is printed in other places in the diagnostic.
1957 OS << '\'' << StartTypeAsDiagnosed << '\'';
1958 std::string LastAddedType = StartTypeAsDiagnosed.str();
1959 std::size_t NumElementsAdded = 1;
1960
1961 // However, the parameter's defined type might not be what the implicit
1962 // conversion started with, e.g. if a typedef is found to convert.
1963 std::string SeqBeginTypeStr = Conv.Begin.getAsString(PP);
1964 std::string SeqEndTypeStr = Conv.End.getAsString(PP);
1965 if (StartTypeAsDiagnosed != SeqBeginTypeStr) {
1966 OS << " (as '" << SeqBeginTypeStr << "')";
1967 LastAddedType = SeqBeginTypeStr;
1968 Trivial = false;
1969 }
1970
1971 auto AddType = [&](StringRef ToAdd) {
1972 if (LastAddedType != ToAdd && ToAdd != SeqEndTypeStr) {
1973 OS << " -> '" << ToAdd << "'";
1974 LastAddedType = ToAdd.str();
1975 ++NumElementsAdded;
1976 }
1977 };
1978 for (QualType InvolvedType : Conv.getInvolvedTypesInSequence())
1979 // Print every type that's unique in the sequence into the diagnosis.
1980 AddType(InvolvedType.getAsString(PP));
1981
1982 if (LastAddedType != DestinationTypeAsDiagnosed) {
1983 OS << " -> '" << DestinationTypeAsDiagnosed << "'";
1984 LastAddedType = DestinationTypeAsDiagnosed.str();
1985 ++NumElementsAdded;
1986 }
1987
1988 // Same reasoning as with the Begin, e.g. if the converted-to type is a
1989 // typedef, it will not be the same inside the conversion sequence (where
1990 // the model already tore off typedefs) as in the code.
1991 if (DestinationTypeAsDiagnosed != SeqEndTypeStr) {
1992 OS << " (as '" << SeqEndTypeStr << "')";
1993 LastAddedType = SeqEndTypeStr;
1994 Trivial = false;
1995 }
1996
1997 if (Trivial && NumElementsAdded > 2)
1998 // If the thing is still marked trivial but we have more than the
1999 // from and to types added, it should not be trivial, and elaborated
2000 // when printing the diagnostic.
2001 Trivial = false;
2002 }
2003};
2004
2005/// Retains the elements called with and returns whether the call is done with
2006/// a new element.
2007template <typename E, std::size_t N> class InsertOnce {
2008 llvm::SmallSet<E, N> CalledWith;
2009
2010public:
2011 bool operator()(E El) { return CalledWith.insert(std::move(El)).second; }
2012
2013 bool calledWith(const E &El) const { return CalledWith.contains(El); }
2014};
2015
2016struct SwappedEqualQualTypePair {
2017 QualType LHSType, RHSType;
2018
2019 bool operator==(const SwappedEqualQualTypePair &Other) const {
2020 return (LHSType == Other.LHSType && RHSType == Other.RHSType) ||
2021 (LHSType == Other.RHSType && RHSType == Other.LHSType);
2022 }
2023
2024 bool operator<(const SwappedEqualQualTypePair &Other) const {
2025 return LHSType < Other.LHSType && RHSType < Other.RHSType;
2026 }
2027};
2028
2029struct TypeAliasDiagnosticTuple {
2030 QualType LHSType, RHSType, CommonType;
2031
2032 bool operator==(const TypeAliasDiagnosticTuple &Other) const {
2033 return CommonType == Other.CommonType &&
2034 ((LHSType == Other.LHSType && RHSType == Other.RHSType) ||
2035 (LHSType == Other.RHSType && RHSType == Other.LHSType));
2036 }
2037
2038 bool operator<(const TypeAliasDiagnosticTuple &Other) const {
2039 return CommonType < Other.CommonType && LHSType < Other.LHSType &&
2040 RHSType < Other.RHSType;
2041 }
2042};
2043
2044/// Helper class to only emit a diagnostic related to MixFlags::TypeAlias once.
2045class UniqueTypeAliasDiagnosticHelper
2046 : public InsertOnce<TypeAliasDiagnosticTuple, 8> {
2047 using Base = InsertOnce<TypeAliasDiagnosticTuple, 8>;
2048
2049public:
2050 /// Returns whether the diagnostic for LHSType and RHSType which are both
2051 /// referring to CommonType being the same has not been emitted already.
2052 bool operator()(QualType LHSType, QualType RHSType, QualType CommonType) {
2053 if (CommonType.isNull() || CommonType == LHSType || CommonType == RHSType)
2054 return Base::operator()({LHSType, RHSType, {}});
2055
2056 TypeAliasDiagnosticTuple ThreeTuple{LHSType, RHSType, CommonType};
2057 if (!Base::operator()(ThreeTuple))
2058 return false;
2059
2060 bool AlreadySaidLHSAndCommonIsSame = calledWith({LHSType, CommonType, {}});
2061 bool AlreadySaidRHSAndCommonIsSame = calledWith({RHSType, CommonType, {}});
2062 if (AlreadySaidLHSAndCommonIsSame && AlreadySaidRHSAndCommonIsSame) {
2063 // "SomeInt == int" && "SomeOtherInt == int" => "Common(SomeInt,
2064 // SomeOtherInt) == int", no need to diagnose it. Save the 3-tuple only
2065 // for shortcut if it ever appears again.
2066 return false;
2067 }
2068
2069 return true;
2070 }
2071};
2072
2073} // namespace
2074
2075EasilySwappableParametersCheck::EasilySwappableParametersCheck(
2076 StringRef Name, ClangTidyContext *Context)
2077 : ClangTidyCheck(Name, Context),
2078 MinimumLength(clampMinimumLength(
2079 Options.get("MinimumLength", DefaultMinimumLength))),
2080 IgnoredParameterNames(optutils::parseStringList(
2081 Options.get("IgnoredParameterNames", DefaultIgnoredParameterNames))),
2082 IgnoredParameterTypeSuffixes(optutils::parseStringList(
2083 Options.get("IgnoredParameterTypeSuffixes",
2084 DefaultIgnoredParameterTypeSuffixes))),
2085 QualifiersMix(Options.get("QualifiersMix", DefaultQualifiersMix)),
2086 ModelImplicitConversions(Options.get("ModelImplicitConversions",
2087 DefaultModelImplicitConversions)),
2088 SuppressParametersUsedTogether(
2089 Options.get("SuppressParametersUsedTogether",
2090 DefaultSuppressParametersUsedTogether)),
2091 NamePrefixSuffixSilenceDissimilarityTreshold(
2092 Options.get("NamePrefixSuffixSilenceDissimilarityTreshold",
2093 DefaultNamePrefixSuffixSilenceDissimilarityTreshold)) {}
2094
2095void EasilySwappableParametersCheck::storeOptions(
2096 ClangTidyOptions::OptionMap &Opts) {
2097 Options.store(Opts, "MinimumLength", MinimumLength);
2098 Options.store(Opts, "IgnoredParameterNames",
2099 optutils::serializeStringList(IgnoredParameterNames));
2100 Options.store(Opts, "IgnoredParameterTypeSuffixes",
2101 optutils::serializeStringList(IgnoredParameterTypeSuffixes));
2102 Options.store(Opts, "QualifiersMix", QualifiersMix);
2103 Options.store(Opts, "ModelImplicitConversions", ModelImplicitConversions);
2104 Options.store(Opts, "SuppressParametersUsedTogether",
2105 SuppressParametersUsedTogether);
2106 Options.store(Opts, "NamePrefixSuffixSilenceDissimilarityTreshold",
2107 NamePrefixSuffixSilenceDissimilarityTreshold);
2108}
2109
2110void EasilySwappableParametersCheck::registerMatchers(MatchFinder *Finder) {
2111 const auto BaseConstraints = functionDecl(
2112 // Only report for definition nodes, as fixing the issues reported
2113 // requires the user to be able to change code.
2114 isDefinition(), parameterCountGE(MinimumLength),
2115 unless(isOverloadedUnaryOrBinaryOperator()));
2116
2117 Finder->addMatcher(
2118 functionDecl(BaseConstraints,
2119 unless(ast_matchers::isTemplateInstantiation()))
2120 .bind("func"),
2121 this);
2122 Finder->addMatcher(
2123 functionDecl(BaseConstraints, isExplicitTemplateSpecialization())
2124 .bind("func"),
2125 this);
2126}
2127
2128void EasilySwappableParametersCheck::check(
2129 const MatchFinder::MatchResult &Result) {
2130 using namespace model;
2131 using namespace filter;
2132
2133 const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("func");
2134 assert(FD)(static_cast <bool> (FD) ? void (0) : __assert_fail ("FD"
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 2134, __extension__ __PRETTY_FUNCTION__))
;
1
'?' condition is true
2135
2136 const PrintingPolicy &PP = FD->getASTContext().getPrintingPolicy();
2137 std::size_t NumParams = FD->getNumParams();
2138 std::size_t MixableRangeStartIndex = 0;
2139
2140 // Spawn one suppressor and if the user requested, gather information from
2141 // the AST for the parameters' usages.
2142 filter::SimilarlyUsedParameterPairSuppressor UsageBasedSuppressor{
2143 FD, SuppressParametersUsedTogether};
2144
2145 LLVM_DEBUG(llvm::dbgs() << "Begin analysis of " << getName(FD) << " with "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Begin analysis of "
<< getName(FD) << " with " << NumParams <<
" parameters...\n"; } } while (false)
2
Assuming 'DebugFlag' is false
3
Loop condition is false. Exiting loop
2146 << NumParams << " parameters...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Begin analysis of "
<< getName(FD) << " with " << NumParams <<
" parameters...\n"; } } while (false)
;
2147 while (MixableRangeStartIndex < NumParams) {
4
Assuming 'MixableRangeStartIndex' is < 'NumParams'
5
Loop condition is true. Entering loop body
2148 if (isIgnoredParameter(*this, FD->getParamDecl(MixableRangeStartIndex))) {
6
Taking false branch
2149 LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Parameter #"
<< MixableRangeStartIndex << " ignored.\n"; } } while
(false)
2150 << "Parameter #" << MixableRangeStartIndex << " ignored.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Parameter #"
<< MixableRangeStartIndex << " ignored.\n"; } } while
(false)
;
2151 ++MixableRangeStartIndex;
2152 continue;
2153 }
2154
2155 MixableParameterRange R = modelMixingRange(
2156 *this, FD, MixableRangeStartIndex, UsageBasedSuppressor);
2157 assert(R.NumParamsChecked > 0 && "Ensure forward progress!")(static_cast <bool> (R.NumParamsChecked > 0 &&
"Ensure forward progress!") ? void (0) : __assert_fail ("R.NumParamsChecked > 0 && \"Ensure forward progress!\""
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 2157, __extension__ __PRETTY_FUNCTION__))
;
7
Assuming field 'NumParamsChecked' is > 0
8
'?' condition is true
2158 MixableRangeStartIndex += R.NumParamsChecked;
2159 if (R.NumParamsChecked < MinimumLength) {
9
Assuming field 'NumParamsChecked' is >= field 'MinimumLength'
10
Taking false branch
2160 LLVM_DEBUG(llvm::dbgs() << "Ignoring range of " << R.NumParamsCheckeddo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Ignoring range of "
<< R.NumParamsChecked << " lower than limit.\n";
} } while (false)
2161 << " lower than limit.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("EasilySwappableParametersCheck")) { llvm::dbgs() << "Ignoring range of "
<< R.NumParamsChecked << " lower than limit.\n";
} } while (false)
;
2162 continue;
2163 }
2164
2165 bool NeedsAnyTypeNote = llvm::any_of(R.Mixes, needsToPrintTypeInDiagnostic);
2166 bool HasAnyImplicits =
2167 llvm::any_of(R.Mixes, needsToElaborateImplicitConversion);
2168 const ParmVarDecl *First = R.getFirstParam(), *Last = R.getLastParam();
2169 std::string FirstParamTypeAsWritten = First->getType().getAsString(PP);
2170 {
2171 StringRef DiagText;
2172
2173 if (HasAnyImplicits
10.1
'HasAnyImplicits' is false
10.1
'HasAnyImplicits' is false
)
11
Taking false branch
2174 DiagText = "%0 adjacent parameters of %1 of convertible types are "
2175 "easily swapped by mistake";
2176 else if (NeedsAnyTypeNote
11.1
'NeedsAnyTypeNote' is false
11.1
'NeedsAnyTypeNote' is false
)
12
Taking false branch
2177 DiagText = "%0 adjacent parameters of %1 of similar type are easily "
2178 "swapped by mistake";
2179 else
2180 DiagText = "%0 adjacent parameters of %1 of similar type ('%2') are "
2181 "easily swapped by mistake";
2182
2183 auto Diag = diag(First->getOuterLocStart(), DiagText)
13
Calling 'DiagnosticBuilder::operator<<'
24
Returning from 'DiagnosticBuilder::operator<<'
25
Calling '~DiagnosticBuilder'
39
Returning from '~DiagnosticBuilder'
2184 << static_cast<unsigned>(R.NumParamsChecked) << FD;
2185 if (!NeedsAnyTypeNote
39.1
'NeedsAnyTypeNote' is false
39.1
'NeedsAnyTypeNote' is false
)
40
Taking true branch
2186 Diag << FirstParamTypeAsWritten;
41
Calling 'DiagnosticBuilder::operator<<'
2187
2188 CharSourceRange HighlightRange = CharSourceRange::getTokenRange(
2189 First->getBeginLoc(), Last->getEndLoc());
2190 Diag << HighlightRange;
2191 }
2192
2193 // There is a chance that the previous highlight did not succeed, e.g. when
2194 // the two parameters are on different lines. For clarity, show the user
2195 // the involved variable explicitly.
2196 diag(First->getLocation(), "the first parameter in the range is '%0'",
2197 DiagnosticIDs::Note)
2198 << getNameOrUnnamed(First)
2199 << CharSourceRange::getTokenRange(First->getLocation(),
2200 First->getLocation());
2201 diag(Last->getLocation(), "the last parameter in the range is '%0'",
2202 DiagnosticIDs::Note)
2203 << getNameOrUnnamed(Last)
2204 << CharSourceRange::getTokenRange(Last->getLocation(),
2205 Last->getLocation());
2206
2207 // Helper classes to silence elaborative diagnostic notes that would be
2208 // too verbose.
2209 UniqueTypeAliasDiagnosticHelper UniqueTypeAlias;
2210 InsertOnce<SwappedEqualQualTypePair, 8> UniqueBindPower;
2211 InsertOnce<SwappedEqualQualTypePair, 8> UniqueImplicitConversion;
2212
2213 for (const model::Mix &M : R.Mixes) {
2214 assert(M.mixable() && "Sentinel or false mix in result.")(static_cast <bool> (M.mixable() && "Sentinel or false mix in result."
) ? void (0) : __assert_fail ("M.mixable() && \"Sentinel or false mix in result.\""
, "clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp"
, 2214, __extension__ __PRETTY_FUNCTION__))
;
2215 if (!needsToPrintTypeInDiagnostic(M) &&
2216 !needsToElaborateImplicitConversion(M))
2217 continue;
2218
2219 // Typedefs might result in the type of the variable needing to be
2220 // emitted to a note diagnostic, so prepare it.
2221 const ParmVarDecl *LVar = M.First;
2222 const ParmVarDecl *RVar = M.Second;
2223 QualType LType = LVar->getType();
2224 QualType RType = RVar->getType();
2225 QualType CommonType = M.commonUnderlyingType();
2226 std::string LTypeStr = LType.getAsString(PP);
2227 std::string RTypeStr = RType.getAsString(PP);
2228 std::string CommonTypeStr = CommonType.getAsString(PP);
2229
2230 if (hasFlag(M.flags(), MixFlags::TypeAlias) &&
2231 UniqueTypeAlias(LType, RType, CommonType)) {
2232 StringRef DiagText;
2233 bool ExplicitlyPrintCommonType = false;
2234 if (LTypeStr == CommonTypeStr || RTypeStr == CommonTypeStr) {
2235 if (hasFlag(M.flags(), MixFlags::Qualifiers))
2236 DiagText = "after resolving type aliases, '%0' and '%1' share a "
2237 "common type";
2238 else
2239 DiagText =
2240 "after resolving type aliases, '%0' and '%1' are the same";
2241 } else if (!CommonType.isNull()) {
2242 DiagText = "after resolving type aliases, the common type of '%0' "
2243 "and '%1' is '%2'";
2244 ExplicitlyPrintCommonType = true;
2245 }
2246
2247 auto Diag =
2248 diag(LVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2249 << LTypeStr << RTypeStr;
2250 if (ExplicitlyPrintCommonType)
2251 Diag << CommonTypeStr;
2252 }
2253
2254 if ((hasFlag(M.flags(), MixFlags::ReferenceBind) ||
2255 hasFlag(M.flags(), MixFlags::Qualifiers)) &&
2256 UniqueBindPower({LType, RType})) {
2257 StringRef DiagText = "'%0' and '%1' parameters accept and bind the "
2258 "same kind of values";
2259 diag(RVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2260 << LTypeStr << RTypeStr;
2261 }
2262
2263 if (needsToElaborateImplicitConversion(M) &&
2264 UniqueImplicitConversion({LType, RType})) {
2265 const model::ConversionSequence &LTR =
2266 M.leftToRightConversionSequence();
2267 const model::ConversionSequence &RTL =
2268 M.rightToLeftConversionSequence();
2269 FormattedConversionSequence LTRFmt{PP, LTypeStr, LTR, RTypeStr};
2270 FormattedConversionSequence RTLFmt{PP, RTypeStr, RTL, LTypeStr};
2271
2272 StringRef DiagText = "'%0' and '%1' may be implicitly converted";
2273 if (!LTRFmt.Trivial || !RTLFmt.Trivial)
2274 DiagText = "'%0' and '%1' may be implicitly converted: %2, %3";
2275
2276 {
2277 auto Diag =
2278 diag(RVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2279 << LTypeStr << RTypeStr;
2280
2281 if (!LTRFmt.Trivial || !RTLFmt.Trivial)
2282 Diag << LTRFmt.DiagnosticText << RTLFmt.DiagnosticText;
2283 }
2284
2285 StringRef ConversionFunctionDiagText =
2286 "the implicit conversion involves the "
2287 "%select{|converting constructor|conversion operator}0 "
2288 "declared here";
2289 if (const FunctionDecl *LFD = LTR.getUserDefinedConversionFunction())
2290 diag(LFD->getLocation(), ConversionFunctionDiagText,
2291 DiagnosticIDs::Note)
2292 << static_cast<unsigned>(LTR.UDConvKind)
2293 << LTR.getUserDefinedConversionHighlight();
2294 if (const FunctionDecl *RFD = RTL.getUserDefinedConversionFunction())
2295 diag(RFD->getLocation(), ConversionFunctionDiagText,
2296 DiagnosticIDs::Note)
2297 << static_cast<unsigned>(RTL.UDConvKind)
2298 << RTL.getUserDefinedConversionHighlight();
2299 }
2300 }
2301 }
2302}
2303
2304} // namespace bugprone
2305} // namespace tidy
2306} // namespace clang

/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/clang/include/clang/Basic/Diagnostic.h

1//===- Diagnostic.h - C Language Family Diagnostic Handling -----*- C++ -*-===//
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/// \file
10/// Defines the Diagnostic-related interfaces.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_BASIC_DIAGNOSTIC_H
15#define LLVM_CLANG_BASIC_DIAGNOSTIC_H
16
17#include "clang/Basic/DiagnosticIDs.h"
18#include "clang/Basic/DiagnosticOptions.h"
19#include "clang/Basic/SourceLocation.h"
20#include "clang/Basic/Specifiers.h"
21#include "llvm/ADT/ArrayRef.h"
22#include "llvm/ADT/DenseMap.h"
23#include "llvm/ADT/IntrusiveRefCntPtr.h"
24#include "llvm/ADT/Optional.h"
25#include "llvm/ADT/SmallVector.h"
26#include "llvm/ADT/StringRef.h"
27#include "llvm/ADT/iterator_range.h"
28#include "llvm/Support/Compiler.h"
29#include <cassert>
30#include <cstdint>
31#include <limits>
32#include <list>
33#include <map>
34#include <memory>
35#include <string>
36#include <type_traits>
37#include <utility>
38#include <vector>
39
40namespace llvm {
41class Error;
42}
43
44namespace clang {
45
46class DeclContext;
47class DiagnosticBuilder;
48class DiagnosticConsumer;
49class IdentifierInfo;
50class LangOptions;
51class Preprocessor;
52class SourceManager;
53class StoredDiagnostic;
54
55namespace tok {
56
57enum TokenKind : unsigned short;
58
59} // namespace tok
60
61/// Annotates a diagnostic with some code that should be
62/// inserted, removed, or replaced to fix the problem.
63///
64/// This kind of hint should be used when we are certain that the
65/// introduction, removal, or modification of a particular (small!)
66/// amount of code will correct a compilation error. The compiler
67/// should also provide full recovery from such errors, such that
68/// suppressing the diagnostic output can still result in successful
69/// compilation.
70class FixItHint {
71public:
72 /// Code that should be replaced to correct the error. Empty for an
73 /// insertion hint.
74 CharSourceRange RemoveRange;
75
76 /// Code in the specific range that should be inserted in the insertion
77 /// location.
78 CharSourceRange InsertFromRange;
79
80 /// The actual code to insert at the insertion location, as a
81 /// string.
82 std::string CodeToInsert;
83
84 bool BeforePreviousInsertions = false;
85
86 /// Empty code modification hint, indicating that no code
87 /// modification is known.
88 FixItHint() = default;
89
90 bool isNull() const {
91 return !RemoveRange.isValid();
92 }
93
94 /// Create a code modification hint that inserts the given
95 /// code string at a specific location.
96 static FixItHint CreateInsertion(SourceLocation InsertionLoc,
97 StringRef Code,
98 bool BeforePreviousInsertions = false) {
99 FixItHint Hint;
100 Hint.RemoveRange =
101 CharSourceRange::getCharRange(InsertionLoc, InsertionLoc);
102 Hint.CodeToInsert = std::string(Code);
103 Hint.BeforePreviousInsertions = BeforePreviousInsertions;
104 return Hint;
105 }
106
107 /// Create a code modification hint that inserts the given
108 /// code from \p FromRange at a specific location.
109 static FixItHint CreateInsertionFromRange(SourceLocation InsertionLoc,
110 CharSourceRange FromRange,
111 bool BeforePreviousInsertions = false) {
112 FixItHint Hint;
113 Hint.RemoveRange =
114 CharSourceRange::getCharRange(InsertionLoc, InsertionLoc);
115 Hint.InsertFromRange = FromRange;
116 Hint.BeforePreviousInsertions = BeforePreviousInsertions;
117 return Hint;
118 }
119
120 /// Create a code modification hint that removes the given
121 /// source range.
122 static FixItHint CreateRemoval(CharSourceRange RemoveRange) {
123 FixItHint Hint;
124 Hint.RemoveRange = RemoveRange;
125 return Hint;
126 }
127 static FixItHint CreateRemoval(SourceRange RemoveRange) {
128 return CreateRemoval(CharSourceRange::getTokenRange(RemoveRange));
129 }
130
131 /// Create a code modification hint that replaces the given
132 /// source range with the given code string.
133 static FixItHint CreateReplacement(CharSourceRange RemoveRange,
134 StringRef Code) {
135 FixItHint Hint;
136 Hint.RemoveRange = RemoveRange;
137 Hint.CodeToInsert = std::string(Code);
138 return Hint;
139 }
140
141 static FixItHint CreateReplacement(SourceRange RemoveRange,
142 StringRef Code) {
143 return CreateReplacement(CharSourceRange::getTokenRange(RemoveRange), Code);
144 }
145};
146
147struct DiagnosticStorage {
148 enum {
149 /// The maximum number of arguments we can hold. We
150 /// currently only support up to 10 arguments (%0-%9).
151 ///
152 /// A single diagnostic with more than that almost certainly has to
153 /// be simplified anyway.
154 MaxArguments = 10
155 };
156
157 /// The number of entries in Arguments.
158 unsigned char NumDiagArgs = 0;
159
160 /// Specifies for each argument whether it is in DiagArgumentsStr
161 /// or in DiagArguments.
162 unsigned char DiagArgumentsKind[MaxArguments];
163
164 /// The values for the various substitution positions.
165 ///
166 /// This is used when the argument is not an std::string. The specific value
167 /// is mangled into an uint64_t and the interpretation depends on exactly
168 /// what sort of argument kind it is.
169 uint64_t DiagArgumentsVal[MaxArguments];
170
171 /// The values for the various substitution positions that have
172 /// string arguments.
173 std::string DiagArgumentsStr[MaxArguments];
174
175 /// The list of ranges added to this diagnostic.
176 SmallVector<CharSourceRange, 8> DiagRanges;
177
178 /// If valid, provides a hint with some code to insert, remove, or
179 /// modify at a particular position.
180 SmallVector<FixItHint, 6> FixItHints;
181
182 DiagnosticStorage() = default;
183};
184
185/// Concrete class used by the front-end to report problems and issues.
186///
187/// This massages the diagnostics (e.g. handling things like "report warnings
188/// as errors" and passes them off to the DiagnosticConsumer for reporting to
189/// the user. DiagnosticsEngine is tied to one translation unit and one
190/// SourceManager.
191class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
192public:
193 /// The level of the diagnostic, after it has been through mapping.
194 enum Level {
195 Ignored = DiagnosticIDs::Ignored,
196 Note = DiagnosticIDs::Note,
197 Remark = DiagnosticIDs::Remark,
198 Warning = DiagnosticIDs::Warning,
199 Error = DiagnosticIDs::Error,
200 Fatal = DiagnosticIDs::Fatal
201 };
202
203 enum ArgumentKind {
204 /// std::string
205 ak_std_string,
206
207 /// const char *
208 ak_c_string,
209
210 /// int
211 ak_sint,
212
213 /// unsigned
214 ak_uint,
215
216 /// enum TokenKind : unsigned
217 ak_tokenkind,
218
219 /// IdentifierInfo
220 ak_identifierinfo,
221
222 /// address space
223 ak_addrspace,
224
225 /// Qualifiers
226 ak_qual,
227
228 /// QualType
229 ak_qualtype,
230
231 /// DeclarationName
232 ak_declarationname,
233
234 /// NamedDecl *
235 ak_nameddecl,
236
237 /// NestedNameSpecifier *
238 ak_nestednamespec,
239
240 /// DeclContext *
241 ak_declcontext,
242
243 /// pair<QualType, QualType>
244 ak_qualtype_pair,
245
246 /// Attr *
247 ak_attr
248 };
249
250 /// Represents on argument value, which is a union discriminated
251 /// by ArgumentKind, with a value.
252 using ArgumentValue = std::pair<ArgumentKind, intptr_t>;
253
254private:
255 // Used by __extension__
256 unsigned char AllExtensionsSilenced = 0;
257
258 // Treat fatal errors like errors.
259 bool FatalsAsError = false;
260
261 // Suppress all diagnostics.
262 bool SuppressAllDiagnostics = false;
263
264 // Elide common types of templates.
265 bool ElideType = true;
266
267 // Print a tree when comparing templates.
268 bool PrintTemplateTree = false;
269
270 // Color printing is enabled.
271 bool ShowColors = false;
272
273 // Which overload candidates to show.
274 OverloadsShown ShowOverloads = Ovl_All;
275
276 // With Ovl_Best, the number of overload candidates to show when we encounter
277 // an error.
278 //
279 // The value here is the number of candidates to show in the first nontrivial
280 // error. Future errors may show a different number of candidates.
281 unsigned NumOverloadsToShow = 32;
282
283 // Cap of # errors emitted, 0 -> no limit.
284 unsigned ErrorLimit = 0;
285
286 // Cap on depth of template backtrace stack, 0 -> no limit.
287 unsigned TemplateBacktraceLimit = 0;
288
289 // Cap on depth of constexpr evaluation backtrace stack, 0 -> no limit.
290 unsigned ConstexprBacktraceLimit = 0;
291
292 IntrusiveRefCntPtr<DiagnosticIDs> Diags;
293 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
294 DiagnosticConsumer *Client = nullptr;
295 std::unique_ptr<DiagnosticConsumer> Owner;
296 SourceManager *SourceMgr = nullptr;
297
298 /// Mapping information for diagnostics.
299 ///
300 /// Mapping info is packed into four bits per diagnostic. The low three
301 /// bits are the mapping (an instance of diag::Severity), or zero if unset.
302 /// The high bit is set when the mapping was established as a user mapping.
303 /// If the high bit is clear, then the low bits are set to the default
304 /// value, and should be mapped with -pedantic, -Werror, etc.
305 ///
306 /// A new DiagState is created and kept around when diagnostic pragmas modify
307 /// the state so that we know what is the diagnostic state at any given
308 /// source location.
309 class DiagState {
310 llvm::DenseMap<unsigned, DiagnosticMapping> DiagMap;
311
312 public:
313 // "Global" configuration state that can actually vary between modules.
314
315 // Ignore all warnings: -w
316 unsigned IgnoreAllWarnings : 1;
317
318 // Enable all warnings.
319 unsigned EnableAllWarnings : 1;
320
321 // Treat warnings like errors.
322 unsigned WarningsAsErrors : 1;
323
324 // Treat errors like fatal errors.
325 unsigned ErrorsAsFatal : 1;
326
327 // Suppress warnings in system headers.
328 unsigned SuppressSystemWarnings : 1;
329
330 // Map extensions to warnings or errors?
331 diag::Severity ExtBehavior = diag::Severity::Ignored;
332
333 DiagState()
334 : IgnoreAllWarnings(false), EnableAllWarnings(false),
335 WarningsAsErrors(false), ErrorsAsFatal(false),
336 SuppressSystemWarnings(false) {}
337
338 using iterator = llvm::DenseMap<unsigned, DiagnosticMapping>::iterator;
339 using const_iterator =
340 llvm::DenseMap<unsigned, DiagnosticMapping>::const_iterator;
341
342 void setMapping(diag::kind Diag, DiagnosticMapping Info) {
343 DiagMap[Diag] = Info;
344 }
345
346 DiagnosticMapping lookupMapping(diag::kind Diag) const {
347 return DiagMap.lookup(Diag);
348 }
349
350 DiagnosticMapping &getOrAddMapping(diag::kind Diag);
351
352 const_iterator begin() const { return DiagMap.begin(); }
353 const_iterator end() const { return DiagMap.end(); }
354 };
355
356 /// Keeps and automatically disposes all DiagStates that we create.
357 std::list<DiagState> DiagStates;
358
359 /// A mapping from files to the diagnostic states for those files. Lazily
360 /// built on demand for files in which the diagnostic state has not changed.
361 class DiagStateMap {
362 public:
363 /// Add an initial diagnostic state.
364 void appendFirst(DiagState *State);
365
366 /// Add a new latest state point.
367 void append(SourceManager &SrcMgr, SourceLocation Loc, DiagState *State);
368
369 /// Look up the diagnostic state at a given source location.
370 DiagState *lookup(SourceManager &SrcMgr, SourceLocation Loc) const;
371
372 /// Determine whether this map is empty.
373 bool empty() const { return Files.empty(); }
374
375 /// Clear out this map.
376 void clear() {
377 Files.clear();
378 FirstDiagState = CurDiagState = nullptr;
379 CurDiagStateLoc = SourceLocation();
380 }
381
382 /// Produce a debugging dump of the diagnostic state.
383 LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) void dump(SourceManager &SrcMgr,
384 StringRef DiagName = StringRef()) const;
385
386 /// Grab the most-recently-added state point.
387 DiagState *getCurDiagState() const { return CurDiagState; }
388
389 /// Get the location at which a diagnostic state was last added.
390 SourceLocation getCurDiagStateLoc() const { return CurDiagStateLoc; }
391
392 private:
393 friend class ASTReader;
394 friend class ASTWriter;
395
396 /// Represents a point in source where the diagnostic state was
397 /// modified because of a pragma.
398 ///
399 /// 'Loc' can be null if the point represents the diagnostic state
400 /// modifications done through the command-line.
401 struct DiagStatePoint {
402 DiagState *State;
403 unsigned Offset;
404
405 DiagStatePoint(DiagState *State, unsigned Offset)
406 : State(State), Offset(Offset) {}
407 };
408
409 /// Description of the diagnostic states and state transitions for a
410 /// particular FileID.
411 struct File {
412 /// The diagnostic state for the parent file. This is strictly redundant,
413 /// as looking up the DecomposedIncludedLoc for the FileID in the Files
414 /// map would give us this, but we cache it here for performance.
415 File *Parent = nullptr;
416
417 /// The offset of this file within its parent.
418 unsigned ParentOffset = 0;
419
420 /// Whether this file has any local (not imported from an AST file)
421 /// diagnostic state transitions.
422 bool HasLocalTransitions = false;
423
424 /// The points within the file where the state changes. There will always
425 /// be at least one of these (the state on entry to the file).
426 llvm::SmallVector<DiagStatePoint, 4> StateTransitions;
427
428 DiagState *lookup(unsigned Offset) const;
429 };
430
431 /// The diagnostic states for each file.
432 mutable std::map<FileID, File> Files;
433
434 /// The initial diagnostic state.
435 DiagState *FirstDiagState;
436
437 /// The current diagnostic state.
438 DiagState *CurDiagState;
439
440 /// The location at which the current diagnostic state was established.
441 SourceLocation CurDiagStateLoc;
442
443 /// Get the diagnostic state information for a file.
444 File *getFile(SourceManager &SrcMgr, FileID ID) const;
445 };
446
447 DiagStateMap DiagStatesByLoc;
448
449 /// Keeps the DiagState that was active during each diagnostic 'push'
450 /// so we can get back at it when we 'pop'.
451 std::vector<DiagState *> DiagStateOnPushStack;
452
453 DiagState *GetCurDiagState() const {
454 return DiagStatesByLoc.getCurDiagState();
455 }
456
457 void PushDiagStatePoint(DiagState *State, SourceLocation L);
458
459 /// Finds the DiagStatePoint that contains the diagnostic state of
460 /// the given source location.
461 DiagState *GetDiagStateForLoc(SourceLocation Loc) const {
462 return SourceMgr ? DiagStatesByLoc.lookup(*SourceMgr, Loc)
463 : DiagStatesByLoc.getCurDiagState();
464 }
465
466 /// Sticky flag set to \c true when an error is emitted.
467 bool ErrorOccurred;
468
469 /// Sticky flag set to \c true when an "uncompilable error" occurs.
470 /// I.e. an error that was not upgraded from a warning by -Werror.
471 bool UncompilableErrorOccurred;
472
473 /// Sticky flag set to \c true when a fatal error is emitted.
474 bool FatalErrorOccurred;
475
476 /// Indicates that an unrecoverable error has occurred.
477 bool UnrecoverableErrorOccurred;
478
479 /// Counts for DiagnosticErrorTrap to check whether an error occurred
480 /// during a parsing section, e.g. during parsing a function.
481 unsigned TrapNumErrorsOccurred;
482 unsigned TrapNumUnrecoverableErrorsOccurred;
483
484 /// The level of the last diagnostic emitted.
485 ///
486 /// This is used to emit continuation diagnostics with the same level as the
487 /// diagnostic that they follow.
488 DiagnosticIDs::Level LastDiagLevel;
489
490 /// Number of warnings reported
491 unsigned NumWarnings;
492
493 /// Number of errors reported
494 unsigned NumErrors;
495
496 /// A function pointer that converts an opaque diagnostic
497 /// argument to a strings.
498 ///
499 /// This takes the modifiers and argument that was present in the diagnostic.
500 ///
501 /// The PrevArgs array indicates the previous arguments formatted for this
502 /// diagnostic. Implementations of this function can use this information to
503 /// avoid redundancy across arguments.
504 ///
505 /// This is a hack to avoid a layering violation between libbasic and libsema.
506 using ArgToStringFnTy = void (*)(
507 ArgumentKind Kind, intptr_t Val,
508 StringRef Modifier, StringRef Argument,
509 ArrayRef<ArgumentValue> PrevArgs,
510 SmallVectorImpl<char> &Output,
511 void *Cookie,
512 ArrayRef<intptr_t> QualTypeVals);
513
514 void *ArgToStringCookie = nullptr;
515 ArgToStringFnTy ArgToStringFn;
516
517 /// ID of the "delayed" diagnostic, which is a (typically
518 /// fatal) diagnostic that had to be delayed because it was found
519 /// while emitting another diagnostic.
520 unsigned DelayedDiagID;
521
522 /// First string argument for the delayed diagnostic.
523 std::string DelayedDiagArg1;
524
525 /// Second string argument for the delayed diagnostic.
526 std::string DelayedDiagArg2;
527
528 /// Third string argument for the delayed diagnostic.
529 std::string DelayedDiagArg3;
530
531 /// Optional flag value.
532 ///
533 /// Some flags accept values, for instance: -Wframe-larger-than=<value> and
534 /// -Rpass=<value>. The content of this string is emitted after the flag name
535 /// and '='.
536 std::string FlagValue;
537
538public:
539 explicit DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> Diags,
540 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
541 DiagnosticConsumer *client = nullptr,
542 bool ShouldOwnClient = true);
543 DiagnosticsEngine(const DiagnosticsEngine &) = delete;
544 DiagnosticsEngine &operator=(const DiagnosticsEngine &) = delete;
545 ~DiagnosticsEngine();
546
547 LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) void dump() const;
548 LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) void dump(StringRef DiagName) const;
549
550 const IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const {
551 return Diags;
552 }
553
554 /// Retrieve the diagnostic options.
555 DiagnosticOptions &getDiagnosticOptions() const { return *DiagOpts; }
556
557 using diag_mapping_range = llvm::iterator_range<DiagState::const_iterator>;
558
559 /// Get the current set of diagnostic mappings.
560 diag_mapping_range getDiagnosticMappings() const {
561 const DiagState &DS = *GetCurDiagState();
562 return diag_mapping_range(DS.begin(), DS.end());
563 }
564
565 DiagnosticConsumer *getClient() { return Client; }
566 const DiagnosticConsumer *getClient() const { return Client; }
567
568 /// Determine whether this \c DiagnosticsEngine object own its client.
569 bool ownsClient() const { return Owner != nullptr; }
570
571 /// Return the current diagnostic client along with ownership of that
572 /// client.
573 std::unique_ptr<DiagnosticConsumer> takeClient() { return std::move(Owner); }
574
575 bool hasSourceManager() const { return SourceMgr != nullptr; }
576
577 SourceManager &getSourceManager() const {
578 assert(SourceMgr && "SourceManager not set!")(static_cast <bool> (SourceMgr && "SourceManager not set!"
) ? void (0) : __assert_fail ("SourceMgr && \"SourceManager not set!\""
, "clang/include/clang/Basic/Diagnostic.h", 578, __extension__
__PRETTY_FUNCTION__))
;
579 return *SourceMgr;
580 }
581
582 void setSourceManager(SourceManager *SrcMgr) {
583 assert(DiagStatesByLoc.empty() &&(static_cast <bool> (DiagStatesByLoc.empty() &&
"Leftover diag state from a different SourceManager.") ? void
(0) : __assert_fail ("DiagStatesByLoc.empty() && \"Leftover diag state from a different SourceManager.\""
, "clang/include/clang/Basic/Diagnostic.h", 584, __extension__
__PRETTY_FUNCTION__))
584 "Leftover diag state from a different SourceManager.")(static_cast <bool> (DiagStatesByLoc.empty() &&
"Leftover diag state from a different SourceManager.") ? void
(0) : __assert_fail ("DiagStatesByLoc.empty() && \"Leftover diag state from a different SourceManager.\""
, "clang/include/clang/Basic/Diagnostic.h", 584, __extension__
__PRETTY_FUNCTION__))
;
585 SourceMgr = SrcMgr;
586 }
587
588 //===--------------------------------------------------------------------===//
589 // DiagnosticsEngine characterization methods, used by a client to customize
590 // how diagnostics are emitted.
591 //
592
593 /// Copies the current DiagMappings and pushes the new copy
594 /// onto the top of the stack.
595 void pushMappings(SourceLocation Loc);
596
597 /// Pops the current DiagMappings off the top of the stack,
598 /// causing the new top of the stack to be the active mappings.
599 ///
600 /// \returns \c true if the pop happens, \c false if there is only one
601 /// DiagMapping on the stack.
602 bool popMappings(SourceLocation Loc);
603
604 /// Set the diagnostic client associated with this diagnostic object.
605 ///
606 /// \param ShouldOwnClient true if the diagnostic object should take
607 /// ownership of \c client.
608 void setClient(DiagnosticConsumer *client, bool ShouldOwnClient = true);
609
610 /// Specify a limit for the number of errors we should
611 /// emit before giving up.
612 ///
613 /// Zero disables the limit.
614 void setErrorLimit(unsigned Limit) { ErrorLimit = Limit; }
615
616 /// Specify the maximum number of template instantiation
617 /// notes to emit along with a given diagnostic.
618 void setTemplateBacktraceLimit(unsigned Limit) {
619 TemplateBacktraceLimit = Limit;
620 }
621
622 /// Retrieve the maximum number of template instantiation
623 /// notes to emit along with a given diagnostic.
624 unsigned getTemplateBacktraceLimit() const {
625 return TemplateBacktraceLimit;
626 }
627
628 /// Specify the maximum number of constexpr evaluation
629 /// notes to emit along with a given diagnostic.
630 void setConstexprBacktraceLimit(unsigned Limit) {
631 ConstexprBacktraceLimit = Limit;
632 }
633
634 /// Retrieve the maximum number of constexpr evaluation
635 /// notes to emit along with a given diagnostic.
636 unsigned getConstexprBacktraceLimit() const {
637 return ConstexprBacktraceLimit;
638 }
639
640 /// When set to true, any unmapped warnings are ignored.
641 ///
642 /// If this and WarningsAsErrors are both set, then this one wins.
643 void setIgnoreAllWarnings(bool Val) {
644 GetCurDiagState()->IgnoreAllWarnings = Val;
645 }
646 bool getIgnoreAllWarnings() const {
647 return GetCurDiagState()->IgnoreAllWarnings;
648 }
649
650 /// When set to true, any unmapped ignored warnings are no longer
651 /// ignored.
652 ///
653 /// If this and IgnoreAllWarnings are both set, then that one wins.
654 void setEnableAllWarnings(bool Val) {
655 GetCurDiagState()->EnableAllWarnings = Val;
656 }
657 bool getEnableAllWarnings() const {
658 return GetCurDiagState()->EnableAllWarnings;
659 }
660
661 /// When set to true, any warnings reported are issued as errors.
662 void setWarningsAsErrors(bool Val) {
663 GetCurDiagState()->WarningsAsErrors = Val;
664 }
665 bool getWarningsAsErrors() const {
666 return GetCurDiagState()->WarningsAsErrors;
667 }
668
669 /// When set to true, any error reported is made a fatal error.
670 void setErrorsAsFatal(bool Val) { GetCurDiagState()->ErrorsAsFatal = Val; }
671 bool getErrorsAsFatal() const { return GetCurDiagState()->ErrorsAsFatal; }
672
673 /// \brief When set to true, any fatal error reported is made an error.
674 ///
675 /// This setting takes precedence over the setErrorsAsFatal setting above.
676 void setFatalsAsError(bool Val) { FatalsAsError = Val; }
677 bool getFatalsAsError() const { return FatalsAsError; }
678
679 /// When set to true mask warnings that come from system headers.
680 void setSuppressSystemWarnings(bool Val) {
681 GetCurDiagState()->SuppressSystemWarnings = Val;
682 }
683 bool getSuppressSystemWarnings() const {
684 return GetCurDiagState()->SuppressSystemWarnings;
685 }
686
687 /// Suppress all diagnostics, to silence the front end when we
688 /// know that we don't want any more diagnostics to be passed along to the
689 /// client
690 void setSuppressAllDiagnostics(bool Val) { SuppressAllDiagnostics = Val; }
691 bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; }
692
693 /// Set type eliding, to skip outputting same types occurring in
694 /// template types.
695 void setElideType(bool Val) { ElideType = Val; }
696 bool getElideType() { return ElideType; }
697
698 /// Set tree printing, to outputting the template difference in a
699 /// tree format.
700 void setPrintTemplateTree(bool Val) { PrintTemplateTree = Val; }
701 bool getPrintTemplateTree() { return PrintTemplateTree; }
702
703 /// Set color printing, so the type diffing will inject color markers
704 /// into the output.
705 void setShowColors(bool Val) { ShowColors = Val; }
706 bool getShowColors() { return ShowColors; }
707
708 /// Specify which overload candidates to show when overload resolution
709 /// fails.
710 ///
711 /// By default, we show all candidates.
712 void setShowOverloads(OverloadsShown Val) {
713 ShowOverloads = Val;
714 }
715 OverloadsShown getShowOverloads() const { return ShowOverloads; }
716
717 /// When a call or operator fails, print out up to this many candidate
718 /// overloads as suggestions.
719 ///
720 /// With Ovl_Best, we set a high limit for the first nontrivial overload set
721 /// we print, and a lower limit for later sets. This way the user has a
722 /// chance of diagnosing at least one callsite in their program without
723 /// having to recompile with -fshow-overloads=all.
724 unsigned getNumOverloadCandidatesToShow() const {
725 switch (getShowOverloads()) {
726 case Ovl_All:
727 // INT_MAX rather than UINT_MAX so that we don't have to think about the
728 // effect of implicit conversions on this value. In practice we'll never
729 // hit 2^31 candidates anyway.
730 return std::numeric_limits<int>::max();
731 case Ovl_Best:
732 return NumOverloadsToShow;
733 }
734 llvm_unreachable("invalid OverloadsShown kind")::llvm::llvm_unreachable_internal("invalid OverloadsShown kind"
, "clang/include/clang/Basic/Diagnostic.h", 734)
;
735 }
736
737 /// Call this after showing N overload candidates. This influences the value
738 /// returned by later calls to getNumOverloadCandidatesToShow().
739 void overloadCandidatesShown(unsigned N) {
740 // Current heuristic: Start out with a large value for NumOverloadsToShow,
741 // and then once we print one nontrivially-large overload set, decrease it
742 // for future calls.
743 if (N > 4) {
744 NumOverloadsToShow = 4;
745 }
746 }
747
748 /// Pretend that the last diagnostic issued was ignored, so any
749 /// subsequent notes will be suppressed, or restore a prior ignoring
750 /// state after ignoring some diagnostics and their notes, possibly in
751 /// the middle of another diagnostic.
752 ///
753 /// This can be used by clients who suppress diagnostics themselves.
754 void setLastDiagnosticIgnored(bool Ignored) {
755 if (LastDiagLevel == DiagnosticIDs::Fatal)
756 FatalErrorOccurred = true;
757 LastDiagLevel = Ignored ? DiagnosticIDs::Ignored : DiagnosticIDs::Warning;
758 }
759
760 /// Determine whether the previous diagnostic was ignored. This can
761 /// be used by clients that want to determine whether notes attached to a
762 /// diagnostic will be suppressed.
763 bool isLastDiagnosticIgnored() const {
764 return LastDiagLevel == DiagnosticIDs::Ignored;
765 }
766
767 /// Controls whether otherwise-unmapped extension diagnostics are
768 /// mapped onto ignore/warning/error.
769 ///
770 /// This corresponds to the GCC -pedantic and -pedantic-errors option.
771 void setExtensionHandlingBehavior(diag::Severity H) {
772 GetCurDiagState()->ExtBehavior = H;
773 }
774 diag::Severity getExtensionHandlingBehavior() const {
775 return GetCurDiagState()->ExtBehavior;
776 }
777
778 /// Counter bumped when an __extension__ block is/ encountered.
779 ///
780 /// When non-zero, all extension diagnostics are entirely silenced, no
781 /// matter how they are mapped.
782 void IncrementAllExtensionsSilenced() { ++AllExtensionsSilenced; }
783 void DecrementAllExtensionsSilenced() { --AllExtensionsSilenced; }
784 bool hasAllExtensionsSilenced() { return AllExtensionsSilenced != 0; }
785
786 /// This allows the client to specify that certain warnings are
787 /// ignored.
788 ///
789 /// Notes can never be mapped, errors can only be mapped to fatal, and
790 /// WARNINGs and EXTENSIONs can be mapped arbitrarily.
791 ///
792 /// \param Loc The source location that this change of diagnostic state should
793 /// take affect. It can be null if we are setting the latest state.
794 void setSeverity(diag::kind Diag, diag::Severity Map, SourceLocation Loc);
795
796 /// Change an entire diagnostic group (e.g. "unknown-pragmas") to
797 /// have the specified mapping.
798 ///
799 /// \returns true (and ignores the request) if "Group" was unknown, false
800 /// otherwise.
801 ///
802 /// \param Flavor The flavor of group to affect. -Rfoo does not affect the
803 /// state of the -Wfoo group and vice versa.
804 ///
805 /// \param Loc The source location that this change of diagnostic state should
806 /// take affect. It can be null if we are setting the state from command-line.
807 bool setSeverityForGroup(diag::Flavor Flavor, StringRef Group,
808 diag::Severity Map,
809 SourceLocation Loc = SourceLocation());
810 bool setSeverityForGroup(diag::Flavor Flavor, diag::Group Group,
811 diag::Severity Map,
812 SourceLocation Loc = SourceLocation());
813
814 /// Set the warning-as-error flag for the given diagnostic group.
815 ///
816 /// This function always only operates on the current diagnostic state.
817 ///
818 /// \returns True if the given group is unknown, false otherwise.
819 bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled);
820
821 /// Set the error-as-fatal flag for the given diagnostic group.
822 ///
823 /// This function always only operates on the current diagnostic state.
824 ///
825 /// \returns True if the given group is unknown, false otherwise.
826 bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled);
827
828 /// Add the specified mapping to all diagnostics of the specified
829 /// flavor.
830 ///
831 /// Mainly to be used by -Wno-everything to disable all warnings but allow
832 /// subsequent -W options to enable specific warnings.
833 void setSeverityForAll(diag::Flavor Flavor, diag::Severity Map,
834 SourceLocation Loc = SourceLocation());
835
836 bool hasErrorOccurred() const { return ErrorOccurred; }
837
838 /// Errors that actually prevent compilation, not those that are
839 /// upgraded from a warning by -Werror.
840 bool hasUncompilableErrorOccurred() const {
841 return UncompilableErrorOccurred;
842 }
843 bool hasFatalErrorOccurred() const { return FatalErrorOccurred; }
844
845 /// Determine whether any kind of unrecoverable error has occurred.
846 bool hasUnrecoverableErrorOccurred() const {
847 return FatalErrorOccurred || UnrecoverableErrorOccurred;
848 }
849
850 unsigned getNumErrors() const { return NumErrors; }
851 unsigned getNumWarnings() const { return NumWarnings; }
852
853 void setNumWarnings(unsigned NumWarnings) {
854 this->NumWarnings = NumWarnings;
855 }
856
857 /// Return an ID for a diagnostic with the specified format string and
858 /// level.
859 ///
860 /// If this is the first request for this diagnostic, it is registered and
861 /// created, otherwise the existing ID is returned.
862 ///
863 /// \param FormatString A fixed diagnostic format string that will be hashed
864 /// and mapped to a unique DiagID.
865 template <unsigned N>
866 unsigned getCustomDiagID(Level L, const char (&FormatString)[N]) {
867 return Diags->getCustomDiagID((DiagnosticIDs::Level)L,
868 StringRef(FormatString, N - 1));
869 }
870
871 /// Converts a diagnostic argument (as an intptr_t) into the string
872 /// that represents it.
873 void ConvertArgToString(ArgumentKind Kind, intptr_t Val,
874 StringRef Modifier, StringRef Argument,
875 ArrayRef<ArgumentValue> PrevArgs,
876 SmallVectorImpl<char> &Output,
877 ArrayRef<intptr_t> QualTypeVals) const {
878 ArgToStringFn(Kind, Val, Modifier, Argument, PrevArgs, Output,
879 ArgToStringCookie, QualTypeVals);
880 }
881
882 void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) {
883 ArgToStringFn = Fn;
884 ArgToStringCookie = Cookie;
885 }
886
887 /// Note that the prior diagnostic was emitted by some other
888 /// \c DiagnosticsEngine, and we may be attaching a note to that diagnostic.
889 void notePriorDiagnosticFrom(const DiagnosticsEngine &Other) {
890 LastDiagLevel = Other.LastDiagLevel;
891 }
892
893 /// Reset the state of the diagnostic object to its initial
894 /// configuration.
895 void Reset();
896
897 //===--------------------------------------------------------------------===//
898 // DiagnosticsEngine classification and reporting interfaces.
899 //
900
901 /// Determine whether the diagnostic is known to be ignored.
902 ///
903 /// This can be used to opportunistically avoid expensive checks when it's
904 /// known for certain that the diagnostic has been suppressed at the
905 /// specified location \p Loc.
906 ///
907 /// \param Loc The source location we are interested in finding out the
908 /// diagnostic state. Can be null in order to query the latest state.
909 bool isIgnored(unsigned DiagID, SourceLocation Loc) const {
910 return Diags->getDiagnosticSeverity(DiagID, Loc, *this) ==
911 diag::Severity::Ignored;
912 }
913
914 /// Based on the way the client configured the DiagnosticsEngine
915 /// object, classify the specified diagnostic ID into a Level, consumable by
916 /// the DiagnosticConsumer.
917 ///
918 /// To preserve invariant assumptions, this function should not be used to
919 /// influence parse or semantic analysis actions. Instead consider using
920 /// \c isIgnored().
921 ///
922 /// \param Loc The source location we are interested in finding out the
923 /// diagnostic state. Can be null in order to query the latest state.
924 Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const {
925 return (Level)Diags->getDiagnosticLevel(DiagID, Loc, *this);
926 }
927
928 /// Issue the message to the client.
929 ///
930 /// This actually returns an instance of DiagnosticBuilder which emits the
931 /// diagnostics (through @c ProcessDiag) when it is destroyed.
932 ///
933 /// \param DiagID A member of the @c diag::kind enum.
934 /// \param Loc Represents the source location associated with the diagnostic,
935 /// which can be an invalid location if no position information is available.
936 inline DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID);
937 inline DiagnosticBuilder Report(unsigned DiagID);
938
939 void Report(const StoredDiagnostic &storedDiag);
940
941 /// Determine whethere there is already a diagnostic in flight.
942 bool isDiagnosticInFlight() const {
943 return CurDiagID != std::numeric_limits<unsigned>::max();
944 }
945
946 /// Set the "delayed" diagnostic that will be emitted once
947 /// the current diagnostic completes.
948 ///
949 /// If a diagnostic is already in-flight but the front end must
950 /// report a problem (e.g., with an inconsistent file system
951 /// state), this routine sets a "delayed" diagnostic that will be
952 /// emitted after the current diagnostic completes. This should
953 /// only be used for fatal errors detected at inconvenient
954 /// times. If emitting a delayed diagnostic causes a second delayed
955 /// diagnostic to be introduced, that second delayed diagnostic
956 /// will be ignored.
957 ///
958 /// \param DiagID The ID of the diagnostic being delayed.
959 ///
960 /// \param Arg1 A string argument that will be provided to the
961 /// diagnostic. A copy of this string will be stored in the
962 /// DiagnosticsEngine object itself.
963 ///
964 /// \param Arg2 A string argument that will be provided to the
965 /// diagnostic. A copy of this string will be stored in the
966 /// DiagnosticsEngine object itself.
967 ///
968 /// \param Arg3 A string argument that will be provided to the
969 /// diagnostic. A copy of this string will be stored in the
970 /// DiagnosticsEngine object itself.
971 void SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1 = "",
972 StringRef Arg2 = "", StringRef Arg3 = "");
973
974 /// Clear out the current diagnostic.
975 void Clear() { CurDiagID = std::numeric_limits<unsigned>::max(); }
976
977 /// Return the value associated with this diagnostic flag.
978 StringRef getFlagValue() const { return FlagValue; }
979
980private:
981 // This is private state used by DiagnosticBuilder. We put it here instead of
982 // in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight
983 // object. This implementation choice means that we can only have one
984 // diagnostic "in flight" at a time, but this seems to be a reasonable
985 // tradeoff to keep these objects small. Assertions verify that only one
986 // diagnostic is in flight at a time.
987 friend class Diagnostic;
988 friend class DiagnosticBuilder;
989 friend class DiagnosticErrorTrap;
990 friend class DiagnosticIDs;
991 friend class PartialDiagnostic;
992
993 /// Report the delayed diagnostic.
994 void ReportDelayed();
995
996 /// The location of the current diagnostic that is in flight.
997 SourceLocation CurDiagLoc;
998
999 /// The ID of the current diagnostic that is in flight.
1000 ///
1001 /// This is set to std::numeric_limits<unsigned>::max() when there is no
1002 /// diagnostic in flight.
1003 unsigned CurDiagID;
1004
1005 enum {
1006 /// The maximum number of arguments we can hold.
1007 ///
1008 /// We currently only support up to 10 arguments (%0-%9). A single
1009 /// diagnostic with more than that almost certainly has to be simplified
1010 /// anyway.
1011 MaxArguments = DiagnosticStorage::MaxArguments,
1012 };
1013
1014 DiagnosticStorage DiagStorage;
1015
1016 DiagnosticMapping makeUserMapping(diag::Severity Map, SourceLocation L) {
1017 bool isPragma = L.isValid();
1018 DiagnosticMapping Mapping =
1019 DiagnosticMapping::Make(Map, /*IsUser=*/true, isPragma);
1020
1021 // If this is a pragma mapping, then set the diagnostic mapping flags so
1022 // that we override command line options.
1023 if (isPragma) {
1024 Mapping.setNoWarningAsError(true);
1025 Mapping.setNoErrorAsFatal(true);
1026 }
1027
1028 return Mapping;
1029 }
1030
1031 /// Used to report a diagnostic that is finally fully formed.
1032 ///
1033 /// \returns true if the diagnostic was emitted, false if it was suppressed.
1034 bool ProcessDiag() {
1035 return Diags->ProcessDiag(*this);
1036 }
1037
1038 /// @name Diagnostic Emission
1039 /// @{
1040protected:
1041 friend class ASTReader;
1042 friend class ASTWriter;
1043
1044 // Sema requires access to the following functions because the current design
1045 // of SFINAE requires it to use its own SemaDiagnosticBuilder, which needs to
1046 // access us directly to ensure we minimize the emitted code for the common
1047 // Sema::Diag() patterns.
1048 friend class Sema;
1049
1050 /// Emit the current diagnostic and clear the diagnostic state.
1051 ///
1052 /// \param Force Emit the diagnostic regardless of suppression settings.
1053 bool EmitCurrentDiagnostic(bool Force = false);
1054
1055 unsigned getCurrentDiagID() const { return CurDiagID; }
1056
1057 SourceLocation getCurrentDiagLoc() const { return CurDiagLoc; }
1058
1059 /// @}
1060};
1061
1062/// RAII class that determines when any errors have occurred
1063/// between the time the instance was created and the time it was
1064/// queried.
1065///
1066/// Note that you almost certainly do not want to use this. It's usually
1067/// meaningless to ask whether a particular scope triggered an error message,
1068/// because error messages outside that scope can mark things invalid (or cause
1069/// us to reach an error limit), which can suppress errors within that scope.
1070class DiagnosticErrorTrap {
1071 DiagnosticsEngine &Diag;
1072 unsigned NumErrors;
1073 unsigned NumUnrecoverableErrors;
1074
1075public:
1076 explicit DiagnosticErrorTrap(DiagnosticsEngine &Diag)
1077 : Diag(Diag) { reset(); }
1078
1079 /// Determine whether any errors have occurred since this
1080 /// object instance was created.
1081 bool hasErrorOccurred() const {
1082 return Diag.TrapNumErrorsOccurred > NumErrors;
1083 }
1084
1085 /// Determine whether any unrecoverable errors have occurred since this
1086 /// object instance was created.
1087 bool hasUnrecoverableErrorOccurred() const {
1088 return Diag.TrapNumUnrecoverableErrorsOccurred > NumUnrecoverableErrors;
1089 }
1090
1091 /// Set to initial state of "no errors occurred".
1092 void reset() {
1093 NumErrors = Diag.TrapNumErrorsOccurred;
1094 NumUnrecoverableErrors = Diag.TrapNumUnrecoverableErrorsOccurred;
1095 }
1096};
1097
1098/// The streaming interface shared between DiagnosticBuilder and
1099/// PartialDiagnostic. This class is not intended to be constructed directly
1100/// but only as base class of DiagnosticBuilder and PartialDiagnostic builder.
1101///
1102/// Any new type of argument accepted by DiagnosticBuilder and PartialDiagnostic
1103/// should be implemented as a '<<' operator of StreamingDiagnostic, e.g.
1104///
1105/// const StreamingDiagnostic&
1106/// operator<<(const StreamingDiagnostic&, NewArgType);
1107///
1108class StreamingDiagnostic {
1109public:
1110 /// An allocator for DiagnosticStorage objects, which uses a small cache to
1111 /// objects, used to reduce malloc()/free() traffic for partial diagnostics.
1112 class DiagStorageAllocator {
1113 static const unsigned NumCached = 16;
1114 DiagnosticStorage Cached[NumCached];
1115 DiagnosticStorage *FreeList[NumCached];
1116 unsigned NumFreeListEntries;
1117
1118 public:
1119 DiagStorageAllocator();
1120 ~DiagStorageAllocator();
1121
1122 /// Allocate new storage.
1123 DiagnosticStorage *Allocate() {
1124 if (NumFreeListEntries == 0)
1125 return new DiagnosticStorage;
1126
1127 DiagnosticStorage *Result = FreeList[--NumFreeListEntries];
1128 Result->NumDiagArgs = 0;
1129 Result->DiagRanges.clear();
1130 Result->FixItHints.clear();
1131 return Result;
1132 }
1133
1134 /// Free the given storage object.
1135 void Deallocate(DiagnosticStorage *S) {
1136 if (S >= Cached && S <= Cached + NumCached) {
33
Assuming 'S' is < field 'Cached'
1137 FreeList[NumFreeListEntries++] = S;
1138 return;
1139 }
1140
1141 delete S;
34
Memory is released
1142 }
1143 };
1144
1145protected:
1146 mutable DiagnosticStorage *DiagStorage = nullptr;
1147
1148 /// Allocator used to allocate storage for this diagnostic.
1149 DiagStorageAllocator *Allocator = nullptr;
1150
1151public:
1152 /// Retrieve storage for this particular diagnostic.
1153 DiagnosticStorage *getStorage() const {
1154 if (DiagStorage)
1155 return DiagStorage;
1156
1157 assert(Allocator)(static_cast <bool> (Allocator) ? void (0) : __assert_fail
("Allocator", "clang/include/clang/Basic/Diagnostic.h", 1157
, __extension__ __PRETTY_FUNCTION__))
;
1158 DiagStorage = Allocator->Allocate();
1159 return DiagStorage;
1160 }
1161
1162 void freeStorage() {
1163 if (!DiagStorage
27.1
Field 'DiagStorage' is non-null
27.1
Field 'DiagStorage' is non-null
)
28
Taking false branch
1164 return;
1165
1166 // The hot path for PartialDiagnostic is when we just used it to wrap an ID
1167 // (typically so we have the flexibility of passing a more complex
1168 // diagnostic into the callee, but that does not commonly occur).
1169 //
1170 // Split this out into a slow function for silly compilers (*cough*) which
1171 // can't do decent partial inlining.
1172 freeStorageSlow();
29
Calling 'StreamingDiagnostic::freeStorageSlow'
36
Returning; memory was released
1173 }
1174
1175 void freeStorageSlow() {
1176 if (!Allocator)
30
Assuming field 'Allocator' is non-null
31
Taking false branch
1177 return;
1178 Allocator->Deallocate(DiagStorage);
32
Calling 'DiagStorageAllocator::Deallocate'
35
Returning; memory was released via 1st parameter
1179 DiagStorage = nullptr;
1180 }
1181
1182 void AddTaggedVal(uint64_t V, DiagnosticsEngine::ArgumentKind Kind) const {
1183 if (!DiagStorage)
18
Assuming field 'DiagStorage' is non-null
1184 DiagStorage = getStorage();
1185
1186 assert(DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments &&(static_cast <bool> (DiagStorage->NumDiagArgs < DiagnosticStorage
::MaxArguments && "Too many arguments to diagnostic!"
) ? void (0) : __assert_fail ("DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments && \"Too many arguments to diagnostic!\""
, "clang/include/clang/Basic/Diagnostic.h", 1187, __extension__
__PRETTY_FUNCTION__))
19
Taking false branch
20
Assuming field 'NumDiagArgs' is < MaxArguments
21
'?' condition is true
1187 "Too many arguments to diagnostic!")(static_cast <bool> (DiagStorage->NumDiagArgs < DiagnosticStorage
::MaxArguments && "Too many arguments to diagnostic!"
) ? void (0) : __assert_fail ("DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments && \"Too many arguments to diagnostic!\""
, "clang/include/clang/Basic/Diagnostic.h", 1187, __extension__
__PRETTY_FUNCTION__))
;
1188 DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind;
1189 DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
1190 }
1191
1192 void AddString(StringRef V) const {
1193 if (!DiagStorage
44.1
Field 'DiagStorage' is non-null
44.1
Field 'DiagStorage' is non-null
)
1194 DiagStorage = getStorage();
1195
1196 assert(DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments &&(static_cast <bool> (DiagStorage->NumDiagArgs < DiagnosticStorage
::MaxArguments && "Too many arguments to diagnostic!"
) ? void (0) : __assert_fail ("DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments && \"Too many arguments to diagnostic!\""
, "clang/include/clang/Basic/Diagnostic.h", 1197, __extension__
__PRETTY_FUNCTION__))
45
Taking false branch
46
Use of memory after it is freed
1197 "Too many arguments to diagnostic!")(static_cast <bool> (DiagStorage->NumDiagArgs < DiagnosticStorage
::MaxArguments && "Too many arguments to diagnostic!"
) ? void (0) : __assert_fail ("DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments && \"Too many arguments to diagnostic!\""
, "clang/include/clang/Basic/Diagnostic.h", 1197, __extension__
__PRETTY_FUNCTION__))
;
1198 DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] =
1199 DiagnosticsEngine::ak_std_string;
1200 DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = std::string(V);
1201 }
1202
1203 void AddSourceRange(const CharSourceRange &R) const {
1204 if (!DiagStorage)
1205 DiagStorage = getStorage();
1206
1207 DiagStorage->DiagRanges.push_back(R);
1208 }
1209
1210 void AddFixItHint(const FixItHint &Hint) const {
1211 if (Hint.isNull())
1212 return;
1213
1214 if (!DiagStorage)
1215 DiagStorage = getStorage();
1216
1217 DiagStorage->FixItHints.push_back(Hint);
1218 }
1219
1220 /// Conversion of StreamingDiagnostic to bool always returns \c true.
1221 ///
1222 /// This allows is to be used in boolean error contexts (where \c true is
1223 /// used to indicate that an error has occurred), like:
1224 /// \code
1225 /// return Diag(...);
1226 /// \endcode
1227 operator bool() const { return true; }
1228
1229protected:
1230 StreamingDiagnostic() = default;
1231
1232 /// Construct with an external storage not owned by itself. The allocator
1233 /// is a null pointer in this case.
1234 explicit StreamingDiagnostic(DiagnosticStorage *Storage)
1235 : DiagStorage(Storage) {}
1236
1237 /// Construct with a storage allocator which will manage the storage. The
1238 /// allocator is not a null pointer in this case.
1239 explicit StreamingDiagnostic(DiagStorageAllocator &Alloc)
1240 : Allocator(&Alloc) {}
1241
1242 StreamingDiagnostic(const StreamingDiagnostic &Diag) = default;
1243 StreamingDiagnostic(StreamingDiagnostic &&Diag) = default;
1244
1245 ~StreamingDiagnostic() { freeStorage(); }
27
Calling 'StreamingDiagnostic::freeStorage'
37
Returning; memory was released
1246};
1247
1248//===----------------------------------------------------------------------===//
1249// DiagnosticBuilder
1250//===----------------------------------------------------------------------===//
1251
1252/// A little helper class used to produce diagnostics.
1253///
1254/// This is constructed by the DiagnosticsEngine::Report method, and
1255/// allows insertion of extra information (arguments and source ranges) into
1256/// the currently "in flight" diagnostic. When the temporary for the builder
1257/// is destroyed, the diagnostic is issued.
1258///
1259/// Note that many of these will be created as temporary objects (many call
1260/// sites), so we want them to be small and we never want their address taken.
1261/// This ensures that compilers with somewhat reasonable optimizers will promote
1262/// the common fields to registers, eliminating increments of the NumArgs field,
1263/// for example.
1264class DiagnosticBuilder : public StreamingDiagnostic {
1265 friend class DiagnosticsEngine;
1266 friend class PartialDiagnostic;
1267
1268 mutable DiagnosticsEngine *DiagObj = nullptr;
1269
1270 /// Status variable indicating if this diagnostic is still active.
1271 ///
1272 // NOTE: This field is redundant with DiagObj (IsActive iff (DiagObj == 0)),
1273 // but LLVM is not currently smart enough to eliminate the null check that
1274 // Emit() would end up with if we used that as our status variable.
1275 mutable bool IsActive = false;
1276
1277 /// Flag indicating that this diagnostic is being emitted via a
1278 /// call to ForceEmit.
1279 mutable bool IsForceEmit = false;
1280
1281 DiagnosticBuilder() = default;
1282
1283 explicit DiagnosticBuilder(DiagnosticsEngine *diagObj)
1284 : StreamingDiagnostic(&diagObj->DiagStorage), DiagObj(diagObj),
1285 IsActive(true) {
1286 assert(diagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!")(static_cast <bool> (diagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!"
) ? void (0) : __assert_fail ("diagObj && \"DiagnosticBuilder requires a valid DiagnosticsEngine!\""
, "clang/include/clang/Basic/Diagnostic.h", 1286, __extension__
__PRETTY_FUNCTION__))
;
1287 assert(DiagStorage &&(static_cast <bool> (DiagStorage && "DiagnosticBuilder requires a valid DiagnosticStorage!"
) ? void (0) : __assert_fail ("DiagStorage && \"DiagnosticBuilder requires a valid DiagnosticStorage!\""
, "clang/include/clang/Basic/Diagnostic.h", 1288, __extension__
__PRETTY_FUNCTION__))
1288 "DiagnosticBuilder requires a valid DiagnosticStorage!")(static_cast <bool> (DiagStorage && "DiagnosticBuilder requires a valid DiagnosticStorage!"
) ? void (0) : __assert_fail ("DiagStorage && \"DiagnosticBuilder requires a valid DiagnosticStorage!\""
, "clang/include/clang/Basic/Diagnostic.h", 1288, __extension__
__PRETTY_FUNCTION__))
;
1289 DiagStorage->NumDiagArgs = 0;
1290 DiagStorage->DiagRanges.clear();
1291 DiagStorage->FixItHints.clear();
1292 }
1293
1294protected:
1295 /// Clear out the current diagnostic.
1296 void Clear() const {
1297 DiagObj = nullptr;
1298 IsActive = false;
1299 IsForceEmit = false;
1300 }
1301
1302 /// Determine whether this diagnostic is still active.
1303 bool isActive() const { return IsActive; }
1304
1305 /// Force the diagnostic builder to emit the diagnostic now.
1306 ///
1307 /// Once this function has been called, the DiagnosticBuilder object
1308 /// should not be used again before it is destroyed.
1309 ///
1310 /// \returns true if a diagnostic was emitted, false if the
1311 /// diagnostic was suppressed.
1312 bool Emit() {
1313 // If this diagnostic is inactive, then its soul was stolen by the copy ctor
1314 // (or by a subclass, as in SemaDiagnosticBuilder).
1315 if (!isActive()) return false;
1316
1317 // Process the diagnostic.
1318 bool Result = DiagObj->EmitCurrentDiagnostic(IsForceEmit);
1319
1320 // This diagnostic is dead.
1321 Clear();
1322
1323 return Result;
1324 }
1325
1326public:
1327 /// Copy constructor. When copied, this "takes" the diagnostic info from the
1328 /// input and neuters it.
1329 DiagnosticBuilder(const DiagnosticBuilder &D) : StreamingDiagnostic() {
1330 DiagObj = D.DiagObj;
1331 DiagStorage = D.DiagStorage;
1332 IsActive = D.IsActive;
1333 IsForceEmit = D.IsForceEmit;
1334 D.Clear();
1335 }
1336
1337 template <typename T> const DiagnosticBuilder &operator<<(const T &V) const {
1338 assert(isActive() && "Clients must not add to cleared diagnostic!")(static_cast <bool> (isActive() && "Clients must not add to cleared diagnostic!"
) ? void (0) : __assert_fail ("isActive() && \"Clients must not add to cleared diagnostic!\""
, "clang/include/clang/Basic/Diagnostic.h", 1338, __extension__
__PRETTY_FUNCTION__))
;
42
'?' condition is true
1339 const StreamingDiagnostic &DB = *this;
1340 DB << V;
43
Calling 'operator<<'
1341 return *this;
1342 }
1343
1344 // It is necessary to limit this to rvalue reference to avoid calling this
1345 // function with a bitfield lvalue argument since non-const reference to
1346 // bitfield is not allowed.
1347 template <typename T, typename = typename std::enable_if<
1348 !std::is_lvalue_reference<T>::value>::type>
1349 const DiagnosticBuilder &operator<<(T &&V) const {
1350 assert(isActive() && "Clients must not add to cleared diagnostic!")(static_cast <bool> (isActive() && "Clients must not add to cleared diagnostic!"
) ? void (0) : __assert_fail ("isActive() && \"Clients must not add to cleared diagnostic!\""
, "clang/include/clang/Basic/Diagnostic.h", 1350, __extension__
__PRETTY_FUNCTION__))
;
14
Assuming the condition is true
15
'?' condition is true
1351 const StreamingDiagnostic &DB = *this;
1352 DB << std::move(V);
16
Calling 'operator<<'
23
Returning from 'operator<<'
1353 return *this;
1354 }
1355
1356 DiagnosticBuilder &operator=(const DiagnosticBuilder &) = delete;
1357
1358 /// Emits the diagnostic.
1359 ~DiagnosticBuilder() { Emit(); }
26
Calling '~StreamingDiagnostic'
38
Returning from '~StreamingDiagnostic'
1360
1361 /// Forces the diagnostic to be emitted.
1362 const DiagnosticBuilder &setForceEmit() const {
1363 IsForceEmit = true;
1364 return *this;
1365 }
1366
1367 void addFlagValue(StringRef V) const { DiagObj->FlagValue = std::string(V); }
1368};
1369
1370struct AddFlagValue {
1371 StringRef Val;
1372
1373 explicit AddFlagValue(StringRef V) : Val(V) {}
1374};
1375
1376/// Register a value for the flag in the current diagnostic. This
1377/// value will be shown as the suffix "=value" after the flag name. It is
1378/// useful in cases where the diagnostic flag accepts values (e.g.,
1379/// -Rpass or -Wframe-larger-than).
1380inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1381 const AddFlagValue V) {
1382 DB.addFlagValue(V.Val);
1383 return DB;
1384}
1385
1386inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1387 StringRef S) {
1388 DB.AddString(S);
44
Calling 'StreamingDiagnostic::AddString'
1389 return DB;
1390}
1391
1392inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1393 const char *Str) {
1394 DB.AddTaggedVal(reinterpret_cast<intptr_t>(Str),
1395 DiagnosticsEngine::ak_c_string);
1396 return DB;
1397}
1398
1399inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1400 int I) {
1401 DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
1402 return DB;
1403}
1404
1405inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1406 int64_t I) {
1407 DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
1408 return DB;
1409}
1410
1411// We use enable_if here to prevent that this overload is selected for
1412// pointers or other arguments that are implicitly convertible to bool.
1413template <typename T>
1414inline std::enable_if_t<std::is_same<T, bool>::value,
1415 const StreamingDiagnostic &>
1416operator<<(const StreamingDiagnostic &DB, T I) {
1417 DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
1418 return DB;
1419}
1420
1421inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1422 unsigned I) {
1423 DB.AddTaggedVal(I, DiagnosticsEngine::ak_uint);
17
Calling 'StreamingDiagnostic::AddTaggedVal'
22
Returning from 'StreamingDiagnostic::AddTaggedVal'
1424 return DB;
1425}
1426
1427inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1428 uint64_t I) {
1429 DB.AddTaggedVal(I, DiagnosticsEngine::ak_uint);
1430 return DB;
1431}
1432
1433inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1434 tok::TokenKind I) {
1435 DB.AddTaggedVal(static_cast<unsigned>(I), DiagnosticsEngine::ak_tokenkind);
1436 return DB;
1437}
1438
1439inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1440 const IdentifierInfo *II) {
1441 DB.AddTaggedVal(reinterpret_cast<intptr_t>(II),
1442 DiagnosticsEngine::ak_identifierinfo);
1443 return DB;
1444}
1445
1446// Adds a DeclContext to the diagnostic. The enable_if template magic is here
1447// so that we only match those arguments that are (statically) DeclContexts;
1448// other arguments that derive from DeclContext (e.g., RecordDecls) will not
1449// match.
1450template <typename T>
1451inline std::enable_if_t<
1452 std::is_same<std::remove_const_t<T>, DeclContext>::value,
1453 const StreamingDiagnostic &>
1454operator<<(const StreamingDiagnostic &DB, T *DC) {
1455 DB.AddTaggedVal(reinterpret_cast<intptr_t>(DC),
1456 DiagnosticsEngine::ak_declcontext);
1457 return DB;
1458}
1459
1460inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1461 SourceRange R) {
1462 DB.AddSourceRange(CharSourceRange::getTokenRange(R));
1463 return DB;
1464}
1465
1466inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1467 ArrayRef<SourceRange> Ranges) {
1468 for (SourceRange R : Ranges)
1469 DB.AddSourceRange(CharSourceRange::getTokenRange(R));
1470 return DB;
1471}
1472
1473inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1474 const CharSourceRange &R) {
1475 DB.AddSourceRange(R);
1476 return DB;
1477}
1478
1479inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1480 const FixItHint &Hint) {
1481 DB.AddFixItHint(Hint);
1482 return DB;
1483}
1484
1485inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1486 ArrayRef<FixItHint> Hints) {
1487 for (const FixItHint &Hint : Hints)
1488 DB.AddFixItHint(Hint);
1489 return DB;
1490}
1491
1492inline const StreamingDiagnostic &
1493operator<<(const StreamingDiagnostic &DB,
1494 const llvm::Optional<SourceRange> &Opt) {
1495 if (Opt)
1496 DB << *Opt;
1497 return DB;
1498}
1499
1500inline const StreamingDiagnostic &
1501operator<<(const StreamingDiagnostic &DB,
1502 const llvm::Optional<CharSourceRange> &Opt) {
1503 if (Opt)
1504 DB << *Opt;
1505 return DB;
1506}
1507
1508inline const StreamingDiagnostic &
1509operator<<(const StreamingDiagnostic &DB,
1510 const llvm::Optional<FixItHint> &Opt) {
1511 if (Opt)
1512 DB << *Opt;
1513 return DB;
1514}
1515
1516/// A nullability kind paired with a bit indicating whether it used a
1517/// context-sensitive keyword.
1518using DiagNullabilityKind = std::pair<NullabilityKind, bool>;
1519
1520const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1521 DiagNullabilityKind nullability);
1522
1523inline DiagnosticBuilder DiagnosticsEngine::Report(SourceLocation Loc,
1524 unsigned DiagID) {
1525 assert(CurDiagID == std::numeric_limits<unsigned>::max() &&(static_cast <bool> (CurDiagID == std::numeric_limits<
unsigned>::max() && "Multiple diagnostics in flight at once!"
) ? void (0) : __assert_fail ("CurDiagID == std::numeric_limits<unsigned>::max() && \"Multiple diagnostics in flight at once!\""
, "clang/include/clang/Basic/Diagnostic.h", 1526, __extension__
__PRETTY_FUNCTION__))
1526 "Multiple diagnostics in flight at once!")(static_cast <bool> (CurDiagID == std::numeric_limits<
unsigned>::max() && "Multiple diagnostics in flight at once!"
) ? void (0) : __assert_fail ("CurDiagID == std::numeric_limits<unsigned>::max() && \"Multiple diagnostics in flight at once!\""
, "clang/include/clang/Basic/Diagnostic.h", 1526, __extension__
__PRETTY_FUNCTION__))
;
1527 CurDiagLoc = Loc;
1528 CurDiagID = DiagID;
1529 FlagValue.clear();
1530 return DiagnosticBuilder(this);
1531}
1532
1533const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
1534 llvm::Error &&E);
1535
1536inline DiagnosticBuilder DiagnosticsEngine::Report(unsigned DiagID) {
1537 return Report(SourceLocation(), DiagID);
1538}
1539
1540//===----------------------------------------------------------------------===//
1541// Diagnostic
1542//===----------------------------------------------------------------------===//
1543
1544/// A little helper class (which is basically a smart pointer that forwards
1545/// info from DiagnosticsEngine) that allows clients to enquire about the
1546/// currently in-flight diagnostic.
1547class Diagnostic {
1548 const DiagnosticsEngine *DiagObj;
1549 StringRef StoredDiagMessage;
1550
1551public:
1552 explicit Diagnostic(const DiagnosticsEngine *DO) : DiagObj(DO) {}
1553 Diagnostic(const DiagnosticsEngine *DO, StringRef storedDiagMessage)
1554 : DiagObj(DO), StoredDiagMessage(storedDiagMessage) {}
1555
1556 const DiagnosticsEngine *getDiags() const { return DiagObj; }
1557 unsigned getID() const { return DiagObj->CurDiagID; }
1558 const SourceLocation &getLocation() const { return DiagObj->CurDiagLoc; }
1559 bool hasSourceManager() const { return DiagObj->hasSourceManager(); }
1560 SourceManager &getSourceManager() const { return DiagObj->getSourceManager();}
1561
1562 unsigned getNumArgs() const { return DiagObj->DiagStorage.NumDiagArgs; }
1563
1564 /// Return the kind of the specified index.
1565 ///
1566 /// Based on the kind of argument, the accessors below can be used to get
1567 /// the value.
1568 ///
1569 /// \pre Idx < getNumArgs()
1570 DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const {
1571 assert(Idx < getNumArgs() && "Argument index out of range!")(static_cast <bool> (Idx < getNumArgs() && "Argument index out of range!"
) ? void (0) : __assert_fail ("Idx < getNumArgs() && \"Argument index out of range!\""
, "clang/include/clang/Basic/Diagnostic.h", 1571, __extension__
__PRETTY_FUNCTION__))
;
1572 return (DiagnosticsEngine::ArgumentKind)
1573 DiagObj->DiagStorage.DiagArgumentsKind[Idx];
1574 }
1575
1576 /// Return the provided argument string specified by \p Idx.
1577 /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_std_string
1578 const std::string &getArgStdStr(unsigned Idx) const {
1579 assert(getArgKind(Idx) == DiagnosticsEngine::ak_std_string &&(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine
::ak_std_string && "invalid argument accessor!") ? void
(0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_std_string && \"invalid argument accessor!\""
, "clang/include/clang/Basic/Diagnostic.h", 1580, __extension__
__PRETTY_FUNCTION__))
1580 "invalid argument accessor!")(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine
::ak_std_string && "invalid argument accessor!") ? void
(0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_std_string && \"invalid argument accessor!\""
, "clang/include/clang/Basic/Diagnostic.h", 1580, __extension__
__PRETTY_FUNCTION__))
;
1581 return DiagObj->DiagStorage.DiagArgumentsStr[Idx];
1582 }
1583
1584 /// Return the specified C string argument.
1585 /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_c_string
1586 const char *getArgCStr(unsigned Idx) const {
1587 assert(getArgKind(Idx) == DiagnosticsEngine::ak_c_string &&(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine
::ak_c_string && "invalid argument accessor!") ? void
(0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_c_string && \"invalid argument accessor!\""
, "clang/include/clang/Basic/Diagnostic.h", 1588, __extension__
__PRETTY_FUNCTION__))
1588 "invalid argument accessor!")(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine
::ak_c_string && "invalid argument accessor!") ? void
(0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_c_string && \"invalid argument accessor!\""
, "clang/include/clang/Basic/Diagnostic.h", 1588, __extension__
__PRETTY_FUNCTION__))
;
1589 return reinterpret_cast<const char *>(
1590 DiagObj->DiagStorage.DiagArgumentsVal[Idx]);
1591 }
1592
1593 /// Return the specified signed integer argument.
1594 /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_sint
1595 int64_t getArgSInt(unsigned Idx) const {
1596 assert(getArgKind(Idx) == DiagnosticsEngine::ak_sint &&(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine
::ak_sint && "invalid argument accessor!") ? void (0)
: __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_sint && \"invalid argument accessor!\""
, "clang/include/clang/Basic/Diagnostic.h", 1597, __extension__
__PRETTY_FUNCTION__))
1597 "invalid argument accessor!")(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine
::ak_sint && "invalid argument accessor!") ? void (0)
: __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_sint && \"invalid argument accessor!\""
, "clang/include/clang/Basic/Diagnostic.h", 1597, __extension__
__PRETTY_FUNCTION__))
;
1598 return (int64_t)DiagObj->DiagStorage.DiagArgumentsVal[Idx];
1599 }
1600
1601 /// Return the specified unsigned integer argument.
1602 /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_uint
1603 uint64_t getArgUInt(unsigned Idx) const {
1604 assert(getArgKind(Idx) == DiagnosticsEngine::ak_uint &&(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine
::ak_uint && "invalid argument accessor!") ? void (0)
: __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_uint && \"invalid argument accessor!\""
, "clang/include/clang/Basic/Diagnostic.h", 1605, __extension__
__PRETTY_FUNCTION__))
1605 "invalid argument accessor!")(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine
::ak_uint && "invalid argument accessor!") ? void (0)
: __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_uint && \"invalid argument accessor!\""
, "clang/include/clang/Basic/Diagnostic.h", 1605, __extension__
__PRETTY_FUNCTION__))
;
1606 return DiagObj->DiagStorage.DiagArgumentsVal[Idx];
1607 }
1608
1609 /// Return the specified IdentifierInfo argument.
1610 /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo
1611 const IdentifierInfo *getArgIdentifier(unsigned Idx) const {
1612 assert(getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo &&(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine
::ak_identifierinfo && "invalid argument accessor!") ?
void (0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo && \"invalid argument accessor!\""
, "clang/include/clang/Basic/Diagnostic.h", 1613, __extension__
__PRETTY_FUNCTION__))
1613 "invalid argument accessor!")(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine
::ak_identifierinfo && "invalid argument accessor!") ?
void (0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo && \"invalid argument accessor!\""
, "clang/include/clang/Basic/Diagnostic.h", 1613, __extension__
__PRETTY_FUNCTION__))
;
1614 return reinterpret_cast<IdentifierInfo *>(
1615 DiagObj->DiagStorage.DiagArgumentsVal[Idx]);
1616 }
1617
1618 /// Return the specified non-string argument in an opaque form.
1619 /// \pre getArgKind(Idx) != DiagnosticsEngine::ak_std_string
1620 uint64_t getRawArg(unsigned Idx) const {
1621 assert(getArgKind(Idx) != DiagnosticsEngine::ak_std_string &&(static_cast <bool> (getArgKind(Idx) != DiagnosticsEngine
::ak_std_string && "invalid argument accessor!") ? void
(0) : __assert_fail ("getArgKind(Idx) != DiagnosticsEngine::ak_std_string && \"invalid argument accessor!\""
, "clang/include/clang/Basic/Diagnostic.h", 1622, __extension__
__PRETTY_FUNCTION__))
1622 "invalid argument accessor!")(static_cast <bool> (getArgKind(Idx) != DiagnosticsEngine
::ak_std_string && "invalid argument accessor!") ? void
(0) : __assert_fail ("getArgKind(Idx) != DiagnosticsEngine::ak_std_string && \"invalid argument accessor!\""
, "clang/include/clang/Basic/Diagnostic.h", 1622, __extension__
__PRETTY_FUNCTION__))
;
1623 return DiagObj->DiagStorage.DiagArgumentsVal[Idx];
1624 }
1625
1626 /// Return the number of source ranges associated with this diagnostic.
1627 unsigned getNumRanges() const {
1628 return DiagObj->DiagStorage.DiagRanges.size();
1629 }
1630
1631 /// \pre Idx < getNumRanges()
1632 const CharSourceRange &getRange(unsigned Idx) const {
1633 assert(Idx < getNumRanges() && "Invalid diagnostic range index!")(static_cast <bool> (Idx < getNumRanges() &&
"Invalid diagnostic range index!") ? void (0) : __assert_fail
("Idx < getNumRanges() && \"Invalid diagnostic range index!\""
, "clang/include/clang/Basic/Diagnostic.h", 1633, __extension__
__PRETTY_FUNCTION__))
;
1634 return DiagObj->DiagStorage.DiagRanges[Idx];
1635 }
1636
1637 /// Return an array reference for this diagnostic's ranges.
1638 ArrayRef<CharSourceRange> getRanges() const {
1639 return DiagObj->DiagStorage.DiagRanges;
1640 }
1641
1642 unsigned getNumFixItHints() const {
1643 return DiagObj->DiagStorage.FixItHints.size();
1644 }
1645
1646 const FixItHint &getFixItHint(unsigned Idx) const {
1647 assert(Idx < getNumFixItHints() && "Invalid index!")(static_cast <bool> (Idx < getNumFixItHints() &&
"Invalid index!") ? void (0) : __assert_fail ("Idx < getNumFixItHints() && \"Invalid index!\""
, "clang/include/clang/Basic/Diagnostic.h", 1647, __extension__
__PRETTY_FUNCTION__))
;
1648 return DiagObj->DiagStorage.FixItHints[Idx];
1649 }
1650
1651 ArrayRef<FixItHint> getFixItHints() const {
1652 return DiagObj->DiagStorage.FixItHints;
1653 }
1654
1655 /// Format this diagnostic into a string, substituting the
1656 /// formal arguments into the %0 slots.
1657 ///
1658 /// The result is appended onto the \p OutStr array.
1659 void FormatDiagnostic(SmallVectorImpl<char> &OutStr) const;
1660
1661 /// Format the given format-string into the output buffer using the
1662 /// arguments stored in this diagnostic.
1663 void FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
1664 SmallVectorImpl<char> &OutStr) const;
1665};
1666
1667/**
1668 * Represents a diagnostic in a form that can be retained until its
1669 * corresponding source manager is destroyed.
1670 */
1671class StoredDiagnostic {
1672 unsigned ID;
1673 DiagnosticsEngine::Level Level;
1674 FullSourceLoc Loc;
1675 std::string Message;
1676 std::vector<CharSourceRange> Ranges;
1677 std::vector<FixItHint> FixIts;
1678
1679public:
1680 StoredDiagnostic() = default;
1681 StoredDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info);
1682 StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
1683 StringRef Message);
1684 StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
1685 StringRef Message, FullSourceLoc Loc,
1686 ArrayRef<CharSourceRange> Ranges,
1687 ArrayRef<FixItHint> Fixits);
1688
1689 /// Evaluates true when this object stores a diagnostic.
1690 explicit operator bool() const { return !Message.empty(); }
1691
1692 unsigned getID() const { return ID; }
1693 DiagnosticsEngine::Level getLevel() const { return Level; }
1694 const FullSourceLoc &getLocation() const { return Loc; }
1695 StringRef getMessage() const { return Message; }
1696
1697 void setLocation(FullSourceLoc Loc) { this->Loc = Loc; }
1698
1699 using range_iterator = std::vector<CharSourceRange>::const_iterator;
1700
1701 range_iterator range_begin() const { return Ranges.begin(); }
1702 range_iterator range_end() const { return Ranges.end(); }
1703 unsigned range_size() const { return Ranges.size(); }
1704
1705 ArrayRef<CharSourceRange> getRanges() const {
1706 return llvm::makeArrayRef(Ranges);
1707 }
1708
1709 using fixit_iterator = std::vector<FixItHint>::const_iterator;
1710
1711 fixit_iterator fixit_begin() const { return FixIts.begin(); }
1712 fixit_iterator fixit_end() const { return FixIts.end(); }
1713 unsigned fixit_size() const { return FixIts.size(); }
1714
1715 ArrayRef<FixItHint> getFixIts() const {
1716 return llvm::makeArrayRef(FixIts);
1717 }
1718};
1719
1720/// Abstract interface, implemented by clients of the front-end, which
1721/// formats and prints fully processed diagnostics.
1722class DiagnosticConsumer {
1723protected:
1724 unsigned NumWarnings = 0; ///< Number of warnings reported
1725 unsigned NumErrors = 0; ///< Number of errors reported
1726
1727public:
1728 DiagnosticConsumer() = default;
1729 virtual ~DiagnosticConsumer();
1730
1731 unsigned getNumErrors() const { return NumErrors; }
1732 unsigned getNumWarnings() const { return NumWarnings; }
1733 virtual void clear() { NumWarnings = NumErrors = 0; }
1734
1735 /// Callback to inform the diagnostic client that processing
1736 /// of a source file is beginning.
1737 ///
1738 /// Note that diagnostics may be emitted outside the processing of a source
1739 /// file, for example during the parsing of command line options. However,
1740 /// diagnostics with source range information are required to only be emitted
1741 /// in between BeginSourceFile() and EndSourceFile().
1742 ///
1743 /// \param LangOpts The language options for the source file being processed.
1744 /// \param PP The preprocessor object being used for the source; this is
1745 /// optional, e.g., it may not be present when processing AST source files.
1746 virtual void BeginSourceFile(const LangOptions &LangOpts,
1747 const Preprocessor *PP = nullptr) {}
1748
1749 /// Callback to inform the diagnostic client that processing
1750 /// of a source file has ended.
1751 ///
1752 /// The diagnostic client should assume that any objects made available via
1753 /// BeginSourceFile() are inaccessible.
1754 virtual void EndSourceFile() {}
1755
1756 /// Callback to inform the diagnostic client that processing of all
1757 /// source files has ended.
1758 virtual void finish() {}
1759
1760 /// Indicates whether the diagnostics handled by this
1761 /// DiagnosticConsumer should be included in the number of diagnostics
1762 /// reported by DiagnosticsEngine.
1763 ///
1764 /// The default implementation returns true.
1765 virtual bool IncludeInDiagnosticCounts() const;
1766
1767 /// Handle this diagnostic, reporting it to the user or
1768 /// capturing it to a log as needed.
1769 ///
1770 /// The default implementation just keeps track of the total number of
1771 /// warnings and errors.
1772 virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
1773 const Diagnostic &Info);
1774};
1775
1776/// A diagnostic client that ignores all diagnostics.
1777class IgnoringDiagConsumer : public DiagnosticConsumer {
1778 virtual void anchor();
1779
1780 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
1781 const Diagnostic &Info) override {
1782 // Just ignore it.
1783 }
1784};
1785
1786/// Diagnostic consumer that forwards diagnostics along to an
1787/// existing, already-initialized diagnostic consumer.
1788///
1789class ForwardingDiagnosticConsumer : public DiagnosticConsumer {
1790 DiagnosticConsumer &Target;
1791
1792public:
1793 ForwardingDiagnosticConsumer(DiagnosticConsumer &Target) : Target(Target) {}
1794 ~ForwardingDiagnosticConsumer() override;
1795
1796 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
1797 const Diagnostic &Info) override;
1798 void clear() override;
1799
1800 bool IncludeInDiagnosticCounts() const override;
1801};
1802
1803// Struct used for sending info about how a type should be printed.
1804struct TemplateDiffTypes {
1805 intptr_t FromType;
1806 intptr_t ToType;
1807 unsigned PrintTree : 1;
1808 unsigned PrintFromType : 1;
1809 unsigned ElideType : 1;
1810 unsigned ShowColors : 1;
1811
1812 // The printer sets this variable to true if the template diff was used.
1813 unsigned TemplateDiffUsed : 1;
1814};
1815
1816/// Special character that the diagnostic printer will use to toggle the bold
1817/// attribute. The character itself will be not be printed.
1818const char ToggleHighlight = 127;
1819
1820/// ProcessWarningOptions - Initialize the diagnostic client and process the
1821/// warning options specified on the command line.
1822void ProcessWarningOptions(DiagnosticsEngine &Diags,
1823 const DiagnosticOptions &Opts,
1824 bool ReportDiags = true);
1825
1826} // namespace clang
1827
1828#endif // LLVM_CLANG_BASIC_DIAGNOSTIC_H