xref: /llvm-project/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp (revision f4efa067435c8137718c907bf0de2b891b76552d)
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"
18 #include "llvm/Support/Debug.h"
19 #include <optional>
20 
21 namespace optutils = clang::tidy::utils::options;
22 
23 /// The default value for the MinimumLength check option.
24 static constexpr std::size_t DefaultMinimumLength = 2;
25 
26 /// The default value for ignored parameter names.
27 static constexpr llvm::StringLiteral DefaultIgnoredParameterNames = "\"\";"
28                                                                     "iterator;"
29                                                                     "Iterator;"
30                                                                     "begin;"
31                                                                     "Begin;"
32                                                                     "end;"
33                                                                     "End;"
34                                                                     "first;"
35                                                                     "First;"
36                                                                     "last;"
37                                                                     "Last;"
38                                                                     "lhs;"
39                                                                     "LHS;"
40                                                                     "rhs;"
41                                                                     "RHS";
42 
43 /// The default value for ignored parameter type suffixes.
44 static constexpr llvm::StringLiteral DefaultIgnoredParameterTypeSuffixes =
45     "bool;"
46     "Bool;"
47     "_Bool;"
48     "it;"
49     "It;"
50     "iterator;"
51     "Iterator;"
52     "inputit;"
53     "InputIt;"
54     "forwardit;"
55     "ForwardIt;"
56     "bidirit;"
57     "BidirIt;"
58     "constiterator;"
59     "const_iterator;"
60     "Const_Iterator;"
61     "Constiterator;"
62     "ConstIterator;"
63     "RandomIt;"
64     "randomit;"
65     "random_iterator;"
66     "ReverseIt;"
67     "reverse_iterator;"
68     "reverse_const_iterator;"
69     "ConstReverseIterator;"
70     "Const_Reverse_Iterator;"
71     "const_reverse_iterator;"
72     "Constreverseiterator;"
73     "constreverseiterator";
74 
75 /// The default value for the QualifiersMix check option.
76 static constexpr bool DefaultQualifiersMix = false;
77 
78 /// The default value for the ModelImplicitConversions check option.
79 static constexpr bool DefaultModelImplicitConversions = true;
80 
81 /// The default value for suppressing diagnostics about parameters that are
82 /// used together.
83 static constexpr bool DefaultSuppressParametersUsedTogether = true;
84 
85 /// The default value for the NamePrefixSuffixSilenceDissimilarityTreshold
86 /// check option.
87 static constexpr std::size_t
88     DefaultNamePrefixSuffixSilenceDissimilarityTreshold = 1;
89 
90 using namespace clang::ast_matchers;
91 
92 namespace clang::tidy::bugprone {
93 
94 using TheCheck = EasilySwappableParametersCheck;
95 
96 namespace filter {
97 class SimilarlyUsedParameterPairSuppressor;
98 
99 static bool isIgnoredParameter(const TheCheck &Check, const ParmVarDecl *Node);
100 static inline bool
101 isSimilarlyUsedParameter(const SimilarlyUsedParameterPairSuppressor &Suppressor,
102                          const ParmVarDecl *Param1, const ParmVarDecl *Param2);
103 static bool prefixSuffixCoverUnderThreshold(std::size_t Threshold,
104                                             StringRef Str1, StringRef Str2);
105 } // namespace filter
106 
107 namespace model {
108 
109 /// The language features involved in allowing the mix between two parameters.
110 enum class MixFlags : unsigned char {
111   Invalid = 0, ///< Sentinel bit pattern. DO NOT USE!
112 
113   /// Certain constructs (such as pointers to noexcept/non-noexcept functions)
114   /// have the same CanonicalType, which would result in false positives.
115   /// During the recursive modelling call, this flag is set if a later diagnosed
116   /// canonical type equivalence should be thrown away.
117   WorkaroundDisableCanonicalEquivalence = 1,
118 
119   None = 2,           ///< Mix between the two parameters is not possible.
120   Trivial = 4,        ///< The two mix trivially, and are the exact same type.
121   Canonical = 8,      ///< The two mix because the types refer to the same
122                       /// CanonicalType, but we do not elaborate as to how.
123   TypeAlias = 16,     ///< The path from one type to the other involves
124                       /// desugaring type aliases.
125   ReferenceBind = 32, ///< The mix involves the binding power of "const &".
126   Qualifiers = 64,    ///< The mix involves change in the qualifiers.
127   ImplicitConversion = 128, ///< The mixing of the parameters is possible
128                             /// through implicit conversions between the types.
129 
130   LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue =*/ImplicitConversion)
131 };
132 LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
133 
134 /// Returns whether the SearchedFlag is turned on in the Data.
hasFlag(MixFlags Data,MixFlags SearchedFlag)135 static inline bool hasFlag(MixFlags Data, MixFlags SearchedFlag) {
136   assert(SearchedFlag != MixFlags::Invalid &&
137          "can't be used to detect lack of all bits!");
138 
139   // "Data & SearchedFlag" would need static_cast<bool>() in conditions.
140   return (Data & SearchedFlag) == SearchedFlag;
141 }
142 
143 #ifndef NDEBUG
144 
145 // The modelling logic of this check is more complex than usual, and
146 // potentially hard to understand without the ability to see into the
147 // representation during the recursive descent. This debug code is only
148 // compiled in 'Debug' mode, or if LLVM_ENABLE_ASSERTIONS config is turned on.
149 
150 /// Formats the MixFlags enum into a useful, user-readable representation.
formatMixFlags(MixFlags F)151 static inline std::string formatMixFlags(MixFlags F) {
152   if (F == MixFlags::Invalid)
153     return "#Inv!";
154 
155   SmallString<8> Str{"-------"};
156 
157   if (hasFlag(F, MixFlags::None))
158     // Shows the None bit explicitly, as it can be applied in the recursion
159     // even if other bits are set.
160     Str[0] = '!';
161   if (hasFlag(F, MixFlags::Trivial))
162     Str[1] = 'T';
163   if (hasFlag(F, MixFlags::Canonical))
164     Str[2] = 'C';
165   if (hasFlag(F, MixFlags::TypeAlias))
166     Str[3] = 't';
167   if (hasFlag(F, MixFlags::ReferenceBind))
168     Str[4] = '&';
169   if (hasFlag(F, MixFlags::Qualifiers))
170     Str[5] = 'Q';
171   if (hasFlag(F, MixFlags::ImplicitConversion))
172     Str[6] = 'i';
173 
174   if (hasFlag(F, MixFlags::WorkaroundDisableCanonicalEquivalence))
175     Str.append("(~C)");
176 
177   return Str.str().str();
178 }
179 
180 #endif // NDEBUG
181 
182 /// The results of the steps of an Implicit Conversion Sequence is saved in
183 /// an instance of this record.
184 ///
185 /// A ConversionSequence maps the steps of the conversion with a member for
186 /// each type involved in the conversion. Imagine going from a hypothetical
187 /// Complex class to projecting it to the real part as a const double.
188 ///
189 /// I.e., given:
190 ///
191 ///    struct Complex {
192 ///      operator double() const;
193 ///    };
194 ///
195 ///    void functionBeingAnalysed(Complex C, const double R);
196 ///
197 /// we will get the following sequence:
198 ///
199 /// (Begin=) Complex
200 ///
201 ///     The first standard conversion is a qualification adjustment.
202 /// (AfterFirstStandard=) const Complex
203 ///
204 ///     Then the user-defined conversion is executed.
205 /// (UDConvOp.ConversionOperatorResultType=) double
206 ///
207 ///     Then this 'double' is qualifier-adjusted to 'const double'.
208 /// (AfterSecondStandard=) double
209 ///
210 /// The conversion's result has now been calculated, so it ends here.
211 /// (End=) double.
212 ///
213 /// Explicit storing of Begin and End in this record is needed, because
214 /// getting to what Begin and End here are needs further resolution of types,
215 /// e.g. in the case of typedefs:
216 ///
217 ///     using Comp = Complex;
218 ///     using CD = const double;
219 ///     void functionBeingAnalysed2(Comp C, CD R);
220 ///
221 /// In this case, the user will be diagnosed with a potential conversion
222 /// between the two typedefs as written in the code, but to elaborate the
223 /// reasoning behind this conversion, we also need to show what the typedefs
224 /// mean. See FormattedConversionSequence towards the bottom of this file!
225 struct ConversionSequence {
226   enum UserDefinedConversionKind { UDCK_None, UDCK_Ctor, UDCK_Oper };
227 
228   struct UserDefinedConvertingConstructor {
229     const CXXConstructorDecl *Fun;
230     QualType ConstructorParameterType;
231     QualType UserDefinedType;
232   };
233 
234   struct UserDefinedConversionOperator {
235     const CXXConversionDecl *Fun;
236     QualType UserDefinedType;
237     QualType ConversionOperatorResultType;
238   };
239 
240   /// The type the conversion stared from.
241   QualType Begin;
242 
243   /// The intermediate type after the first Standard Conversion Sequence.
244   QualType AfterFirstStandard;
245 
246   /// The details of the user-defined conversion involved, as a tagged union.
247   union {
248     char None;
249     UserDefinedConvertingConstructor UDConvCtor;
250     UserDefinedConversionOperator UDConvOp;
251   };
252   UserDefinedConversionKind UDConvKind;
253 
254   /// The intermediate type after performing the second Standard Conversion
255   /// Sequence.
256   QualType AfterSecondStandard;
257 
258   /// The result type the conversion targeted.
259   QualType End;
260 
ConversionSequenceclang::tidy::bugprone::model::ConversionSequence261   ConversionSequence() : None(0), UDConvKind(UDCK_None) {}
ConversionSequenceclang::tidy::bugprone::model::ConversionSequence262   ConversionSequence(QualType From, QualType To)
263       : Begin(From), None(0), UDConvKind(UDCK_None), End(To) {}
264 
operator boolclang::tidy::bugprone::model::ConversionSequence265   explicit operator bool() const {
266     return !AfterFirstStandard.isNull() || UDConvKind != UDCK_None ||
267            !AfterSecondStandard.isNull();
268   }
269 
270   /// Returns all the "steps" (non-unique and non-similar) types involved in
271   /// the conversion sequence. This method does **NOT** return Begin and End.
getInvolvedTypesInSequenceclang::tidy::bugprone::model::ConversionSequence272   SmallVector<QualType, 4> getInvolvedTypesInSequence() const {
273     SmallVector<QualType, 4> Ret;
274     auto EmplaceIfDifferent = [&Ret](QualType QT) {
275       if (QT.isNull())
276         return;
277       if (Ret.empty())
278         Ret.emplace_back(QT);
279       else if (Ret.back() != QT)
280         Ret.emplace_back(QT);
281     };
282 
283     EmplaceIfDifferent(AfterFirstStandard);
284     switch (UDConvKind) {
285     case UDCK_Ctor:
286       EmplaceIfDifferent(UDConvCtor.ConstructorParameterType);
287       EmplaceIfDifferent(UDConvCtor.UserDefinedType);
288       break;
289     case UDCK_Oper:
290       EmplaceIfDifferent(UDConvOp.UserDefinedType);
291       EmplaceIfDifferent(UDConvOp.ConversionOperatorResultType);
292       break;
293     case UDCK_None:
294       break;
295     }
296     EmplaceIfDifferent(AfterSecondStandard);
297 
298     return Ret;
299   }
300 
301   /// Updates the steps of the conversion sequence with the steps from the
302   /// other instance.
303   ///
304   /// \note This method does not check if the resulting conversion sequence is
305   /// sensible!
updateclang::tidy::bugprone::model::ConversionSequence306   ConversionSequence &update(const ConversionSequence &RHS) {
307     if (!RHS.AfterFirstStandard.isNull())
308       AfterFirstStandard = RHS.AfterFirstStandard;
309     switch (RHS.UDConvKind) {
310     case UDCK_Ctor:
311       UDConvKind = UDCK_Ctor;
312       UDConvCtor = RHS.UDConvCtor;
313       break;
314     case UDCK_Oper:
315       UDConvKind = UDCK_Oper;
316       UDConvOp = RHS.UDConvOp;
317       break;
318     case UDCK_None:
319       break;
320     }
321     if (!RHS.AfterSecondStandard.isNull())
322       AfterSecondStandard = RHS.AfterSecondStandard;
323 
324     return *this;
325   }
326 
327   /// Sets the user-defined conversion to the given constructor.
setConversionclang::tidy::bugprone::model::ConversionSequence328   void setConversion(const UserDefinedConvertingConstructor &UDCC) {
329     UDConvKind = UDCK_Ctor;
330     UDConvCtor = UDCC;
331   }
332 
333   /// Sets the user-defined conversion to the given operator.
setConversionclang::tidy::bugprone::model::ConversionSequence334   void setConversion(const UserDefinedConversionOperator &UDCO) {
335     UDConvKind = UDCK_Oper;
336     UDConvOp = UDCO;
337   }
338 
339   /// Returns the type in the conversion that's formally "in our hands" once
340   /// the user-defined conversion is executed.
getTypeAfterUserDefinedConversionclang::tidy::bugprone::model::ConversionSequence341   QualType getTypeAfterUserDefinedConversion() const {
342     switch (UDConvKind) {
343     case UDCK_Ctor:
344       return UDConvCtor.UserDefinedType;
345     case UDCK_Oper:
346       return UDConvOp.ConversionOperatorResultType;
347     case UDCK_None:
348       return {};
349     }
350     llvm_unreachable("Invalid UDConv kind.");
351   }
352 
getUserDefinedConversionFunctionclang::tidy::bugprone::model::ConversionSequence353   const CXXMethodDecl *getUserDefinedConversionFunction() const {
354     switch (UDConvKind) {
355     case UDCK_Ctor:
356       return UDConvCtor.Fun;
357     case UDCK_Oper:
358       return UDConvOp.Fun;
359     case UDCK_None:
360       return {};
361     }
362     llvm_unreachable("Invalid UDConv kind.");
363   }
364 
365   /// Returns the SourceRange in the text that corresponds to the interesting
366   /// part of the user-defined conversion. This is either the parameter type
367   /// in a converting constructor, or the conversion result type in a conversion
368   /// operator.
getUserDefinedConversionHighlightclang::tidy::bugprone::model::ConversionSequence369   SourceRange getUserDefinedConversionHighlight() const {
370     switch (UDConvKind) {
371     case UDCK_Ctor:
372       return UDConvCtor.Fun->getParamDecl(0)->getSourceRange();
373     case UDCK_Oper:
374       // getReturnTypeSourceRange() does not work for CXXConversionDecls as the
375       // returned type is physically behind the declaration's name ("operator").
376       if (const FunctionTypeLoc FTL = UDConvOp.Fun->getFunctionTypeLoc())
377         if (const TypeLoc RetLoc = FTL.getReturnLoc())
378           return RetLoc.getSourceRange();
379       return {};
380     case UDCK_None:
381       return {};
382     }
383     llvm_unreachable("Invalid UDConv kind.");
384   }
385 };
386 
387 /// Contains the metadata for the mixability result between two types,
388 /// independently of which parameters they were calculated from.
389 struct MixData {
390   /// The flag bits of the mix indicating what language features allow for it.
391   MixFlags Flags = MixFlags::Invalid;
392 
393   /// A potentially calculated common underlying type after desugaring, that
394   /// both sides of the mix can originate from.
395   QualType CommonType;
396 
397   /// The steps an implicit conversion performs to get from one type to the
398   /// other.
399   ConversionSequence Conversion, ConversionRTL;
400 
401   /// True if the MixData was specifically created with only a one-way
402   /// conversion modelled.
403   bool CreatedFromOneWayConversion = false;
404 
MixDataclang::tidy::bugprone::model::MixData405   MixData(MixFlags Flags) : Flags(Flags) {}
MixDataclang::tidy::bugprone::model::MixData406   MixData(MixFlags Flags, QualType CommonType)
407       : Flags(Flags), CommonType(CommonType) {}
MixDataclang::tidy::bugprone::model::MixData408   MixData(MixFlags Flags, ConversionSequence Conv)
409       : Flags(Flags), Conversion(Conv), CreatedFromOneWayConversion(true) {}
MixDataclang::tidy::bugprone::model::MixData410   MixData(MixFlags Flags, ConversionSequence LTR, ConversionSequence RTL)
411       : Flags(Flags), Conversion(LTR), ConversionRTL(RTL) {}
MixDataclang::tidy::bugprone::model::MixData412   MixData(MixFlags Flags, QualType CommonType, ConversionSequence LTR,
413           ConversionSequence RTL)
414       : Flags(Flags), CommonType(CommonType), Conversion(LTR),
415         ConversionRTL(RTL) {}
416 
sanitizeclang::tidy::bugprone::model::MixData417   void sanitize() {
418     assert(Flags != MixFlags::Invalid && "sanitize() called on invalid bitvec");
419 
420     MixFlags CanonicalAndWorkaround =
421         MixFlags::Canonical | MixFlags::WorkaroundDisableCanonicalEquivalence;
422     if ((Flags & CanonicalAndWorkaround) == CanonicalAndWorkaround) {
423       // A workaround for too eagerly equivalent canonical types was requested,
424       // and a canonical equivalence was proven. Fulfill the request and throw
425       // this result away.
426       Flags = MixFlags::None;
427       return;
428     }
429 
430     if (hasFlag(Flags, MixFlags::None)) {
431       // If anywhere down the recursion a potential mix "path" is deemed
432       // impossible, throw away all the other bits because the mix is not
433       // possible.
434       Flags = MixFlags::None;
435       return;
436     }
437 
438     if (Flags == MixFlags::Trivial)
439       return;
440 
441     if (static_cast<bool>(Flags ^ MixFlags::Trivial))
442       // If the mix involves somewhere trivial equivalence but down the
443       // recursion other bit(s) were set, remove the trivial bit, as it is not
444       // trivial.
445       Flags &= ~MixFlags::Trivial;
446 
447     bool ShouldHaveImplicitConvFlag = false;
448     if (CreatedFromOneWayConversion && Conversion)
449       ShouldHaveImplicitConvFlag = true;
450     else if (!CreatedFromOneWayConversion && Conversion && ConversionRTL)
451       // Only say that we have implicit conversion mix possibility if it is
452       // bidirectional. Otherwise, the compiler would report an *actual* swap
453       // at a call site...
454       ShouldHaveImplicitConvFlag = true;
455 
456     if (ShouldHaveImplicitConvFlag)
457       Flags |= MixFlags::ImplicitConversion;
458     else
459       Flags &= ~MixFlags::ImplicitConversion;
460   }
461 
isValidclang::tidy::bugprone::model::MixData462   bool isValid() const { return Flags >= MixFlags::None; }
463 
indicatesMixabilityclang::tidy::bugprone::model::MixData464   bool indicatesMixability() const { return Flags > MixFlags::None; }
465 
466   /// Add the specified flag bits to the flags.
operator |clang::tidy::bugprone::model::MixData467   MixData operator|(MixFlags EnableFlags) const {
468     if (CreatedFromOneWayConversion) {
469       MixData M{Flags | EnableFlags, Conversion};
470       M.CommonType = CommonType;
471       return M;
472     }
473     return {Flags | EnableFlags, CommonType, Conversion, ConversionRTL};
474   }
475 
476   /// Add the specified flag bits to the flags.
operator |=clang::tidy::bugprone::model::MixData477   MixData &operator|=(MixFlags EnableFlags) {
478     Flags |= EnableFlags;
479     return *this;
480   }
481 
withCommonTypeTransformedclang::tidy::bugprone::model::MixData482   template <typename F> MixData withCommonTypeTransformed(const F &Func) const {
483     if (CommonType.isNull())
484       return *this;
485 
486     QualType NewCommonType = Func(CommonType);
487 
488     if (CreatedFromOneWayConversion) {
489       MixData M{Flags, Conversion};
490       M.CommonType = NewCommonType;
491       return M;
492     }
493 
494     return {Flags, NewCommonType, Conversion, ConversionRTL};
495   }
496 };
497 
498 /// A named tuple that contains the information for a mix between two concrete
499 /// parameters.
500 struct Mix {
501   const ParmVarDecl *First, *Second;
502   MixData Data;
503 
Mixclang::tidy::bugprone::model::Mix504   Mix(const ParmVarDecl *F, const ParmVarDecl *S, MixData Data)
505       : First(F), Second(S), Data(std::move(Data)) {}
506 
sanitizeclang::tidy::bugprone::model::Mix507   void sanitize() { Data.sanitize(); }
flagsclang::tidy::bugprone::model::Mix508   MixFlags flags() const { return Data.Flags; }
flagsValidclang::tidy::bugprone::model::Mix509   bool flagsValid() const { return Data.isValid(); }
mixableclang::tidy::bugprone::model::Mix510   bool mixable() const { return Data.indicatesMixability(); }
commonUnderlyingTypeclang::tidy::bugprone::model::Mix511   QualType commonUnderlyingType() const { return Data.CommonType; }
leftToRightConversionSequenceclang::tidy::bugprone::model::Mix512   const ConversionSequence &leftToRightConversionSequence() const {
513     return Data.Conversion;
514   }
rightToLeftConversionSequenceclang::tidy::bugprone::model::Mix515   const ConversionSequence &rightToLeftConversionSequence() const {
516     return Data.ConversionRTL;
517   }
518 };
519 
520 // NOLINTNEXTLINE(misc-redundant-expression): Seems to be a bogus warning.
521 static_assert(std::is_trivially_copyable_v<Mix> &&
522                   std::is_trivially_move_constructible_v<Mix> &&
523                   std::is_trivially_move_assignable_v<Mix>,
524               "Keep frequently used data simple!");
525 
526 struct MixableParameterRange {
527   /// A container for Mixes.
528   using MixVector = SmallVector<Mix, 8>;
529 
530   /// The number of parameters iterated to build the instance.
531   std::size_t NumParamsChecked = 0;
532 
533   /// The individual flags and supporting information for the mixes.
534   MixVector Mixes;
535 
536   /// Gets the leftmost parameter of the range.
getFirstParamclang::tidy::bugprone::model::MixableParameterRange537   const ParmVarDecl *getFirstParam() const {
538     // The first element is the LHS of the very first mix in the range.
539     assert(!Mixes.empty());
540     return Mixes.front().First;
541   }
542 
543   /// Gets the rightmost parameter of the range.
getLastParamclang::tidy::bugprone::model::MixableParameterRange544   const ParmVarDecl *getLastParam() const {
545     // The builder function breaks building an instance of this type if it
546     // finds something that can not be mixed with the rest, by going *forward*
547     // in the list of parameters. So at any moment of break, the RHS of the last
548     // element of the mix vector is also the last element of the mixing range.
549     assert(!Mixes.empty());
550     return Mixes.back().Second;
551   }
552 };
553 
554 /// Helper enum for the recursive calls in the modelling that toggle what kinds
555 /// of implicit conversions are to be modelled.
556 enum class ImplicitConversionModellingMode : unsigned char {
557   ///< No implicit conversions are modelled.
558   None,
559 
560   ///< The full implicit conversion sequence is modelled.
561   All,
562 
563   ///< Only model a unidirectional implicit conversion and within it only one
564   /// standard conversion sequence.
565   OneWaySingleStandardOnly
566 };
567 
568 static MixData
569 isLRefEquallyBindingToType(const TheCheck &Check,
570                            const LValueReferenceType *LRef, QualType Ty,
571                            const ASTContext &Ctx, bool IsRefRHS,
572                            ImplicitConversionModellingMode ImplicitMode);
573 
574 static MixData
575 approximateImplicitConversion(const TheCheck &Check, QualType LType,
576                               QualType RType, const ASTContext &Ctx,
577                               ImplicitConversionModellingMode ImplicitMode);
578 
isUselessSugar(const Type * T)579 static inline bool isUselessSugar(const Type *T) {
580   return isa<AttributedType, DecayedType, ElaboratedType, ParenType>(T);
581 }
582 
583 namespace {
584 
585 struct NonCVRQualifiersResult {
586   /// True if the types are qualified in a way that even after equating or
587   /// removing local CVR qualification, even if the unqualified types
588   /// themselves would mix, the qualified ones don't, because there are some
589   /// other local qualifiers that are not equal.
590   bool HasMixabilityBreakingQualifiers;
591 
592   /// The set of equal qualifiers between the two types.
593   Qualifiers CommonQualifiers;
594 };
595 
596 } // namespace
597 
598 /// Returns if the two types are qualified in a way that ever after equating or
599 /// removing local CVR qualification, even if the unqualified types would mix,
600 /// the qualified ones don't, because there are some other local qualifiers
601 /// that aren't equal.
602 static NonCVRQualifiersResult
getNonCVRQualifiers(const ASTContext & Ctx,QualType LType,QualType RType)603 getNonCVRQualifiers(const ASTContext &Ctx, QualType LType, QualType RType) {
604   LLVM_DEBUG(llvm::dbgs() << ">>> getNonCVRQualifiers for LType:\n";
605              LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";
606              RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';);
607   Qualifiers LQual = LType.getLocalQualifiers(),
608              RQual = RType.getLocalQualifiers();
609 
610   // Strip potential CVR. That is handled by the check option QualifiersMix.
611   LQual.removeCVRQualifiers();
612   RQual.removeCVRQualifiers();
613 
614   NonCVRQualifiersResult Ret;
615   Ret.CommonQualifiers = Qualifiers::removeCommonQualifiers(LQual, RQual);
616 
617   LLVM_DEBUG(llvm::dbgs() << "--- hasNonCVRMixabilityBreakingQualifiers. "
618                              "Removed common qualifiers: ";
619              Ret.CommonQualifiers.print(llvm::dbgs(), Ctx.getPrintingPolicy());
620              llvm::dbgs() << "\n\tremaining on LType: ";
621              LQual.print(llvm::dbgs(), Ctx.getPrintingPolicy());
622              llvm::dbgs() << "\n\tremaining on RType: ";
623              RQual.print(llvm::dbgs(), Ctx.getPrintingPolicy());
624              llvm::dbgs() << '\n';);
625 
626   // If there are no other non-cvr non-common qualifiers left, we can deduce
627   // that mixability isn't broken.
628   Ret.HasMixabilityBreakingQualifiers =
629       LQual.hasQualifiers() || RQual.hasQualifiers();
630 
631   return Ret;
632 }
633 
634 /// Approximate the way how LType and RType might refer to "essentially the
635 /// same" type, in a sense that at a particular call site, an expression of
636 /// type LType and RType might be successfully passed to a variable (in our
637 /// specific case, a parameter) of type RType and LType, respectively.
638 /// Note the swapped order!
639 ///
640 /// The returned data structure is not guaranteed to be properly set, as this
641 /// function is potentially recursive. It is the caller's responsibility to
642 /// call sanitize() on the result once the recursion is over.
643 static MixData
calculateMixability(const TheCheck & Check,QualType LType,QualType RType,const ASTContext & Ctx,ImplicitConversionModellingMode ImplicitMode)644 calculateMixability(const TheCheck &Check, QualType LType, QualType RType,
645                     const ASTContext &Ctx,
646                     ImplicitConversionModellingMode ImplicitMode) {
647   LLVM_DEBUG(llvm::dbgs() << ">>> calculateMixability for LType:\n";
648              LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";
649              RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';);
650   if (LType == RType) {
651     LLVM_DEBUG(llvm::dbgs() << "<<< calculateMixability. Trivial equality.\n");
652     return {MixFlags::Trivial, LType};
653   }
654 
655   // Dissolve certain type sugars that do not affect the mixability of one type
656   // with the other, and also do not require any sort of elaboration for the
657   // user to understand.
658   if (isUselessSugar(LType.getTypePtr())) {
659     LLVM_DEBUG(llvm::dbgs()
660                << "--- calculateMixability. LHS is useless sugar.\n");
661     return calculateMixability(Check, LType.getSingleStepDesugaredType(Ctx),
662                                RType, Ctx, ImplicitMode);
663   }
664   if (isUselessSugar(RType.getTypePtr())) {
665     LLVM_DEBUG(llvm::dbgs()
666                << "--- calculateMixability. RHS is useless sugar.\n");
667     return calculateMixability(
668         Check, LType, RType.getSingleStepDesugaredType(Ctx), Ctx, ImplicitMode);
669   }
670 
671   const auto *LLRef = LType->getAs<LValueReferenceType>();
672   const auto *RLRef = RType->getAs<LValueReferenceType>();
673   if (LLRef && RLRef) {
674     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. LHS and RHS are &.\n");
675 
676     return calculateMixability(Check, LLRef->getPointeeType(),
677                                RLRef->getPointeeType(), Ctx, ImplicitMode)
678         .withCommonTypeTransformed(
679             [&Ctx](QualType QT) { return Ctx.getLValueReferenceType(QT); });
680   }
681   // At a particular call site, what could be passed to a 'T' or 'const T' might
682   // also be passed to a 'const T &' without the call site putting a direct
683   // side effect on the passed expressions.
684   if (LLRef) {
685     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. LHS is &.\n");
686     return isLRefEquallyBindingToType(Check, LLRef, RType, Ctx, false,
687                                       ImplicitMode) |
688            MixFlags::ReferenceBind;
689   }
690   if (RLRef) {
691     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. RHS is &.\n");
692     return isLRefEquallyBindingToType(Check, RLRef, LType, Ctx, true,
693                                       ImplicitMode) |
694            MixFlags::ReferenceBind;
695   }
696 
697   if (LType->getAs<TypedefType>()) {
698     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. LHS is typedef.\n");
699     return calculateMixability(Check, LType.getSingleStepDesugaredType(Ctx),
700                                RType, Ctx, ImplicitMode) |
701            MixFlags::TypeAlias;
702   }
703   if (RType->getAs<TypedefType>()) {
704     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. RHS is typedef.\n");
705     return calculateMixability(Check, LType,
706                                RType.getSingleStepDesugaredType(Ctx), Ctx,
707                                ImplicitMode) |
708            MixFlags::TypeAlias;
709   }
710 
711   // A parameter of type 'cvr1 T' and another of potentially differently
712   // qualified 'cvr2 T' may bind with the same power, if the user so requested.
713   //
714   // Whether to do this check for the inner unqualified types.
715   bool CompareUnqualifiedTypes = false;
716   if (LType.getLocalCVRQualifiers() != RType.getLocalCVRQualifiers()) {
717     LLVM_DEBUG(if (LType.getLocalCVRQualifiers()) {
718       llvm::dbgs() << "--- calculateMixability. LHS has CVR-Qualifiers: ";
719       Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers())
720           .print(llvm::dbgs(), Ctx.getPrintingPolicy());
721       llvm::dbgs() << '\n';
722     });
723     LLVM_DEBUG(if (RType.getLocalCVRQualifiers()) {
724       llvm::dbgs() << "--- calculateMixability. RHS has CVR-Qualifiers: ";
725       Qualifiers::fromCVRMask(RType.getLocalCVRQualifiers())
726           .print(llvm::dbgs(), Ctx.getPrintingPolicy());
727       llvm::dbgs() << '\n';
728     });
729 
730     if (!Check.QualifiersMix) {
731       LLVM_DEBUG(llvm::dbgs()
732                  << "<<< calculateMixability. QualifiersMix turned off - not "
733                     "mixable.\n");
734       return {MixFlags::None};
735     }
736 
737     CompareUnqualifiedTypes = true;
738   }
739   // Whether the two types had the same CVR qualifiers.
740   bool OriginallySameQualifiers = false;
741   if (LType.getLocalCVRQualifiers() == RType.getLocalCVRQualifiers() &&
742       LType.getLocalCVRQualifiers() != 0) {
743     LLVM_DEBUG(if (LType.getLocalCVRQualifiers()) {
744       llvm::dbgs()
745           << "--- calculateMixability. LHS and RHS have same CVR-Qualifiers: ";
746       Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers())
747           .print(llvm::dbgs(), Ctx.getPrintingPolicy());
748       llvm::dbgs() << '\n';
749     });
750 
751     CompareUnqualifiedTypes = true;
752     OriginallySameQualifiers = true;
753   }
754 
755   if (CompareUnqualifiedTypes) {
756     NonCVRQualifiersResult AdditionalQuals =
757         getNonCVRQualifiers(Ctx, LType, RType);
758     if (AdditionalQuals.HasMixabilityBreakingQualifiers) {
759       LLVM_DEBUG(llvm::dbgs() << "<<< calculateMixability. Additional "
760                                  "non-equal incompatible qualifiers.\n");
761       return {MixFlags::None};
762     }
763 
764     MixData UnqualifiedMixability =
765         calculateMixability(Check, LType.getLocalUnqualifiedType(),
766                             RType.getLocalUnqualifiedType(), Ctx, ImplicitMode)
767             .withCommonTypeTransformed([&AdditionalQuals, &Ctx](QualType QT) {
768               // Once the mixability was deduced, apply the qualifiers common
769               // to the two type back onto the diagnostic printout.
770               return Ctx.getQualifiedType(QT, AdditionalQuals.CommonQualifiers);
771             });
772 
773     if (!OriginallySameQualifiers)
774       // User-enabled qualifier change modelled for the mix.
775       return UnqualifiedMixability | MixFlags::Qualifiers;
776 
777     // Apply the same qualifier back into the found common type if they were
778     // the same.
779     return UnqualifiedMixability.withCommonTypeTransformed(
780         [&Ctx, LType](QualType QT) {
781           return Ctx.getQualifiedType(QT, LType.getLocalQualifiers());
782         });
783   }
784 
785   // Certain constructs match on the last catch-all getCanonicalType() equality,
786   // which is perhaps something not what we want. If this variable is true,
787   // the canonical type equality will be ignored.
788   bool RecursiveReturnDiscardingCanonicalType = false;
789 
790   if (LType->isPointerType() && RType->isPointerType()) {
791     // If both types are pointers, and pointed to the exact same type,
792     // LType == RType took care of that. Try to see if the pointee type has
793     // some other match. However, this must not consider implicit conversions.
794     LLVM_DEBUG(llvm::dbgs()
795                << "--- calculateMixability. LHS and RHS are Ptrs.\n");
796     MixData MixOfPointee =
797         calculateMixability(Check, LType->getPointeeType(),
798                             RType->getPointeeType(), Ctx,
799                             ImplicitConversionModellingMode::None)
800             .withCommonTypeTransformed(
801                 [&Ctx](QualType QT) { return Ctx.getPointerType(QT); });
802     if (hasFlag(MixOfPointee.Flags,
803                 MixFlags::WorkaroundDisableCanonicalEquivalence))
804       RecursiveReturnDiscardingCanonicalType = true;
805 
806     MixOfPointee.sanitize();
807     if (MixOfPointee.indicatesMixability()) {
808       LLVM_DEBUG(llvm::dbgs()
809                  << "<<< calculateMixability. Pointees are mixable.\n");
810       return MixOfPointee;
811     }
812   }
813 
814   if (ImplicitMode > ImplicitConversionModellingMode::None) {
815     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. Start implicit...\n");
816     MixData MixLTR =
817         approximateImplicitConversion(Check, LType, RType, Ctx, ImplicitMode);
818     LLVM_DEBUG(
819         if (hasFlag(MixLTR.Flags, MixFlags::ImplicitConversion)) llvm::dbgs()
820             << "--- calculateMixability. Implicit Left -> Right found.\n";);
821 
822     if (ImplicitMode ==
823             ImplicitConversionModellingMode::OneWaySingleStandardOnly &&
824         MixLTR.Conversion && !MixLTR.Conversion.AfterFirstStandard.isNull() &&
825         MixLTR.Conversion.UDConvKind == ConversionSequence::UDCK_None &&
826         MixLTR.Conversion.AfterSecondStandard.isNull()) {
827       // The invoker of the method requested only modelling a single standard
828       // conversion, in only the forward direction, and they got just that.
829       LLVM_DEBUG(llvm::dbgs() << "<<< calculateMixability. Implicit "
830                                  "conversion, one-way, standard-only.\n");
831       return {MixFlags::ImplicitConversion, MixLTR.Conversion};
832     }
833 
834     // Otherwise if the invoker requested a full modelling, do the other
835     // direction as well.
836     MixData MixRTL =
837         approximateImplicitConversion(Check, RType, LType, Ctx, ImplicitMode);
838     LLVM_DEBUG(
839         if (hasFlag(MixRTL.Flags, MixFlags::ImplicitConversion)) llvm::dbgs()
840             << "--- calculateMixability. Implicit Right -> Left found.\n";);
841 
842     if (MixLTR.Conversion && MixRTL.Conversion) {
843       LLVM_DEBUG(
844           llvm::dbgs()
845           << "<<< calculateMixability. Implicit conversion, bidirectional.\n");
846       return {MixFlags::ImplicitConversion, MixLTR.Conversion,
847               MixRTL.Conversion};
848     }
849   }
850 
851   if (RecursiveReturnDiscardingCanonicalType)
852     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. Before CanonicalType, "
853                                "Discard was enabled.\n");
854 
855   // Certain kinds unfortunately need to be side-stepped for canonical type
856   // matching.
857   if (LType->getAs<FunctionProtoType>() || RType->getAs<FunctionProtoType>()) {
858     // Unfortunately, the canonical type of a function pointer becomes the
859     // same even if exactly one is "noexcept" and the other isn't, making us
860     // give a false positive report irrespective of implicit conversions.
861     LLVM_DEBUG(llvm::dbgs()
862                << "--- calculateMixability. Discarding potential canonical "
863                   "equivalence on FunctionProtoTypes.\n");
864     RecursiveReturnDiscardingCanonicalType = true;
865   }
866 
867   MixData MixToReturn{MixFlags::None};
868 
869   // If none of the previous logic found a match, try if Clang otherwise
870   // believes the types to be the same.
871   QualType LCanonical = LType.getCanonicalType();
872   if (LCanonical == RType.getCanonicalType()) {
873     LLVM_DEBUG(llvm::dbgs()
874                << "<<< calculateMixability. Same CanonicalType.\n");
875     MixToReturn = {MixFlags::Canonical, LCanonical};
876   }
877 
878   if (RecursiveReturnDiscardingCanonicalType)
879     MixToReturn |= MixFlags::WorkaroundDisableCanonicalEquivalence;
880 
881   LLVM_DEBUG(if (MixToReturn.Flags == MixFlags::None) llvm::dbgs()
882              << "<<< calculateMixability. No match found.\n");
883   return MixToReturn;
884 }
885 
886 /// Calculates if the reference binds an expression of the given type. This is
887 /// true iff 'LRef' is some 'const T &' type, and the 'Ty' is 'T' or 'const T'.
888 ///
889 /// \param ImplicitMode is forwarded in the possible recursive call to
890 /// calculateMixability.
891 static MixData
isLRefEquallyBindingToType(const TheCheck & Check,const LValueReferenceType * LRef,QualType Ty,const ASTContext & Ctx,bool IsRefRHS,ImplicitConversionModellingMode ImplicitMode)892 isLRefEquallyBindingToType(const TheCheck &Check,
893                            const LValueReferenceType *LRef, QualType Ty,
894                            const ASTContext &Ctx, bool IsRefRHS,
895                            ImplicitConversionModellingMode ImplicitMode) {
896   LLVM_DEBUG(llvm::dbgs() << ">>> isLRefEquallyBindingToType for LRef:\n";
897              LRef->dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand Type:\n";
898              Ty.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';);
899 
900   QualType ReferredType = LRef->getPointeeType();
901   if (!ReferredType.isLocalConstQualified() &&
902       ReferredType->getAs<TypedefType>()) {
903     LLVM_DEBUG(
904         llvm::dbgs()
905         << "--- isLRefEquallyBindingToType. Non-const LRef to Typedef.\n");
906     ReferredType = ReferredType.getDesugaredType(Ctx);
907     if (!ReferredType.isLocalConstQualified()) {
908       LLVM_DEBUG(llvm::dbgs()
909                  << "<<< isLRefEquallyBindingToType. Typedef is not const.\n");
910       return {MixFlags::None};
911     }
912 
913     LLVM_DEBUG(llvm::dbgs() << "--- isLRefEquallyBindingToType. Typedef is "
914                                "const, considering as const LRef.\n");
915   } else if (!ReferredType.isLocalConstQualified()) {
916     LLVM_DEBUG(llvm::dbgs()
917                << "<<< isLRefEquallyBindingToType. Not const LRef.\n");
918     return {MixFlags::None};
919   };
920 
921   assert(ReferredType.isLocalConstQualified() &&
922          "Reaching this point means we are sure LRef is effectively a const&.");
923 
924   if (ReferredType == Ty) {
925     LLVM_DEBUG(
926         llvm::dbgs()
927         << "<<< isLRefEquallyBindingToType. Type of referred matches.\n");
928     return {MixFlags::Trivial, ReferredType};
929   }
930 
931   QualType NonConstReferredType = ReferredType;
932   NonConstReferredType.removeLocalConst();
933   if (NonConstReferredType == Ty) {
934     LLVM_DEBUG(llvm::dbgs() << "<<< isLRefEquallyBindingToType. Type of "
935                                "referred matches to non-const qualified.\n");
936     return {MixFlags::Trivial, NonConstReferredType};
937   }
938 
939   LLVM_DEBUG(
940       llvm::dbgs()
941       << "--- isLRefEquallyBindingToType. Checking mix for underlying type.\n");
942   return IsRefRHS ? calculateMixability(Check, Ty, NonConstReferredType, Ctx,
943                                         ImplicitMode)
944                   : calculateMixability(Check, NonConstReferredType, Ty, Ctx,
945                                         ImplicitMode);
946 }
947 
isDerivedToBase(const CXXRecordDecl * Derived,const CXXRecordDecl * Base)948 static inline bool isDerivedToBase(const CXXRecordDecl *Derived,
949                                    const CXXRecordDecl *Base) {
950   return Derived && Base && Derived->isCompleteDefinition() &&
951          Base->isCompleteDefinition() && Derived->isDerivedFrom(Base);
952 }
953 
954 static std::optional<QualType>
approximateStandardConversionSequence(const TheCheck & Check,QualType From,QualType To,const ASTContext & Ctx)955 approximateStandardConversionSequence(const TheCheck &Check, QualType From,
956                                       QualType To, const ASTContext &Ctx) {
957   LLVM_DEBUG(llvm::dbgs() << ">>> approximateStdConv for LType:\n";
958              From.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";
959              To.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';);
960 
961   // A standard conversion sequence consists of the following, in order:
962   //  * Maybe either LValue->RValue conv., Array->Ptr conv., Function->Ptr conv.
963   //  * Maybe Numeric promotion or conversion.
964   //  * Maybe function pointer conversion.
965   //  * Maybe qualifier adjustments.
966   QualType WorkType = From;
967   // Get out the qualifiers of the original type. This will always be
968   // re-applied to the WorkType to ensure it is the same qualification as the
969   // original From was.
970   auto FastQualifiersToApply = static_cast<unsigned>(
971       From.split().Quals.getAsOpaqueValue() & Qualifiers::FastMask);
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()
996                << "--- approximateStdConv. Conversion between numerics.\n");
997     WorkType = QualType{ToBuiltin, FastQualifiersToApply};
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()
1005                << "--- approximateStdConv. Unscoped enum to numeric.\n");
1006     WorkType = QualType{ToBuiltin, FastQualifiersToApply};
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 "
1011                                  "enum, not possible in C++!\n");
1012       return {};
1013     }
1014 
1015     LLVM_DEBUG(llvm::dbgs()
1016                << "--- approximateStdConv. Numeric to unscoped enum.\n");
1017     WorkType = QualType{ToEnum, FastQualifiersToApply};
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");
1026       WorkType = QualType{ToPtr, FastQualifiersToApply};
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");
1033       WorkType = QualType{ToPtr, FastQualifiersToApply};
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");
1043     WorkType = QualType{ToRecord->getTypeForDecl(), FastQualifiersToApply};
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 "
1057                                  "pointer to non-noexcept.\n");
1058       WorkType = QualType{ToPtr, FastQualifiersToApply};
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()
1065              << "--- approximateStdConv. Trying qualifier adjustment...\n");
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()
1071                << "<<< approximateStdConv. Qualifiers adjusted.\n");
1072     WorkType = To;
1073   }
1074 
1075   if (WorkType == To) {
1076     LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Reached 'To' type.\n");
1077     return {WorkType};
1078   }
1079 
1080   LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Did not reach 'To'.\n");
1081   return {};
1082 }
1083 
1084 namespace {
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.
1089 class UserDefinedConversionSelector {
1090 public:
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 
PreparedConversionclang::tidy::bugprone::model::__anoneac3b3da0811::UserDefinedConversionSelector::PreparedConversion1100     PreparedConversion(const CXXMethodDecl *CMD, MixFlags F,
1101                        ConversionSequence S)
1102         : ConversionFun(CMD), Flags(F), Seq(S) {}
1103   };
1104 
UserDefinedConversionSelector(const TheCheck & Check)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.
addConversion(const CXXMethodDecl * ConvFun,QualType FromType,QualType ToType)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: "
1124                             << formatMixFlags(Mix.Flags) << '\n');
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.
operator ()() const1130   std::optional<PreparedConversion> operator()() const {
1131     if (FlaggedConversions.empty()) {
1132       LLVM_DEBUG(llvm::dbgs() << "--- selectUserDefinedConv. Empty.\n");
1133       return {};
1134     }
1135     if (FlaggedConversions.size() == 1) {
1136       LLVM_DEBUG(llvm::dbgs() << "--- selectUserDefinedConv. Single.\n");
1137       return FlaggedConversions.front();
1138     }
1139 
1140     std::optional<PreparedConversion> BestConversion;
1141     unsigned short HowManyGoodConversions = 0;
1142     for (const auto &Prepared : FlaggedConversions) {
1143       LLVM_DEBUG(llvm::dbgs() << "--- selectUserDefinedConv. Candidate flags: "
1144                               << formatMixFlags(Prepared.Flags) << '\n');
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()
1177                  << "--- selectUserDefinedConv. Unique result. Flags: "
1178                  << formatMixFlags(BestConversion->Flags) << '\n');
1179       return BestConversion;
1180     }
1181 
1182     LLVM_DEBUG(llvm::dbgs()
1183                << "--- selectUserDefinedConv. No, or ambiguous.\n");
1184     return {};
1185   }
1186 
1187 private:
1188   llvm::SmallVector<PreparedConversion, 2> FlaggedConversions;
1189   const TheCheck &Check;
1190 };
1191 
1192 } // namespace
1193 
1194 static std::optional<ConversionSequence>
tryConversionOperators(const TheCheck & Check,const CXXRecordDecl * RD,QualType ToType)1195 tryConversionOperators(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()
1202                           << " to:\n";
1203              ToType.dump(llvm::dbgs(), RD->getASTContext());
1204              llvm::dbgs() << '\n';);
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";
1213                Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';);
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 (std::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");
1238     return Result;
1239   }
1240 
1241   LLVM_DEBUG(llvm::dbgs() << "<<< tryConversionOperators. No conversion.\n");
1242   return {};
1243 }
1244 
1245 static std::optional<ConversionSequence>
tryConvertingConstructors(const TheCheck & Check,QualType FromType,const CXXRecordDecl * RD)1246 tryConvertingConstructors(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()
1253                           << " from:\n";
1254              FromType.dump(llvm::dbgs(), RD->getASTContext());
1255              llvm::dbgs() << '\n';);
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";
1264                Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';);
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 (std::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()
1285                << "<<< tryConvertingConstructors. Found result.\n");
1286     return Result;
1287   }
1288 
1289   LLVM_DEBUG(llvm::dbgs() << "<<< tryConvertingConstructors. No conversion.\n");
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.
1298 static MixData
approximateImplicitConversion(const TheCheck & Check,QualType LType,QualType RType,const ASTContext & Ctx,ImplicitConversionModellingMode ImplicitMode)1299 approximateImplicitConversion(const TheCheck &Check, QualType LType,
1300                               QualType RType, const ASTContext &Ctx,
1301                               ImplicitConversionModellingMode ImplicitMode) {
1302   LLVM_DEBUG(llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n";
1303              LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";
1304              RType.dump(llvm::dbgs(), Ctx);
1305              llvm::dbgs() << "\nimplicit mode: "; switch (ImplicitMode) {
1306                case ImplicitConversionModellingMode::None:
1307                  llvm::dbgs() << "None";
1308                  break;
1309                case ImplicitConversionModellingMode::All:
1310                  llvm::dbgs() << "All";
1311                  break;
1312                case ImplicitConversionModellingMode::OneWaySingleStandardOnly:
1313                  llvm::dbgs() << "OneWay, Single, STD Only";
1314                  break;
1315              } llvm::dbgs() << '\n';);
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   std::optional<QualType> AfterFirstStdConv =
1327       approximateStandardConversionSequence(Check, LType, RType, Ctx);
1328   if (AfterFirstStdConv) {
1329     LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Standard "
1330                                "Pre-Conversion found!\n");
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       std::optional<ConversionSequence> ConversionOperatorResult =
1347           tryConversionOperators(Check, LRD, RType);
1348       if (ConversionOperatorResult) {
1349         LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Found "
1350                                    "conversion operator.\n");
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       std::optional<ConversionSequence> ConvCtorResult =
1362           tryConvertingConstructors(Check, LType, RRD);
1363       if (ConvCtorResult) {
1364         LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Found "
1365                                    "converting constructor.\n");
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()
1375                  << "<<< approximateImplicitConversion. Found both "
1376                     "user-defined conversion kinds in the same sequence!\n");
1377       return {MixFlags::None};
1378     }
1379   }
1380 
1381   // After the potential user-defined conversion, another standard conversion
1382   // sequence might exist.
1383   LLVM_DEBUG(
1384       llvm::dbgs()
1385       << "--- approximateImplicitConversion. Try to find post-conversion.\n");
1386   MixData SecondStdConv = approximateImplicitConversion(
1387       Check, WorkType, RType, Ctx,
1388       ImplicitConversionModellingMode::OneWaySingleStandardOnly);
1389   if (SecondStdConv.indicatesMixability()) {
1390     LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Standard "
1391                                "Post-Conversion found!\n");
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()
1403                << "<<< approximateImplicitConversion. Found a conversion.\n");
1404     return {MixFlags::ImplicitConversion, ImplicitSeq};
1405   }
1406 
1407   LLVM_DEBUG(
1408       llvm::dbgs() << "<<< approximateImplicitConversion. No match found.\n");
1409   return {MixFlags::None};
1410 }
1411 
modelMixingRange(const TheCheck & Check,const FunctionDecl * FD,std::size_t StartIndex,const filter::SimilarlyUsedParameterPairSuppressor & UsageBasedSuppressor)1412 static 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");
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()
1427                << "Check param #" << I << " '" << ParamName << "'...\n");
1428     if (filter::isIgnoredParameter(Check, Ith)) {
1429       LLVM_DEBUG(llvm::dbgs() << "Param #" << I << " is ignored. Break!\n");
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 '" << ParamName
1439                               << "' follows a pattern with previous parameter '"
1440                               << PrevParamName << "'. Break!\n");
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()
1450                  << "Check mix of #" << J << " against #" << I << "...\n");
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 #" << J
1456                                 << " deemed related, ignoring...\n");
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)           : "
1471                               << formatMixFlags(M.flags()) << '\n');
1472       M.sanitize();
1473       LLVM_DEBUG(llvm::dbgs() << "Mix flags (after sanitize): "
1474                               << formatMixFlags(M.flags()) << '\n');
1475 
1476       assert(M.flagsValid() && "All flags decayed!");
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()
1486                  << "Param #" << I
1487                  << " does not mix with any in the current range. Break!\n");
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.
AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<Stmt>,paramRefExpr)1501 AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<Stmt>, paramRefExpr) {
1502   return expr(ignoringParenImpCasts(ignoringElidableConstructorCall(
1503       declRefExpr(to(parmVarDecl().bind("param"))))));
1504 }
1505 
1506 namespace 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.
isIgnoredParameter(const TheCheck & Check,const ParmVarDecl * Node)1510 static bool isIgnoredParameter(const TheCheck &Check, const ParmVarDecl *Node) {
1511   LLVM_DEBUG(llvm::dbgs() << "Checking if '" << Node->getName()
1512                           << "' is ignored.\n");
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");
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 '"
1531                             << Lexer::getSourceText(
1532                                    CharSourceRange::getTokenRange(B, E), SM, LO)
1533                             << "'...\n");
1534     if (B.isMacroID()) {
1535       LLVM_DEBUG(llvm::dbgs() << "\t\tBeginning is macro.\n");
1536       B = SM.getTopMacroCallerLoc(B);
1537     }
1538     if (E.isMacroID()) {
1539       LLVM_DEBUG(llvm::dbgs() << "\t\tEnding is macro.\n");
1540       E = Lexer::getLocForEndOfToken(SM.getTopMacroCallerLoc(E), 0, SM, LO);
1541     }
1542     LLVM_DEBUG(llvm::dbgs() << "\tType name code is '"
1543                             << Lexer::getSourceText(
1544                                    CharSourceRange::getTokenRange(B, E), SM, LO)
1545                             << "'...\n");
1546 
1547     return Lexer::getSourceText(CharSourceRange::getTokenRange(B, E), SM, LO);
1548   }();
1549 
1550   LLVM_DEBUG(llvm::dbgs() << "\tType name is '" << NodeTypeName << "'\n");
1551   if (!NodeTypeName.empty()) {
1552     if (llvm::any_of(Check.IgnoredParameterTypeSuffixes,
1553                      [NodeTypeName](StringRef E) {
1554                        return !E.empty() && NodeTypeName.ends_with(E);
1555                      })) {
1556       LLVM_DEBUG(llvm::dbgs() << "\tType suffix ignored.\n");
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.
1566 namespace relatedness_heuristic {
1567 
1568 static constexpr std::size_t SmallDataStructureSize = 4;
1569 
1570 template <typename T, std::size_t N = SmallDataStructureSize>
1571 using 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.
1576 template <typename MapTy, typename ElemTy>
lazyMapOfSetsIntersectionExists(const MapTy & Map,const ElemTy & E1,const ElemTy & E2)1577 bool 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 (E2Iterator->second.contains(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.
1595 class 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 
1604 public:
setup(const FunctionDecl * FD)1605   void setup(const FunctionDecl *FD) {
1606     this->FD = FD;
1607     TraverseFunctionDecl(const_cast<FunctionDecl *>(FD));
1608   }
1609 
operator ()(const ParmVarDecl * Param1,const ParmVarDecl * Param2) const1610   bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1611     return lazyMapOfSetsIntersectionExists(ParentExprsForParamRefs, Param1,
1612                                            Param2);
1613   }
1614 
TraverseDecl(Decl * D)1615   bool TraverseDecl(Decl *D) {
1616     CurrentExprOnlyTreeRoot = nullptr;
1617     return Base::TraverseDecl(D);
1618   }
1619 
TraverseStmt(Stmt * S,DataRecursionQueue * Queue=nullptr)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 
VisitDeclRefExpr(DeclRefExpr * DRE)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.
1657 class PassedToSameFunction {
1658   ParamToSmallSetMap<std::pair<const FunctionDecl *, unsigned>> TargetParams;
1659 
1660 public:
setup(const FunctionDecl * FD)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);
1673 
1674       const FunctionDecl *CalledFn = CE->getDirectCallee();
1675       if (!CalledFn)
1676         continue;
1677 
1678       std::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?");
1685       TargetParams[PassedParamOfThisFn].insert(
1686           {CalledFn->getCanonicalDecl(), *TargetIdx});
1687     }
1688   }
1689 
operator ()(const ParmVarDecl * Param1,const ParmVarDecl * Param2) const1690   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.
1697 class AccessedSameMemberOf {
1698   ParamToSmallSetMap<const Decl *> AccessedMembers;
1699 
1700 public:
setup(const FunctionDecl * FD)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);
1711       AccessedMembers[AccessedParam].insert(
1712           ME->getMemberDecl()->getCanonicalDecl());
1713     }
1714   }
1715 
operator ()(const ParmVarDecl * Param1,const ParmVarDecl * Param2) const1716   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.
1723 class Returned {
1724   llvm::SmallVector<const ParmVarDecl *, SmallDataStructureSize> ReturnedParams;
1725 
1726 public:
setup(const FunctionDecl * FD)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);
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 
operator ()(const ParmVarDecl * Param1,const ParmVarDecl * Param2) const1746   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.
1756 class 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 
1763 public:
SimilarlyUsedParameterPairSuppressor(const FunctionDecl * FD,bool Enable)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.
operator ()(const ParmVarDecl * Param1,const ParmVarDecl * Param2) const1777   bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1778     if (!Enabled)
1779       return false;
1780 
1781     LLVM_DEBUG(llvm::dbgs()
1782                << "::: Matching similar usage / relatedness heuristic...\n");
1783 
1784     if (SameExpr(Param1, Param2)) {
1785       LLVM_DEBUG(llvm::dbgs() << "::: Used in the same expression.\n");
1786       return true;
1787     }
1788 
1789     if (PassToFun(Param1, Param2)) {
1790       LLVM_DEBUG(llvm::dbgs()
1791                  << "::: Passed to same function in different calls.\n");
1792       return true;
1793     }
1794 
1795     if (SameMember(Param1, Param2)) {
1796       LLVM_DEBUG(llvm::dbgs()
1797                  << "::: Same member field access or method called.\n");
1798       return true;
1799     }
1800 
1801     if (Returns(Param1, Param2)) {
1802       LLVM_DEBUG(llvm::dbgs() << "::: Both parameter returned.\n");
1803       return true;
1804     }
1805 
1806     LLVM_DEBUG(llvm::dbgs() << "::: None.\n");
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.)
1813 static inline bool
isSimilarlyUsedParameter(const SimilarlyUsedParameterPairSuppressor & Suppressor,const ParmVarDecl * Param1,const ParmVarDecl * Param2)1814 isSimilarlyUsedParameter(const SimilarlyUsedParameterPairSuppressor &Suppressor,
1815                          const ParmVarDecl *Param1, const ParmVarDecl *Param2) {
1816   return Suppressor(Param1, Param2);
1817 }
1818 
padStringAtEnd(SmallVectorImpl<char> & Str,std::size_t ToLen)1819 static void padStringAtEnd(SmallVectorImpl<char> &Str, std::size_t ToLen) {
1820   while (Str.size() < ToLen)
1821     Str.emplace_back('\0');
1822 }
1823 
padStringAtBegin(SmallVectorImpl<char> & Str,std::size_t ToLen)1824 static void padStringAtBegin(SmallVectorImpl<char> &Str, std::size_t ToLen) {
1825   while (Str.size() < ToLen)
1826     Str.insert(Str.begin(), '\0');
1827 }
1828 
isCommonPrefixWithoutSomeCharacters(std::size_t N,StringRef S1,StringRef S2)1829 static bool isCommonPrefixWithoutSomeCharacters(std::size_t N, StringRef S1,
1830                                                 StringRef S2) {
1831   assert(S1.size() >= N && S2.size() >= N);
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 
isCommonSuffixWithoutSomeCharacters(std::size_t N,StringRef S1,StringRef S2)1837 static bool isCommonSuffixWithoutSomeCharacters(std::size_t N, StringRef S1,
1838                                                 StringRef S2) {
1839   assert(S1.size() >= N && S2.size() >= N);
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.
prefixSuffixCoverUnderThreshold(std::size_t Threshold,StringRef Str1,StringRef Str2)1847 static 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.
AST_MATCHER_P(FunctionDecl,parameterCountGE,unsigned,N)1886 AST_MATCHER_P(FunctionDecl, parameterCountGE, unsigned, N) {
1887   return Node.getNumParams() >= N;
1888 }
1889 
1890 /// Matches *any* overloaded unary and binary operators.
AST_MATCHER(FunctionDecl,isOverloadedUnaryOrBinaryOperator)1891 AST_MATCHER(FunctionDecl, isOverloadedUnaryOrBinaryOperator) {
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.
clampMinimumLength(const unsigned Value)1909 static 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.
getName(const NamedDecl * ND)1916 static 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.
getNameOrUnnamed(const NamedDecl * ND)1924 static 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.
needsToPrintTypeInDiagnostic(const model::Mix & M)1933 static 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.
needsToElaborateImplicitConversion(const model::Mix & M)1942 static inline bool needsToElaborateImplicitConversion(const model::Mix &M) {
1943   return hasFlag(M.flags(), model::MixFlags::ImplicitConversion);
1944 }
1945 
1946 namespace {
1947 
1948 /// This class formats a conversion sequence into a "Ty1 -> Ty2 -> Ty3" line
1949 /// that can be used in diagnostics.
1950 struct 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 = true;
1957 
FormattedConversionSequenceclang::tidy::bugprone::__anoneac3b3da0b11::FormattedConversionSequence1958   FormattedConversionSequence(const PrintingPolicy &PP,
1959                               StringRef StartTypeAsDiagnosed,
1960                               const model::ConversionSequence &Conv,
1961                               StringRef DestinationTypeAsDiagnosed) {
1962     llvm::raw_string_ostream OS{DiagnosticText};
1963 
1964     // Print the type name as it is printed in other places in the diagnostic.
1965     OS << '\'' << StartTypeAsDiagnosed << '\'';
1966     std::string LastAddedType = StartTypeAsDiagnosed.str();
1967     std::size_t NumElementsAdded = 1;
1968 
1969     // However, the parameter's defined type might not be what the implicit
1970     // conversion started with, e.g. if a typedef is found to convert.
1971     std::string SeqBeginTypeStr = Conv.Begin.getAsString(PP);
1972     std::string SeqEndTypeStr = Conv.End.getAsString(PP);
1973     if (StartTypeAsDiagnosed != SeqBeginTypeStr) {
1974       OS << " (as '" << SeqBeginTypeStr << "')";
1975       LastAddedType = SeqBeginTypeStr;
1976       Trivial = false;
1977     }
1978 
1979     auto AddType = [&](StringRef ToAdd) {
1980       if (LastAddedType != ToAdd && ToAdd != SeqEndTypeStr) {
1981         OS << " -> '" << ToAdd << "'";
1982         LastAddedType = ToAdd.str();
1983         ++NumElementsAdded;
1984       }
1985     };
1986     for (QualType InvolvedType : Conv.getInvolvedTypesInSequence())
1987       // Print every type that's unique in the sequence into the diagnosis.
1988       AddType(InvolvedType.getAsString(PP));
1989 
1990     if (LastAddedType != DestinationTypeAsDiagnosed) {
1991       OS << " -> '" << DestinationTypeAsDiagnosed << "'";
1992       LastAddedType = DestinationTypeAsDiagnosed.str();
1993       ++NumElementsAdded;
1994     }
1995 
1996     // Same reasoning as with the Begin, e.g. if the converted-to type is a
1997     // typedef, it will not be the same inside the conversion sequence (where
1998     // the model already tore off typedefs) as in the code.
1999     if (DestinationTypeAsDiagnosed != SeqEndTypeStr) {
2000       OS << " (as '" << SeqEndTypeStr << "')";
2001       LastAddedType = SeqEndTypeStr;
2002       Trivial = false;
2003     }
2004 
2005     if (Trivial && NumElementsAdded > 2)
2006       // If the thing is still marked trivial but we have more than the
2007       // from and to types added, it should not be trivial, and elaborated
2008       // when printing the diagnostic.
2009       Trivial = false;
2010   }
2011 };
2012 
2013 /// Retains the elements called with and returns whether the call is done with
2014 /// a new element.
2015 template <typename E, std::size_t N> class InsertOnce {
2016   llvm::SmallSet<E, N> CalledWith;
2017 
2018 public:
operator ()(E El)2019   bool operator()(E El) { return CalledWith.insert(std::move(El)).second; }
2020 
calledWith(const E & El) const2021   bool calledWith(const E &El) const { return CalledWith.contains(El); }
2022 };
2023 
2024 struct SwappedEqualQualTypePair {
2025   QualType LHSType, RHSType;
2026 
operator ==clang::tidy::bugprone::__anoneac3b3da0b11::SwappedEqualQualTypePair2027   bool operator==(const SwappedEqualQualTypePair &Other) const {
2028     return (LHSType == Other.LHSType && RHSType == Other.RHSType) ||
2029            (LHSType == Other.RHSType && RHSType == Other.LHSType);
2030   }
2031 
operator <clang::tidy::bugprone::__anoneac3b3da0b11::SwappedEqualQualTypePair2032   bool operator<(const SwappedEqualQualTypePair &Other) const {
2033     return LHSType < Other.LHSType && RHSType < Other.RHSType;
2034   }
2035 };
2036 
2037 struct TypeAliasDiagnosticTuple {
2038   QualType LHSType, RHSType, CommonType;
2039 
operator ==clang::tidy::bugprone::__anoneac3b3da0b11::TypeAliasDiagnosticTuple2040   bool operator==(const TypeAliasDiagnosticTuple &Other) const {
2041     return CommonType == Other.CommonType &&
2042            ((LHSType == Other.LHSType && RHSType == Other.RHSType) ||
2043             (LHSType == Other.RHSType && RHSType == Other.LHSType));
2044   }
2045 
operator <clang::tidy::bugprone::__anoneac3b3da0b11::TypeAliasDiagnosticTuple2046   bool operator<(const TypeAliasDiagnosticTuple &Other) const {
2047     return CommonType < Other.CommonType && LHSType < Other.LHSType &&
2048            RHSType < Other.RHSType;
2049   }
2050 };
2051 
2052 /// Helper class to only emit a diagnostic related to MixFlags::TypeAlias once.
2053 class UniqueTypeAliasDiagnosticHelper
2054     : public InsertOnce<TypeAliasDiagnosticTuple, 8> {
2055   using Base = InsertOnce<TypeAliasDiagnosticTuple, 8>;
2056 
2057 public:
2058   /// Returns whether the diagnostic for LHSType and RHSType which are both
2059   /// referring to CommonType being the same has not been emitted already.
operator ()(QualType LHSType,QualType RHSType,QualType CommonType)2060   bool operator()(QualType LHSType, QualType RHSType, QualType CommonType) {
2061     if (CommonType.isNull() || CommonType == LHSType || CommonType == RHSType)
2062       return Base::operator()({LHSType, RHSType, {}});
2063 
2064     TypeAliasDiagnosticTuple ThreeTuple{LHSType, RHSType, CommonType};
2065     if (!Base::operator()(ThreeTuple))
2066       return false;
2067 
2068     bool AlreadySaidLHSAndCommonIsSame = calledWith({LHSType, CommonType, {}});
2069     bool AlreadySaidRHSAndCommonIsSame = calledWith({RHSType, CommonType, {}});
2070     if (AlreadySaidLHSAndCommonIsSame && AlreadySaidRHSAndCommonIsSame) {
2071       // "SomeInt == int" && "SomeOtherInt == int" => "Common(SomeInt,
2072       // SomeOtherInt) == int", no need to diagnose it. Save the 3-tuple only
2073       // for shortcut if it ever appears again.
2074       return false;
2075     }
2076 
2077     return true;
2078   }
2079 };
2080 
2081 } // namespace
2082 
EasilySwappableParametersCheck(StringRef Name,ClangTidyContext * Context)2083 EasilySwappableParametersCheck::EasilySwappableParametersCheck(
2084     StringRef Name, ClangTidyContext *Context)
2085     : ClangTidyCheck(Name, Context),
2086       MinimumLength(clampMinimumLength(
2087           Options.get("MinimumLength", DefaultMinimumLength))),
2088       IgnoredParameterNames(optutils::parseStringList(
2089           Options.get("IgnoredParameterNames", DefaultIgnoredParameterNames))),
2090       IgnoredParameterTypeSuffixes(optutils::parseStringList(
2091           Options.get("IgnoredParameterTypeSuffixes",
2092                       DefaultIgnoredParameterTypeSuffixes))),
2093       QualifiersMix(Options.get("QualifiersMix", DefaultQualifiersMix)),
2094       ModelImplicitConversions(Options.get("ModelImplicitConversions",
2095                                            DefaultModelImplicitConversions)),
2096       SuppressParametersUsedTogether(
2097           Options.get("SuppressParametersUsedTogether",
2098                       DefaultSuppressParametersUsedTogether)),
2099       NamePrefixSuffixSilenceDissimilarityTreshold(
2100           Options.get("NamePrefixSuffixSilenceDissimilarityTreshold",
2101                       DefaultNamePrefixSuffixSilenceDissimilarityTreshold)) {}
2102 
storeOptions(ClangTidyOptions::OptionMap & Opts)2103 void EasilySwappableParametersCheck::storeOptions(
2104     ClangTidyOptions::OptionMap &Opts) {
2105   Options.store(Opts, "MinimumLength", MinimumLength);
2106   Options.store(Opts, "IgnoredParameterNames",
2107                 optutils::serializeStringList(IgnoredParameterNames));
2108   Options.store(Opts, "IgnoredParameterTypeSuffixes",
2109                 optutils::serializeStringList(IgnoredParameterTypeSuffixes));
2110   Options.store(Opts, "QualifiersMix", QualifiersMix);
2111   Options.store(Opts, "ModelImplicitConversions", ModelImplicitConversions);
2112   Options.store(Opts, "SuppressParametersUsedTogether",
2113                 SuppressParametersUsedTogether);
2114   Options.store(Opts, "NamePrefixSuffixSilenceDissimilarityTreshold",
2115                 NamePrefixSuffixSilenceDissimilarityTreshold);
2116 }
2117 
registerMatchers(MatchFinder * Finder)2118 void EasilySwappableParametersCheck::registerMatchers(MatchFinder *Finder) {
2119   const auto BaseConstraints = functionDecl(
2120       // Only report for definition nodes, as fixing the issues reported
2121       // requires the user to be able to change code.
2122       isDefinition(), parameterCountGE(MinimumLength),
2123       unless(isOverloadedUnaryOrBinaryOperator()));
2124 
2125   Finder->addMatcher(
2126       functionDecl(BaseConstraints,
2127                    unless(ast_matchers::isTemplateInstantiation()))
2128           .bind("func"),
2129       this);
2130   Finder->addMatcher(
2131       functionDecl(BaseConstraints, isExplicitTemplateSpecialization())
2132           .bind("func"),
2133       this);
2134 }
2135 
check(const MatchFinder::MatchResult & Result)2136 void EasilySwappableParametersCheck::check(
2137     const MatchFinder::MatchResult &Result) {
2138   using namespace model;
2139   using namespace filter;
2140 
2141   const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("func");
2142   assert(FD);
2143 
2144   const PrintingPolicy &PP = FD->getASTContext().getPrintingPolicy();
2145   std::size_t NumParams = FD->getNumParams();
2146   std::size_t MixableRangeStartIndex = 0;
2147 
2148   // Spawn one suppressor and if the user requested, gather information from
2149   // the AST for the parameters' usages.
2150   filter::SimilarlyUsedParameterPairSuppressor UsageBasedSuppressor{
2151       FD, SuppressParametersUsedTogether};
2152 
2153   LLVM_DEBUG(llvm::dbgs() << "Begin analysis of " << getName(FD) << " with "
2154                           << NumParams << " parameters...\n");
2155   while (MixableRangeStartIndex < NumParams) {
2156     if (isIgnoredParameter(*this, FD->getParamDecl(MixableRangeStartIndex))) {
2157       LLVM_DEBUG(llvm::dbgs()
2158                  << "Parameter #" << MixableRangeStartIndex << " ignored.\n");
2159       ++MixableRangeStartIndex;
2160       continue;
2161     }
2162 
2163     MixableParameterRange R = modelMixingRange(
2164         *this, FD, MixableRangeStartIndex, UsageBasedSuppressor);
2165     assert(R.NumParamsChecked > 0 && "Ensure forward progress!");
2166     MixableRangeStartIndex += R.NumParamsChecked;
2167     if (R.NumParamsChecked < MinimumLength) {
2168       LLVM_DEBUG(llvm::dbgs() << "Ignoring range of " << R.NumParamsChecked
2169                               << " lower than limit.\n");
2170       continue;
2171     }
2172 
2173     bool NeedsAnyTypeNote = llvm::any_of(R.Mixes, needsToPrintTypeInDiagnostic);
2174     bool HasAnyImplicits =
2175         llvm::any_of(R.Mixes, needsToElaborateImplicitConversion);
2176     const ParmVarDecl *First = R.getFirstParam(), *Last = R.getLastParam();
2177     std::string FirstParamTypeAsWritten = First->getType().getAsString(PP);
2178     {
2179       StringRef DiagText;
2180 
2181       if (HasAnyImplicits)
2182         DiagText = "%0 adjacent parameters of %1 of convertible types are "
2183                    "easily swapped by mistake";
2184       else if (NeedsAnyTypeNote)
2185         DiagText = "%0 adjacent parameters of %1 of similar type are easily "
2186                    "swapped by mistake";
2187       else
2188         DiagText = "%0 adjacent parameters of %1 of similar type ('%2') are "
2189                    "easily swapped by mistake";
2190 
2191       auto Diag = diag(First->getOuterLocStart(), DiagText)
2192                   << static_cast<unsigned>(R.NumParamsChecked) << FD;
2193       if (!NeedsAnyTypeNote)
2194         Diag << FirstParamTypeAsWritten;
2195 
2196       CharSourceRange HighlightRange = CharSourceRange::getTokenRange(
2197           First->getBeginLoc(), Last->getEndLoc());
2198       Diag << HighlightRange;
2199     }
2200 
2201     // There is a chance that the previous highlight did not succeed, e.g. when
2202     // the two parameters are on different lines. For clarity, show the user
2203     // the involved variable explicitly.
2204     diag(First->getLocation(), "the first parameter in the range is '%0'",
2205          DiagnosticIDs::Note)
2206         << getNameOrUnnamed(First)
2207         << CharSourceRange::getTokenRange(First->getLocation(),
2208                                           First->getLocation());
2209     diag(Last->getLocation(), "the last parameter in the range is '%0'",
2210          DiagnosticIDs::Note)
2211         << getNameOrUnnamed(Last)
2212         << CharSourceRange::getTokenRange(Last->getLocation(),
2213                                           Last->getLocation());
2214 
2215     // Helper classes to silence elaborative diagnostic notes that would be
2216     // too verbose.
2217     UniqueTypeAliasDiagnosticHelper UniqueTypeAlias;
2218     InsertOnce<SwappedEqualQualTypePair, 8> UniqueBindPower;
2219     InsertOnce<SwappedEqualQualTypePair, 8> UniqueImplicitConversion;
2220 
2221     for (const model::Mix &M : R.Mixes) {
2222       assert(M.mixable() && "Sentinel or false mix in result.");
2223       if (!needsToPrintTypeInDiagnostic(M) &&
2224           !needsToElaborateImplicitConversion(M))
2225         continue;
2226 
2227       // Typedefs might result in the type of the variable needing to be
2228       // emitted to a note diagnostic, so prepare it.
2229       const ParmVarDecl *LVar = M.First;
2230       const ParmVarDecl *RVar = M.Second;
2231       QualType LType = LVar->getType();
2232       QualType RType = RVar->getType();
2233       QualType CommonType = M.commonUnderlyingType();
2234       std::string LTypeStr = LType.getAsString(PP);
2235       std::string RTypeStr = RType.getAsString(PP);
2236       std::string CommonTypeStr = CommonType.getAsString(PP);
2237 
2238       if (hasFlag(M.flags(), MixFlags::TypeAlias) &&
2239           UniqueTypeAlias(LType, RType, CommonType)) {
2240         StringRef DiagText;
2241         bool ExplicitlyPrintCommonType = false;
2242         if (LTypeStr == CommonTypeStr || RTypeStr == CommonTypeStr) {
2243           if (hasFlag(M.flags(), MixFlags::Qualifiers))
2244             DiagText = "after resolving type aliases, '%0' and '%1' share a "
2245                        "common type";
2246           else
2247             DiagText =
2248                 "after resolving type aliases, '%0' and '%1' are the same";
2249         } else if (!CommonType.isNull()) {
2250           DiagText = "after resolving type aliases, the common type of '%0' "
2251                      "and '%1' is '%2'";
2252           ExplicitlyPrintCommonType = true;
2253         }
2254 
2255         auto Diag =
2256             diag(LVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2257             << LTypeStr << RTypeStr;
2258         if (ExplicitlyPrintCommonType)
2259           Diag << CommonTypeStr;
2260       }
2261 
2262       if ((hasFlag(M.flags(), MixFlags::ReferenceBind) ||
2263            hasFlag(M.flags(), MixFlags::Qualifiers)) &&
2264           UniqueBindPower({LType, RType})) {
2265         StringRef DiagText = "'%0' and '%1' parameters accept and bind the "
2266                              "same kind of values";
2267         diag(RVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2268             << LTypeStr << RTypeStr;
2269       }
2270 
2271       if (needsToElaborateImplicitConversion(M) &&
2272           UniqueImplicitConversion({LType, RType})) {
2273         const model::ConversionSequence &LTR =
2274             M.leftToRightConversionSequence();
2275         const model::ConversionSequence &RTL =
2276             M.rightToLeftConversionSequence();
2277         FormattedConversionSequence LTRFmt{PP, LTypeStr, LTR, RTypeStr};
2278         FormattedConversionSequence RTLFmt{PP, RTypeStr, RTL, LTypeStr};
2279 
2280         StringRef DiagText = "'%0' and '%1' may be implicitly converted";
2281         if (!LTRFmt.Trivial || !RTLFmt.Trivial)
2282           DiagText = "'%0' and '%1' may be implicitly converted: %2, %3";
2283 
2284         {
2285           auto Diag =
2286               diag(RVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2287               << LTypeStr << RTypeStr;
2288 
2289           if (!LTRFmt.Trivial || !RTLFmt.Trivial)
2290             Diag << LTRFmt.DiagnosticText << RTLFmt.DiagnosticText;
2291         }
2292 
2293         StringRef ConversionFunctionDiagText =
2294             "the implicit conversion involves the "
2295             "%select{|converting constructor|conversion operator}0 "
2296             "declared here";
2297         if (const FunctionDecl *LFD = LTR.getUserDefinedConversionFunction())
2298           diag(LFD->getLocation(), ConversionFunctionDiagText,
2299                DiagnosticIDs::Note)
2300               << static_cast<unsigned>(LTR.UDConvKind)
2301               << LTR.getUserDefinedConversionHighlight();
2302         if (const FunctionDecl *RFD = RTL.getUserDefinedConversionFunction())
2303           diag(RFD->getLocation(), ConversionFunctionDiagText,
2304                DiagnosticIDs::Note)
2305               << static_cast<unsigned>(RTL.UDConvKind)
2306               << RTL.getUserDefinedConversionHighlight();
2307       }
2308     }
2309   }
2310 }
2311 
2312 } // namespace clang::tidy::bugprone
2313