Bug Summary

File:build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/clang/include/clang/Basic/Diagnostic.h
Warning:line 1198, 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-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-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-16/lib/clang/16.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-16~++20220904122748+c444af1c20b3/clang-tools-extra/clang-tidy/bugprone -I tools/clang/tools/extra/clang-tidy -I /build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/clang/include -I tools/clang/include -I include -I /build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/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-16/lib/clang/16.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-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/= -O2 -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 -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/= -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-09-04-125545-48738-1 -x c++ /build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp

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

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