xref: /llvm-project/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp (revision f4efa067435c8137718c907bf0de2b891b76552d)
1499e39c5SWhisperity //===--- EasilySwappableParametersCheck.cpp - clang-tidy ------------------===//
2499e39c5SWhisperity //
3499e39c5SWhisperity // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4499e39c5SWhisperity // See https://llvm.org/LICENSE.txt for license information.
5499e39c5SWhisperity // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6499e39c5SWhisperity //
7499e39c5SWhisperity //===----------------------------------------------------------------------===//
8499e39c5SWhisperity 
9499e39c5SWhisperity #include "EasilySwappableParametersCheck.h"
10499e39c5SWhisperity #include "../utils/OptionsUtils.h"
11499e39c5SWhisperity #include "clang/AST/ASTContext.h"
12b9ece034SWhisperity #include "clang/AST/RecursiveASTVisitor.h"
13499e39c5SWhisperity #include "clang/ASTMatchers/ASTMatchFinder.h"
14499e39c5SWhisperity #include "clang/Lex/Lexer.h"
1526d864b4SWhisperity #include "llvm/ADT/SmallSet.h"
16499e39c5SWhisperity 
17499e39c5SWhisperity #define DEBUG_TYPE "EasilySwappableParametersCheck"
18499e39c5SWhisperity #include "llvm/Support/Debug.h"
1971f55735SKazu Hirata #include <optional>
20499e39c5SWhisperity 
21499e39c5SWhisperity namespace optutils = clang::tidy::utils::options;
22499e39c5SWhisperity 
23499e39c5SWhisperity /// The default value for the MinimumLength check option.
24499e39c5SWhisperity static constexpr std::size_t DefaultMinimumLength = 2;
25499e39c5SWhisperity 
26499e39c5SWhisperity /// The default value for ignored parameter names.
27a4bdeb9aSNathan James static constexpr llvm::StringLiteral DefaultIgnoredParameterNames = "\"\";"
28a4bdeb9aSNathan James                                                                     "iterator;"
29a4bdeb9aSNathan James                                                                     "Iterator;"
30a4bdeb9aSNathan James                                                                     "begin;"
31a4bdeb9aSNathan James                                                                     "Begin;"
32a4bdeb9aSNathan James                                                                     "end;"
33a4bdeb9aSNathan James                                                                     "End;"
34a4bdeb9aSNathan James                                                                     "first;"
35a4bdeb9aSNathan James                                                                     "First;"
36a4bdeb9aSNathan James                                                                     "last;"
37a4bdeb9aSNathan James                                                                     "Last;"
38a4bdeb9aSNathan James                                                                     "lhs;"
39a4bdeb9aSNathan James                                                                     "LHS;"
40a4bdeb9aSNathan James                                                                     "rhs;"
41a4bdeb9aSNathan James                                                                     "RHS";
42499e39c5SWhisperity 
43499e39c5SWhisperity /// The default value for ignored parameter type suffixes.
44a4bdeb9aSNathan James static constexpr llvm::StringLiteral DefaultIgnoredParameterTypeSuffixes =
45a4bdeb9aSNathan James     "bool;"
46a4bdeb9aSNathan James     "Bool;"
47a4bdeb9aSNathan James     "_Bool;"
48a4bdeb9aSNathan James     "it;"
49a4bdeb9aSNathan James     "It;"
50a4bdeb9aSNathan James     "iterator;"
51a4bdeb9aSNathan James     "Iterator;"
52a4bdeb9aSNathan James     "inputit;"
53a4bdeb9aSNathan James     "InputIt;"
54a4bdeb9aSNathan James     "forwardit;"
55a4bdeb9aSNathan James     "ForwardIt;"
56a4bdeb9aSNathan James     "bidirit;"
57a4bdeb9aSNathan James     "BidirIt;"
58a4bdeb9aSNathan James     "constiterator;"
59a4bdeb9aSNathan James     "const_iterator;"
60a4bdeb9aSNathan James     "Const_Iterator;"
61a4bdeb9aSNathan James     "Constiterator;"
62a4bdeb9aSNathan James     "ConstIterator;"
63a4bdeb9aSNathan James     "RandomIt;"
64a4bdeb9aSNathan James     "randomit;"
65a4bdeb9aSNathan James     "random_iterator;"
66a4bdeb9aSNathan James     "ReverseIt;"
67a4bdeb9aSNathan James     "reverse_iterator;"
68a4bdeb9aSNathan James     "reverse_const_iterator;"
69a4bdeb9aSNathan James     "ConstReverseIterator;"
70a4bdeb9aSNathan James     "Const_Reverse_Iterator;"
71a4bdeb9aSNathan James     "const_reverse_iterator;"
72a4bdeb9aSNathan James     "Constreverseiterator;"
73a4bdeb9aSNathan James     "constreverseiterator";
74499e39c5SWhisperity 
75961e9e6aSWhisperity /// The default value for the QualifiersMix check option.
76961e9e6aSWhisperity static constexpr bool DefaultQualifiersMix = false;
77961e9e6aSWhisperity 
78e33d0478SWhisperity /// The default value for the ModelImplicitConversions check option.
79e33d0478SWhisperity static constexpr bool DefaultModelImplicitConversions = true;
80e33d0478SWhisperity 
81b9ece034SWhisperity /// The default value for suppressing diagnostics about parameters that are
82b9ece034SWhisperity /// used together.
83b9ece034SWhisperity static constexpr bool DefaultSuppressParametersUsedTogether = true;
84b9ece034SWhisperity 
850fba450bSWhisperity /// The default value for the NamePrefixSuffixSilenceDissimilarityTreshold
860fba450bSWhisperity /// check option.
870fba450bSWhisperity static constexpr std::size_t
880fba450bSWhisperity     DefaultNamePrefixSuffixSilenceDissimilarityTreshold = 1;
890fba450bSWhisperity 
90499e39c5SWhisperity using namespace clang::ast_matchers;
91499e39c5SWhisperity 
927d2ea6c4SCarlos Galvez namespace clang::tidy::bugprone {
93499e39c5SWhisperity 
94499e39c5SWhisperity using TheCheck = EasilySwappableParametersCheck;
95499e39c5SWhisperity 
96499e39c5SWhisperity namespace filter {
97b9ece034SWhisperity class SimilarlyUsedParameterPairSuppressor;
98b9ece034SWhisperity 
99499e39c5SWhisperity static bool isIgnoredParameter(const TheCheck &Check, const ParmVarDecl *Node);
100b9ece034SWhisperity static inline bool
101b9ece034SWhisperity isSimilarlyUsedParameter(const SimilarlyUsedParameterPairSuppressor &Suppressor,
102b9ece034SWhisperity                          const ParmVarDecl *Param1, const ParmVarDecl *Param2);
1030fba450bSWhisperity static bool prefixSuffixCoverUnderThreshold(std::size_t Threshold,
1040fba450bSWhisperity                                             StringRef Str1, StringRef Str2);
105499e39c5SWhisperity } // namespace filter
106499e39c5SWhisperity 
107499e39c5SWhisperity namespace model {
108499e39c5SWhisperity 
109499e39c5SWhisperity /// The language features involved in allowing the mix between two parameters.
110499e39c5SWhisperity enum class MixFlags : unsigned char {
111f3b55a8aSWhisperity   Invalid = 0, ///< Sentinel bit pattern. DO NOT USE!
112499e39c5SWhisperity 
113f3b55a8aSWhisperity   /// Certain constructs (such as pointers to noexcept/non-noexcept functions)
114f3b55a8aSWhisperity   /// have the same CanonicalType, which would result in false positives.
115f3b55a8aSWhisperity   /// During the recursive modelling call, this flag is set if a later diagnosed
116f3b55a8aSWhisperity   /// canonical type equivalence should be thrown away.
117e33d0478SWhisperity   WorkaroundDisableCanonicalEquivalence = 1,
118499e39c5SWhisperity 
119f3b55a8aSWhisperity   None = 2,           ///< Mix between the two parameters is not possible.
120f3b55a8aSWhisperity   Trivial = 4,        ///< The two mix trivially, and are the exact same type.
121f3b55a8aSWhisperity   Canonical = 8,      ///< The two mix because the types refer to the same
122f3b55a8aSWhisperity                       /// CanonicalType, but we do not elaborate as to how.
123f3b55a8aSWhisperity   TypeAlias = 16,     ///< The path from one type to the other involves
124f3b55a8aSWhisperity                       /// desugaring type aliases.
125f3b55a8aSWhisperity   ReferenceBind = 32, ///< The mix involves the binding power of "const &".
126f3b55a8aSWhisperity   Qualifiers = 64,    ///< The mix involves change in the qualifiers.
127f3b55a8aSWhisperity   ImplicitConversion = 128, ///< The mixing of the parameters is possible
128f3b55a8aSWhisperity                             /// through implicit conversions between the types.
129e33d0478SWhisperity 
130e33d0478SWhisperity   LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue =*/ImplicitConversion)
131499e39c5SWhisperity };
132499e39c5SWhisperity LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
133499e39c5SWhisperity 
134499e39c5SWhisperity /// Returns whether the SearchedFlag is turned on in the Data.
hasFlag(MixFlags Data,MixFlags SearchedFlag)135499e39c5SWhisperity static inline bool hasFlag(MixFlags Data, MixFlags SearchedFlag) {
136499e39c5SWhisperity   assert(SearchedFlag != MixFlags::Invalid &&
137499e39c5SWhisperity          "can't be used to detect lack of all bits!");
138499e39c5SWhisperity 
139499e39c5SWhisperity   // "Data & SearchedFlag" would need static_cast<bool>() in conditions.
140499e39c5SWhisperity   return (Data & SearchedFlag) == SearchedFlag;
141499e39c5SWhisperity }
142499e39c5SWhisperity 
143499e39c5SWhisperity #ifndef NDEBUG
144499e39c5SWhisperity 
145499e39c5SWhisperity // The modelling logic of this check is more complex than usual, and
146499e39c5SWhisperity // potentially hard to understand without the ability to see into the
147499e39c5SWhisperity // representation during the recursive descent. This debug code is only
148499e39c5SWhisperity // compiled in 'Debug' mode, or if LLVM_ENABLE_ASSERTIONS config is turned on.
149499e39c5SWhisperity 
150499e39c5SWhisperity /// Formats the MixFlags enum into a useful, user-readable representation.
formatMixFlags(MixFlags F)151499e39c5SWhisperity static inline std::string formatMixFlags(MixFlags F) {
152499e39c5SWhisperity   if (F == MixFlags::Invalid)
153499e39c5SWhisperity     return "#Inv!";
154499e39c5SWhisperity 
155e33d0478SWhisperity   SmallString<8> Str{"-------"};
156499e39c5SWhisperity 
157499e39c5SWhisperity   if (hasFlag(F, MixFlags::None))
158499e39c5SWhisperity     // Shows the None bit explicitly, as it can be applied in the recursion
159499e39c5SWhisperity     // even if other bits are set.
160499e39c5SWhisperity     Str[0] = '!';
161499e39c5SWhisperity   if (hasFlag(F, MixFlags::Trivial))
162499e39c5SWhisperity     Str[1] = 'T';
163499e39c5SWhisperity   if (hasFlag(F, MixFlags::Canonical))
164499e39c5SWhisperity     Str[2] = 'C';
16526d864b4SWhisperity   if (hasFlag(F, MixFlags::TypeAlias))
16626d864b4SWhisperity     Str[3] = 't';
16726d864b4SWhisperity   if (hasFlag(F, MixFlags::ReferenceBind))
16826d864b4SWhisperity     Str[4] = '&';
169961e9e6aSWhisperity   if (hasFlag(F, MixFlags::Qualifiers))
170961e9e6aSWhisperity     Str[5] = 'Q';
171e33d0478SWhisperity   if (hasFlag(F, MixFlags::ImplicitConversion))
172e33d0478SWhisperity     Str[6] = 'i';
173e33d0478SWhisperity 
174e33d0478SWhisperity   if (hasFlag(F, MixFlags::WorkaroundDisableCanonicalEquivalence))
175e33d0478SWhisperity     Str.append("(~C)");
176499e39c5SWhisperity 
177499e39c5SWhisperity   return Str.str().str();
178499e39c5SWhisperity }
179499e39c5SWhisperity 
180499e39c5SWhisperity #endif // NDEBUG
181499e39c5SWhisperity 
182e33d0478SWhisperity /// The results of the steps of an Implicit Conversion Sequence is saved in
183e33d0478SWhisperity /// an instance of this record.
184e33d0478SWhisperity ///
185e33d0478SWhisperity /// A ConversionSequence maps the steps of the conversion with a member for
186e33d0478SWhisperity /// each type involved in the conversion. Imagine going from a hypothetical
187e33d0478SWhisperity /// Complex class to projecting it to the real part as a const double.
188e33d0478SWhisperity ///
189e33d0478SWhisperity /// I.e., given:
190e33d0478SWhisperity ///
191e33d0478SWhisperity ///    struct Complex {
192e33d0478SWhisperity ///      operator double() const;
193e33d0478SWhisperity ///    };
194e33d0478SWhisperity ///
195e33d0478SWhisperity ///    void functionBeingAnalysed(Complex C, const double R);
196e33d0478SWhisperity ///
197e33d0478SWhisperity /// we will get the following sequence:
198e33d0478SWhisperity ///
199e33d0478SWhisperity /// (Begin=) Complex
200e33d0478SWhisperity ///
201e33d0478SWhisperity ///     The first standard conversion is a qualification adjustment.
202e33d0478SWhisperity /// (AfterFirstStandard=) const Complex
203e33d0478SWhisperity ///
204e33d0478SWhisperity ///     Then the user-defined conversion is executed.
205e33d0478SWhisperity /// (UDConvOp.ConversionOperatorResultType=) double
206e33d0478SWhisperity ///
207e33d0478SWhisperity ///     Then this 'double' is qualifier-adjusted to 'const double'.
208e33d0478SWhisperity /// (AfterSecondStandard=) double
209e33d0478SWhisperity ///
210e33d0478SWhisperity /// The conversion's result has now been calculated, so it ends here.
211e33d0478SWhisperity /// (End=) double.
212e33d0478SWhisperity ///
213e33d0478SWhisperity /// Explicit storing of Begin and End in this record is needed, because
214e33d0478SWhisperity /// getting to what Begin and End here are needs further resolution of types,
215e33d0478SWhisperity /// e.g. in the case of typedefs:
216e33d0478SWhisperity ///
217e33d0478SWhisperity ///     using Comp = Complex;
218e33d0478SWhisperity ///     using CD = const double;
219e33d0478SWhisperity ///     void functionBeingAnalysed2(Comp C, CD R);
220e33d0478SWhisperity ///
221e33d0478SWhisperity /// In this case, the user will be diagnosed with a potential conversion
222e33d0478SWhisperity /// between the two typedefs as written in the code, but to elaborate the
223e33d0478SWhisperity /// reasoning behind this conversion, we also need to show what the typedefs
224e33d0478SWhisperity /// mean. See FormattedConversionSequence towards the bottom of this file!
225e33d0478SWhisperity struct ConversionSequence {
226e33d0478SWhisperity   enum UserDefinedConversionKind { UDCK_None, UDCK_Ctor, UDCK_Oper };
227e33d0478SWhisperity 
228e33d0478SWhisperity   struct UserDefinedConvertingConstructor {
229e33d0478SWhisperity     const CXXConstructorDecl *Fun;
230e33d0478SWhisperity     QualType ConstructorParameterType;
231e33d0478SWhisperity     QualType UserDefinedType;
232e33d0478SWhisperity   };
233e33d0478SWhisperity 
234e33d0478SWhisperity   struct UserDefinedConversionOperator {
235e33d0478SWhisperity     const CXXConversionDecl *Fun;
236e33d0478SWhisperity     QualType UserDefinedType;
237e33d0478SWhisperity     QualType ConversionOperatorResultType;
238e33d0478SWhisperity   };
239e33d0478SWhisperity 
240e33d0478SWhisperity   /// The type the conversion stared from.
241e33d0478SWhisperity   QualType Begin;
242e33d0478SWhisperity 
243e33d0478SWhisperity   /// The intermediate type after the first Standard Conversion Sequence.
244e33d0478SWhisperity   QualType AfterFirstStandard;
245e33d0478SWhisperity 
246e33d0478SWhisperity   /// The details of the user-defined conversion involved, as a tagged union.
247e33d0478SWhisperity   union {
248e33d0478SWhisperity     char None;
249e33d0478SWhisperity     UserDefinedConvertingConstructor UDConvCtor;
250e33d0478SWhisperity     UserDefinedConversionOperator UDConvOp;
251e33d0478SWhisperity   };
252e33d0478SWhisperity   UserDefinedConversionKind UDConvKind;
253e33d0478SWhisperity 
254e33d0478SWhisperity   /// The intermediate type after performing the second Standard Conversion
255e33d0478SWhisperity   /// Sequence.
256e33d0478SWhisperity   QualType AfterSecondStandard;
257e33d0478SWhisperity 
258e33d0478SWhisperity   /// The result type the conversion targeted.
259e33d0478SWhisperity   QualType End;
260e33d0478SWhisperity 
ConversionSequenceclang::tidy::bugprone::model::ConversionSequence261e33d0478SWhisperity   ConversionSequence() : None(0), UDConvKind(UDCK_None) {}
ConversionSequenceclang::tidy::bugprone::model::ConversionSequence262e33d0478SWhisperity   ConversionSequence(QualType From, QualType To)
263e33d0478SWhisperity       : Begin(From), None(0), UDConvKind(UDCK_None), End(To) {}
264e33d0478SWhisperity 
operator boolclang::tidy::bugprone::model::ConversionSequence265e33d0478SWhisperity   explicit operator bool() const {
266e33d0478SWhisperity     return !AfterFirstStandard.isNull() || UDConvKind != UDCK_None ||
267e33d0478SWhisperity            !AfterSecondStandard.isNull();
268e33d0478SWhisperity   }
269e33d0478SWhisperity 
270e33d0478SWhisperity   /// Returns all the "steps" (non-unique and non-similar) types involved in
271e33d0478SWhisperity   /// the conversion sequence. This method does **NOT** return Begin and End.
getInvolvedTypesInSequenceclang::tidy::bugprone::model::ConversionSequence272e33d0478SWhisperity   SmallVector<QualType, 4> getInvolvedTypesInSequence() const {
273e33d0478SWhisperity     SmallVector<QualType, 4> Ret;
274e33d0478SWhisperity     auto EmplaceIfDifferent = [&Ret](QualType QT) {
275e33d0478SWhisperity       if (QT.isNull())
276e33d0478SWhisperity         return;
277e33d0478SWhisperity       if (Ret.empty())
278e33d0478SWhisperity         Ret.emplace_back(QT);
279e33d0478SWhisperity       else if (Ret.back() != QT)
280e33d0478SWhisperity         Ret.emplace_back(QT);
281e33d0478SWhisperity     };
282e33d0478SWhisperity 
283e33d0478SWhisperity     EmplaceIfDifferent(AfterFirstStandard);
284e33d0478SWhisperity     switch (UDConvKind) {
285e33d0478SWhisperity     case UDCK_Ctor:
286e33d0478SWhisperity       EmplaceIfDifferent(UDConvCtor.ConstructorParameterType);
287e33d0478SWhisperity       EmplaceIfDifferent(UDConvCtor.UserDefinedType);
288e33d0478SWhisperity       break;
289e33d0478SWhisperity     case UDCK_Oper:
290e33d0478SWhisperity       EmplaceIfDifferent(UDConvOp.UserDefinedType);
291e33d0478SWhisperity       EmplaceIfDifferent(UDConvOp.ConversionOperatorResultType);
292e33d0478SWhisperity       break;
293e33d0478SWhisperity     case UDCK_None:
294e33d0478SWhisperity       break;
295e33d0478SWhisperity     }
296e33d0478SWhisperity     EmplaceIfDifferent(AfterSecondStandard);
297e33d0478SWhisperity 
298e33d0478SWhisperity     return Ret;
299e33d0478SWhisperity   }
300e33d0478SWhisperity 
301e33d0478SWhisperity   /// Updates the steps of the conversion sequence with the steps from the
302e33d0478SWhisperity   /// other instance.
303e33d0478SWhisperity   ///
304e33d0478SWhisperity   /// \note This method does not check if the resulting conversion sequence is
305e33d0478SWhisperity   /// sensible!
updateclang::tidy::bugprone::model::ConversionSequence306e33d0478SWhisperity   ConversionSequence &update(const ConversionSequence &RHS) {
307e33d0478SWhisperity     if (!RHS.AfterFirstStandard.isNull())
308e33d0478SWhisperity       AfterFirstStandard = RHS.AfterFirstStandard;
309e33d0478SWhisperity     switch (RHS.UDConvKind) {
310e33d0478SWhisperity     case UDCK_Ctor:
311e33d0478SWhisperity       UDConvKind = UDCK_Ctor;
312e33d0478SWhisperity       UDConvCtor = RHS.UDConvCtor;
313e33d0478SWhisperity       break;
314e33d0478SWhisperity     case UDCK_Oper:
315e33d0478SWhisperity       UDConvKind = UDCK_Oper;
316e33d0478SWhisperity       UDConvOp = RHS.UDConvOp;
317e33d0478SWhisperity       break;
318e33d0478SWhisperity     case UDCK_None:
319e33d0478SWhisperity       break;
320e33d0478SWhisperity     }
321e33d0478SWhisperity     if (!RHS.AfterSecondStandard.isNull())
322e33d0478SWhisperity       AfterSecondStandard = RHS.AfterSecondStandard;
323e33d0478SWhisperity 
324e33d0478SWhisperity     return *this;
325e33d0478SWhisperity   }
326e33d0478SWhisperity 
327e33d0478SWhisperity   /// Sets the user-defined conversion to the given constructor.
setConversionclang::tidy::bugprone::model::ConversionSequence328e33d0478SWhisperity   void setConversion(const UserDefinedConvertingConstructor &UDCC) {
329e33d0478SWhisperity     UDConvKind = UDCK_Ctor;
330e33d0478SWhisperity     UDConvCtor = UDCC;
331e33d0478SWhisperity   }
332e33d0478SWhisperity 
333e33d0478SWhisperity   /// Sets the user-defined conversion to the given operator.
setConversionclang::tidy::bugprone::model::ConversionSequence334e33d0478SWhisperity   void setConversion(const UserDefinedConversionOperator &UDCO) {
335e33d0478SWhisperity     UDConvKind = UDCK_Oper;
336e33d0478SWhisperity     UDConvOp = UDCO;
337e33d0478SWhisperity   }
338e33d0478SWhisperity 
339e33d0478SWhisperity   /// Returns the type in the conversion that's formally "in our hands" once
340e33d0478SWhisperity   /// the user-defined conversion is executed.
getTypeAfterUserDefinedConversionclang::tidy::bugprone::model::ConversionSequence341e33d0478SWhisperity   QualType getTypeAfterUserDefinedConversion() const {
342e33d0478SWhisperity     switch (UDConvKind) {
343e33d0478SWhisperity     case UDCK_Ctor:
344e33d0478SWhisperity       return UDConvCtor.UserDefinedType;
345e33d0478SWhisperity     case UDCK_Oper:
346e33d0478SWhisperity       return UDConvOp.ConversionOperatorResultType;
347e33d0478SWhisperity     case UDCK_None:
348e33d0478SWhisperity       return {};
349e33d0478SWhisperity     }
350e33d0478SWhisperity     llvm_unreachable("Invalid UDConv kind.");
351e33d0478SWhisperity   }
352e33d0478SWhisperity 
getUserDefinedConversionFunctionclang::tidy::bugprone::model::ConversionSequence353e33d0478SWhisperity   const CXXMethodDecl *getUserDefinedConversionFunction() const {
354e33d0478SWhisperity     switch (UDConvKind) {
355e33d0478SWhisperity     case UDCK_Ctor:
356e33d0478SWhisperity       return UDConvCtor.Fun;
357e33d0478SWhisperity     case UDCK_Oper:
358e33d0478SWhisperity       return UDConvOp.Fun;
359e33d0478SWhisperity     case UDCK_None:
360e33d0478SWhisperity       return {};
361e33d0478SWhisperity     }
362e33d0478SWhisperity     llvm_unreachable("Invalid UDConv kind.");
363e33d0478SWhisperity   }
364e33d0478SWhisperity 
365e33d0478SWhisperity   /// Returns the SourceRange in the text that corresponds to the interesting
366e33d0478SWhisperity   /// part of the user-defined conversion. This is either the parameter type
367e33d0478SWhisperity   /// in a converting constructor, or the conversion result type in a conversion
368e33d0478SWhisperity   /// operator.
getUserDefinedConversionHighlightclang::tidy::bugprone::model::ConversionSequence369e33d0478SWhisperity   SourceRange getUserDefinedConversionHighlight() const {
370e33d0478SWhisperity     switch (UDConvKind) {
371e33d0478SWhisperity     case UDCK_Ctor:
372e33d0478SWhisperity       return UDConvCtor.Fun->getParamDecl(0)->getSourceRange();
373e33d0478SWhisperity     case UDCK_Oper:
374e33d0478SWhisperity       // getReturnTypeSourceRange() does not work for CXXConversionDecls as the
375e33d0478SWhisperity       // returned type is physically behind the declaration's name ("operator").
376e33d0478SWhisperity       if (const FunctionTypeLoc FTL = UDConvOp.Fun->getFunctionTypeLoc())
377e33d0478SWhisperity         if (const TypeLoc RetLoc = FTL.getReturnLoc())
378e33d0478SWhisperity           return RetLoc.getSourceRange();
379e33d0478SWhisperity       return {};
380e33d0478SWhisperity     case UDCK_None:
381e33d0478SWhisperity       return {};
382e33d0478SWhisperity     }
383e33d0478SWhisperity     llvm_unreachable("Invalid UDConv kind.");
384e33d0478SWhisperity   }
385e33d0478SWhisperity };
386e33d0478SWhisperity 
387499e39c5SWhisperity /// Contains the metadata for the mixability result between two types,
388499e39c5SWhisperity /// independently of which parameters they were calculated from.
389499e39c5SWhisperity struct MixData {
39026d864b4SWhisperity   /// The flag bits of the mix indicating what language features allow for it.
391e33d0478SWhisperity   MixFlags Flags = MixFlags::Invalid;
392499e39c5SWhisperity 
39326d864b4SWhisperity   /// A potentially calculated common underlying type after desugaring, that
39426d864b4SWhisperity   /// both sides of the mix can originate from.
39526d864b4SWhisperity   QualType CommonType;
39626d864b4SWhisperity 
397e33d0478SWhisperity   /// The steps an implicit conversion performs to get from one type to the
398e33d0478SWhisperity   /// other.
399e33d0478SWhisperity   ConversionSequence Conversion, ConversionRTL;
400e33d0478SWhisperity 
401e33d0478SWhisperity   /// True if the MixData was specifically created with only a one-way
402e33d0478SWhisperity   /// conversion modelled.
403e33d0478SWhisperity   bool CreatedFromOneWayConversion = false;
404e33d0478SWhisperity 
MixDataclang::tidy::bugprone::model::MixData405499e39c5SWhisperity   MixData(MixFlags Flags) : Flags(Flags) {}
MixDataclang::tidy::bugprone::model::MixData40626d864b4SWhisperity   MixData(MixFlags Flags, QualType CommonType)
40726d864b4SWhisperity       : Flags(Flags), CommonType(CommonType) {}
MixDataclang::tidy::bugprone::model::MixData408e33d0478SWhisperity   MixData(MixFlags Flags, ConversionSequence Conv)
409e33d0478SWhisperity       : Flags(Flags), Conversion(Conv), CreatedFromOneWayConversion(true) {}
MixDataclang::tidy::bugprone::model::MixData410e33d0478SWhisperity   MixData(MixFlags Flags, ConversionSequence LTR, ConversionSequence RTL)
411e33d0478SWhisperity       : Flags(Flags), Conversion(LTR), ConversionRTL(RTL) {}
MixDataclang::tidy::bugprone::model::MixData412e33d0478SWhisperity   MixData(MixFlags Flags, QualType CommonType, ConversionSequence LTR,
413e33d0478SWhisperity           ConversionSequence RTL)
414e33d0478SWhisperity       : Flags(Flags), CommonType(CommonType), Conversion(LTR),
415e33d0478SWhisperity         ConversionRTL(RTL) {}
416499e39c5SWhisperity 
sanitizeclang::tidy::bugprone::model::MixData417499e39c5SWhisperity   void sanitize() {
418499e39c5SWhisperity     assert(Flags != MixFlags::Invalid && "sanitize() called on invalid bitvec");
41926d864b4SWhisperity 
420e33d0478SWhisperity     MixFlags CanonicalAndWorkaround =
421e33d0478SWhisperity         MixFlags::Canonical | MixFlags::WorkaroundDisableCanonicalEquivalence;
422e33d0478SWhisperity     if ((Flags & CanonicalAndWorkaround) == CanonicalAndWorkaround) {
423e33d0478SWhisperity       // A workaround for too eagerly equivalent canonical types was requested,
424e33d0478SWhisperity       // and a canonical equivalence was proven. Fulfill the request and throw
425e33d0478SWhisperity       // this result away.
426e33d0478SWhisperity       Flags = MixFlags::None;
427e33d0478SWhisperity       return;
428e33d0478SWhisperity     }
429e33d0478SWhisperity 
43026d864b4SWhisperity     if (hasFlag(Flags, MixFlags::None)) {
43126d864b4SWhisperity       // If anywhere down the recursion a potential mix "path" is deemed
43226d864b4SWhisperity       // impossible, throw away all the other bits because the mix is not
43326d864b4SWhisperity       // possible.
43426d864b4SWhisperity       Flags = MixFlags::None;
43526d864b4SWhisperity       return;
43626d864b4SWhisperity     }
43726d864b4SWhisperity 
43826d864b4SWhisperity     if (Flags == MixFlags::Trivial)
43926d864b4SWhisperity       return;
44026d864b4SWhisperity 
44126d864b4SWhisperity     if (static_cast<bool>(Flags ^ MixFlags::Trivial))
44226d864b4SWhisperity       // If the mix involves somewhere trivial equivalence but down the
44326d864b4SWhisperity       // recursion other bit(s) were set, remove the trivial bit, as it is not
44426d864b4SWhisperity       // trivial.
44526d864b4SWhisperity       Flags &= ~MixFlags::Trivial;
446e33d0478SWhisperity 
447e33d0478SWhisperity     bool ShouldHaveImplicitConvFlag = false;
448e33d0478SWhisperity     if (CreatedFromOneWayConversion && Conversion)
449e33d0478SWhisperity       ShouldHaveImplicitConvFlag = true;
450e33d0478SWhisperity     else if (!CreatedFromOneWayConversion && Conversion && ConversionRTL)
451e33d0478SWhisperity       // Only say that we have implicit conversion mix possibility if it is
452e33d0478SWhisperity       // bidirectional. Otherwise, the compiler would report an *actual* swap
453e33d0478SWhisperity       // at a call site...
454e33d0478SWhisperity       ShouldHaveImplicitConvFlag = true;
455e33d0478SWhisperity 
456e33d0478SWhisperity     if (ShouldHaveImplicitConvFlag)
457e33d0478SWhisperity       Flags |= MixFlags::ImplicitConversion;
458e33d0478SWhisperity     else
459e33d0478SWhisperity       Flags &= ~MixFlags::ImplicitConversion;
46026d864b4SWhisperity   }
46126d864b4SWhisperity 
isValidclang::tidy::bugprone::model::MixData462e33d0478SWhisperity   bool isValid() const { return Flags >= MixFlags::None; }
463e33d0478SWhisperity 
indicatesMixabilityclang::tidy::bugprone::model::MixData464e33d0478SWhisperity   bool indicatesMixability() const { return Flags > MixFlags::None; }
465e33d0478SWhisperity 
466961e9e6aSWhisperity   /// Add the specified flag bits to the flags.
operator |clang::tidy::bugprone::model::MixData46726d864b4SWhisperity   MixData operator|(MixFlags EnableFlags) const {
468e33d0478SWhisperity     if (CreatedFromOneWayConversion) {
469e33d0478SWhisperity       MixData M{Flags | EnableFlags, Conversion};
470e33d0478SWhisperity       M.CommonType = CommonType;
471e33d0478SWhisperity       return M;
472e33d0478SWhisperity     }
473e33d0478SWhisperity     return {Flags | EnableFlags, CommonType, Conversion, ConversionRTL};
47426d864b4SWhisperity   }
475961e9e6aSWhisperity 
476961e9e6aSWhisperity   /// Add the specified flag bits to the flags.
operator |=clang::tidy::bugprone::model::MixData47726d864b4SWhisperity   MixData &operator|=(MixFlags EnableFlags) {
47826d864b4SWhisperity     Flags |= EnableFlags;
47926d864b4SWhisperity     return *this;
480499e39c5SWhisperity   }
481961e9e6aSWhisperity 
withCommonTypeTransformedclang::tidy::bugprone::model::MixData48226078f33SPiotr Zegar   template <typename F> MixData withCommonTypeTransformed(const F &Func) const {
483473eff1cSWhisperity     if (CommonType.isNull())
484473eff1cSWhisperity       return *this;
485473eff1cSWhisperity 
4868b0cc4a6SWhisperity     QualType NewCommonType = Func(CommonType);
487961e9e6aSWhisperity 
488e33d0478SWhisperity     if (CreatedFromOneWayConversion) {
489e33d0478SWhisperity       MixData M{Flags, Conversion};
490473eff1cSWhisperity       M.CommonType = NewCommonType;
491e33d0478SWhisperity       return M;
492e33d0478SWhisperity     }
4938b0cc4a6SWhisperity 
494473eff1cSWhisperity     return {Flags, NewCommonType, Conversion, ConversionRTL};
495961e9e6aSWhisperity   }
496499e39c5SWhisperity };
497499e39c5SWhisperity 
498499e39c5SWhisperity /// A named tuple that contains the information for a mix between two concrete
499499e39c5SWhisperity /// parameters.
500499e39c5SWhisperity struct Mix {
501499e39c5SWhisperity   const ParmVarDecl *First, *Second;
502499e39c5SWhisperity   MixData Data;
503499e39c5SWhisperity 
Mixclang::tidy::bugprone::model::Mix504499e39c5SWhisperity   Mix(const ParmVarDecl *F, const ParmVarDecl *S, MixData Data)
505499e39c5SWhisperity       : First(F), Second(S), Data(std::move(Data)) {}
506499e39c5SWhisperity 
sanitizeclang::tidy::bugprone::model::Mix507499e39c5SWhisperity   void sanitize() { Data.sanitize(); }
flagsclang::tidy::bugprone::model::Mix508499e39c5SWhisperity   MixFlags flags() const { return Data.Flags; }
flagsValidclang::tidy::bugprone::model::Mix509e33d0478SWhisperity   bool flagsValid() const { return Data.isValid(); }
mixableclang::tidy::bugprone::model::Mix510e33d0478SWhisperity   bool mixable() const { return Data.indicatesMixability(); }
commonUnderlyingTypeclang::tidy::bugprone::model::Mix51126d864b4SWhisperity   QualType commonUnderlyingType() const { return Data.CommonType; }
leftToRightConversionSequenceclang::tidy::bugprone::model::Mix512e33d0478SWhisperity   const ConversionSequence &leftToRightConversionSequence() const {
513e33d0478SWhisperity     return Data.Conversion;
514e33d0478SWhisperity   }
rightToLeftConversionSequenceclang::tidy::bugprone::model::Mix515e33d0478SWhisperity   const ConversionSequence &rightToLeftConversionSequence() const {
516e33d0478SWhisperity     return Data.ConversionRTL;
517e33d0478SWhisperity   }
518499e39c5SWhisperity };
519499e39c5SWhisperity 
520499e39c5SWhisperity // NOLINTNEXTLINE(misc-redundant-expression): Seems to be a bogus warning.
5217142f731SPiotr Zegar static_assert(std::is_trivially_copyable_v<Mix> &&
5227142f731SPiotr Zegar                   std::is_trivially_move_constructible_v<Mix> &&
5237142f731SPiotr Zegar                   std::is_trivially_move_assignable_v<Mix>,
524499e39c5SWhisperity               "Keep frequently used data simple!");
525499e39c5SWhisperity 
526499e39c5SWhisperity struct MixableParameterRange {
527499e39c5SWhisperity   /// A container for Mixes.
528499e39c5SWhisperity   using MixVector = SmallVector<Mix, 8>;
529499e39c5SWhisperity 
530499e39c5SWhisperity   /// The number of parameters iterated to build the instance.
531499e39c5SWhisperity   std::size_t NumParamsChecked = 0;
532499e39c5SWhisperity 
533499e39c5SWhisperity   /// The individual flags and supporting information for the mixes.
534499e39c5SWhisperity   MixVector Mixes;
535499e39c5SWhisperity 
536499e39c5SWhisperity   /// Gets the leftmost parameter of the range.
getFirstParamclang::tidy::bugprone::model::MixableParameterRange537499e39c5SWhisperity   const ParmVarDecl *getFirstParam() const {
538499e39c5SWhisperity     // The first element is the LHS of the very first mix in the range.
539499e39c5SWhisperity     assert(!Mixes.empty());
540499e39c5SWhisperity     return Mixes.front().First;
541499e39c5SWhisperity   }
542499e39c5SWhisperity 
543499e39c5SWhisperity   /// Gets the rightmost parameter of the range.
getLastParamclang::tidy::bugprone::model::MixableParameterRange544499e39c5SWhisperity   const ParmVarDecl *getLastParam() const {
545499e39c5SWhisperity     // The builder function breaks building an instance of this type if it
546499e39c5SWhisperity     // finds something that can not be mixed with the rest, by going *forward*
547499e39c5SWhisperity     // in the list of parameters. So at any moment of break, the RHS of the last
548499e39c5SWhisperity     // element of the mix vector is also the last element of the mixing range.
549499e39c5SWhisperity     assert(!Mixes.empty());
550499e39c5SWhisperity     return Mixes.back().Second;
551499e39c5SWhisperity   }
552499e39c5SWhisperity };
553499e39c5SWhisperity 
554e33d0478SWhisperity /// Helper enum for the recursive calls in the modelling that toggle what kinds
555e33d0478SWhisperity /// of implicit conversions are to be modelled.
556f3b55a8aSWhisperity enum class ImplicitConversionModellingMode : unsigned char {
5578b0cc4a6SWhisperity   ///< No implicit conversions are modelled.
558f3b55a8aSWhisperity   None,
559e33d0478SWhisperity 
5608b0cc4a6SWhisperity   ///< The full implicit conversion sequence is modelled.
561f3b55a8aSWhisperity   All,
562e33d0478SWhisperity 
5638b0cc4a6SWhisperity   ///< Only model a unidirectional implicit conversion and within it only one
564f3b55a8aSWhisperity   /// standard conversion sequence.
565f3b55a8aSWhisperity   OneWaySingleStandardOnly
566e33d0478SWhisperity };
567e33d0478SWhisperity 
568e33d0478SWhisperity static MixData
569e33d0478SWhisperity isLRefEquallyBindingToType(const TheCheck &Check,
570e33d0478SWhisperity                            const LValueReferenceType *LRef, QualType Ty,
571e33d0478SWhisperity                            const ASTContext &Ctx, bool IsRefRHS,
572e33d0478SWhisperity                            ImplicitConversionModellingMode ImplicitMode);
573e33d0478SWhisperity 
574e33d0478SWhisperity static MixData
575e33d0478SWhisperity approximateImplicitConversion(const TheCheck &Check, QualType LType,
576e33d0478SWhisperity                               QualType RType, const ASTContext &Ctx,
577e33d0478SWhisperity                               ImplicitConversionModellingMode ImplicitMode);
578e33d0478SWhisperity 
isUselessSugar(const Type * T)579e33d0478SWhisperity static inline bool isUselessSugar(const Type *T) {
580473eff1cSWhisperity   return isa<AttributedType, DecayedType, ElaboratedType, ParenType>(T);
581473eff1cSWhisperity }
582473eff1cSWhisperity 
5838b0cc4a6SWhisperity namespace {
5848b0cc4a6SWhisperity 
5858b0cc4a6SWhisperity struct NonCVRQualifiersResult {
5868b0cc4a6SWhisperity   /// True if the types are qualified in a way that even after equating or
5878b0cc4a6SWhisperity   /// removing local CVR qualification, even if the unqualified types
5888b0cc4a6SWhisperity   /// themselves would mix, the qualified ones don't, because there are some
5898b0cc4a6SWhisperity   /// other local qualifiers that are not equal.
5908b0cc4a6SWhisperity   bool HasMixabilityBreakingQualifiers;
5918b0cc4a6SWhisperity 
5928b0cc4a6SWhisperity   /// The set of equal qualifiers between the two types.
5938b0cc4a6SWhisperity   Qualifiers CommonQualifiers;
5948b0cc4a6SWhisperity };
5958b0cc4a6SWhisperity 
5968b0cc4a6SWhisperity } // namespace
5978b0cc4a6SWhisperity 
598473eff1cSWhisperity /// Returns if the two types are qualified in a way that ever after equating or
599473eff1cSWhisperity /// removing local CVR qualification, even if the unqualified types would mix,
600473eff1cSWhisperity /// the qualified ones don't, because there are some other local qualifiers
601473eff1cSWhisperity /// that aren't equal.
6028b0cc4a6SWhisperity static NonCVRQualifiersResult
getNonCVRQualifiers(const ASTContext & Ctx,QualType LType,QualType RType)6038b0cc4a6SWhisperity getNonCVRQualifiers(const ASTContext &Ctx, QualType LType, QualType RType) {
6048b0cc4a6SWhisperity   LLVM_DEBUG(llvm::dbgs() << ">>> getNonCVRQualifiers for LType:\n";
605473eff1cSWhisperity              LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";
606473eff1cSWhisperity              RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';);
607473eff1cSWhisperity   Qualifiers LQual = LType.getLocalQualifiers(),
608473eff1cSWhisperity              RQual = RType.getLocalQualifiers();
609473eff1cSWhisperity 
610473eff1cSWhisperity   // Strip potential CVR. That is handled by the check option QualifiersMix.
611473eff1cSWhisperity   LQual.removeCVRQualifiers();
612473eff1cSWhisperity   RQual.removeCVRQualifiers();
613473eff1cSWhisperity 
6148b0cc4a6SWhisperity   NonCVRQualifiersResult Ret;
6158b0cc4a6SWhisperity   Ret.CommonQualifiers = Qualifiers::removeCommonQualifiers(LQual, RQual);
616473eff1cSWhisperity 
617473eff1cSWhisperity   LLVM_DEBUG(llvm::dbgs() << "--- hasNonCVRMixabilityBreakingQualifiers. "
618473eff1cSWhisperity                              "Removed common qualifiers: ";
6198b0cc4a6SWhisperity              Ret.CommonQualifiers.print(llvm::dbgs(), Ctx.getPrintingPolicy());
620473eff1cSWhisperity              llvm::dbgs() << "\n\tremaining on LType: ";
621473eff1cSWhisperity              LQual.print(llvm::dbgs(), Ctx.getPrintingPolicy());
622473eff1cSWhisperity              llvm::dbgs() << "\n\tremaining on RType: ";
623473eff1cSWhisperity              RQual.print(llvm::dbgs(), Ctx.getPrintingPolicy());
624473eff1cSWhisperity              llvm::dbgs() << '\n';);
625473eff1cSWhisperity 
6268b0cc4a6SWhisperity   // If there are no other non-cvr non-common qualifiers left, we can deduce
6278b0cc4a6SWhisperity   // that mixability isn't broken.
6288b0cc4a6SWhisperity   Ret.HasMixabilityBreakingQualifiers =
6298b0cc4a6SWhisperity       LQual.hasQualifiers() || RQual.hasQualifiers();
6308b0cc4a6SWhisperity 
6318b0cc4a6SWhisperity   return Ret;
632e33d0478SWhisperity }
63326d864b4SWhisperity 
634499e39c5SWhisperity /// Approximate the way how LType and RType might refer to "essentially the
635499e39c5SWhisperity /// same" type, in a sense that at a particular call site, an expression of
636499e39c5SWhisperity /// type LType and RType might be successfully passed to a variable (in our
637499e39c5SWhisperity /// specific case, a parameter) of type RType and LType, respectively.
638499e39c5SWhisperity /// Note the swapped order!
639499e39c5SWhisperity ///
640499e39c5SWhisperity /// The returned data structure is not guaranteed to be properly set, as this
641499e39c5SWhisperity /// function is potentially recursive. It is the caller's responsibility to
642499e39c5SWhisperity /// call sanitize() on the result once the recursion is over.
643e33d0478SWhisperity static MixData
calculateMixability(const TheCheck & Check,QualType LType,QualType RType,const ASTContext & Ctx,ImplicitConversionModellingMode ImplicitMode)644e33d0478SWhisperity calculateMixability(const TheCheck &Check, QualType LType, QualType RType,
645e33d0478SWhisperity                     const ASTContext &Ctx,
646e33d0478SWhisperity                     ImplicitConversionModellingMode ImplicitMode) {
647499e39c5SWhisperity   LLVM_DEBUG(llvm::dbgs() << ">>> calculateMixability for LType:\n";
648499e39c5SWhisperity              LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";
649499e39c5SWhisperity              RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';);
650499e39c5SWhisperity   if (LType == RType) {
651499e39c5SWhisperity     LLVM_DEBUG(llvm::dbgs() << "<<< calculateMixability. Trivial equality.\n");
65226d864b4SWhisperity     return {MixFlags::Trivial, LType};
653499e39c5SWhisperity   }
654499e39c5SWhisperity 
65526d864b4SWhisperity   // Dissolve certain type sugars that do not affect the mixability of one type
65626d864b4SWhisperity   // with the other, and also do not require any sort of elaboration for the
65726d864b4SWhisperity   // user to understand.
658e33d0478SWhisperity   if (isUselessSugar(LType.getTypePtr())) {
659e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs()
660e33d0478SWhisperity                << "--- calculateMixability. LHS is useless sugar.\n");
66126d864b4SWhisperity     return calculateMixability(Check, LType.getSingleStepDesugaredType(Ctx),
662e33d0478SWhisperity                                RType, Ctx, ImplicitMode);
66326d864b4SWhisperity   }
664e33d0478SWhisperity   if (isUselessSugar(RType.getTypePtr())) {
665e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs()
666e33d0478SWhisperity                << "--- calculateMixability. RHS is useless sugar.\n");
667e33d0478SWhisperity     return calculateMixability(
668e33d0478SWhisperity         Check, LType, RType.getSingleStepDesugaredType(Ctx), Ctx, ImplicitMode);
66926d864b4SWhisperity   }
67026d864b4SWhisperity 
6718b0cc4a6SWhisperity   const auto *LLRef = LType->getAs<LValueReferenceType>();
6728b0cc4a6SWhisperity   const auto *RLRef = RType->getAs<LValueReferenceType>();
6738b0cc4a6SWhisperity   if (LLRef && RLRef) {
6748b0cc4a6SWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. LHS and RHS are &.\n");
6758b0cc4a6SWhisperity 
6768b0cc4a6SWhisperity     return calculateMixability(Check, LLRef->getPointeeType(),
6778b0cc4a6SWhisperity                                RLRef->getPointeeType(), Ctx, ImplicitMode)
6788b0cc4a6SWhisperity         .withCommonTypeTransformed(
6798b0cc4a6SWhisperity             [&Ctx](QualType QT) { return Ctx.getLValueReferenceType(QT); });
6808b0cc4a6SWhisperity   }
68126d864b4SWhisperity   // At a particular call site, what could be passed to a 'T' or 'const T' might
68226d864b4SWhisperity   // also be passed to a 'const T &' without the call site putting a direct
68326d864b4SWhisperity   // side effect on the passed expressions.
6848b0cc4a6SWhisperity   if (LLRef) {
68526d864b4SWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. LHS is &.\n");
6868b0cc4a6SWhisperity     return isLRefEquallyBindingToType(Check, LLRef, RType, Ctx, false,
687e33d0478SWhisperity                                       ImplicitMode) |
68826d864b4SWhisperity            MixFlags::ReferenceBind;
68926d864b4SWhisperity   }
6908b0cc4a6SWhisperity   if (RLRef) {
69126d864b4SWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. RHS is &.\n");
6928b0cc4a6SWhisperity     return isLRefEquallyBindingToType(Check, RLRef, LType, Ctx, true,
693e33d0478SWhisperity                                       ImplicitMode) |
69426d864b4SWhisperity            MixFlags::ReferenceBind;
69526d864b4SWhisperity   }
696499e39c5SWhisperity 
697961e9e6aSWhisperity   if (LType->getAs<TypedefType>()) {
698961e9e6aSWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. LHS is typedef.\n");
699961e9e6aSWhisperity     return calculateMixability(Check, LType.getSingleStepDesugaredType(Ctx),
700e33d0478SWhisperity                                RType, Ctx, ImplicitMode) |
701961e9e6aSWhisperity            MixFlags::TypeAlias;
702961e9e6aSWhisperity   }
703961e9e6aSWhisperity   if (RType->getAs<TypedefType>()) {
704961e9e6aSWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. RHS is typedef.\n");
705961e9e6aSWhisperity     return calculateMixability(Check, LType,
706e33d0478SWhisperity                                RType.getSingleStepDesugaredType(Ctx), Ctx,
707e33d0478SWhisperity                                ImplicitMode) |
708961e9e6aSWhisperity            MixFlags::TypeAlias;
709961e9e6aSWhisperity   }
710961e9e6aSWhisperity 
711961e9e6aSWhisperity   // A parameter of type 'cvr1 T' and another of potentially differently
712961e9e6aSWhisperity   // qualified 'cvr2 T' may bind with the same power, if the user so requested.
713473eff1cSWhisperity   //
714473eff1cSWhisperity   // Whether to do this check for the inner unqualified types.
715473eff1cSWhisperity   bool CompareUnqualifiedTypes = false;
716961e9e6aSWhisperity   if (LType.getLocalCVRQualifiers() != RType.getLocalCVRQualifiers()) {
717473eff1cSWhisperity     LLVM_DEBUG(if (LType.getLocalCVRQualifiers()) {
718473eff1cSWhisperity       llvm::dbgs() << "--- calculateMixability. LHS has CVR-Qualifiers: ";
719473eff1cSWhisperity       Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers())
720473eff1cSWhisperity           .print(llvm::dbgs(), Ctx.getPrintingPolicy());
721473eff1cSWhisperity       llvm::dbgs() << '\n';
722473eff1cSWhisperity     });
723473eff1cSWhisperity     LLVM_DEBUG(if (RType.getLocalCVRQualifiers()) {
724473eff1cSWhisperity       llvm::dbgs() << "--- calculateMixability. RHS has CVR-Qualifiers: ";
725473eff1cSWhisperity       Qualifiers::fromCVRMask(RType.getLocalCVRQualifiers())
726473eff1cSWhisperity           .print(llvm::dbgs(), Ctx.getPrintingPolicy());
727473eff1cSWhisperity       llvm::dbgs() << '\n';
728473eff1cSWhisperity     });
729961e9e6aSWhisperity 
730961e9e6aSWhisperity     if (!Check.QualifiersMix) {
731961e9e6aSWhisperity       LLVM_DEBUG(llvm::dbgs()
732473eff1cSWhisperity                  << "<<< calculateMixability. QualifiersMix turned off - not "
733473eff1cSWhisperity                     "mixable.\n");
734961e9e6aSWhisperity       return {MixFlags::None};
735961e9e6aSWhisperity     }
736961e9e6aSWhisperity 
737473eff1cSWhisperity     CompareUnqualifiedTypes = true;
738961e9e6aSWhisperity   }
7398b0cc4a6SWhisperity   // Whether the two types had the same CVR qualifiers.
7408b0cc4a6SWhisperity   bool OriginallySameQualifiers = false;
741961e9e6aSWhisperity   if (LType.getLocalCVRQualifiers() == RType.getLocalCVRQualifiers() &&
742961e9e6aSWhisperity       LType.getLocalCVRQualifiers() != 0) {
743473eff1cSWhisperity     LLVM_DEBUG(if (LType.getLocalCVRQualifiers()) {
744473eff1cSWhisperity       llvm::dbgs()
745473eff1cSWhisperity           << "--- calculateMixability. LHS and RHS have same CVR-Qualifiers: ";
746473eff1cSWhisperity       Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers())
747473eff1cSWhisperity           .print(llvm::dbgs(), Ctx.getPrintingPolicy());
748473eff1cSWhisperity       llvm::dbgs() << '\n';
749473eff1cSWhisperity     });
750473eff1cSWhisperity 
751473eff1cSWhisperity     CompareUnqualifiedTypes = true;
7528b0cc4a6SWhisperity     OriginallySameQualifiers = true;
753473eff1cSWhisperity   }
754473eff1cSWhisperity 
755473eff1cSWhisperity   if (CompareUnqualifiedTypes) {
7568b0cc4a6SWhisperity     NonCVRQualifiersResult AdditionalQuals =
7578b0cc4a6SWhisperity         getNonCVRQualifiers(Ctx, LType, RType);
7588b0cc4a6SWhisperity     if (AdditionalQuals.HasMixabilityBreakingQualifiers) {
759473eff1cSWhisperity       LLVM_DEBUG(llvm::dbgs() << "<<< calculateMixability. Additional "
760473eff1cSWhisperity                                  "non-equal incompatible qualifiers.\n");
761473eff1cSWhisperity       return {MixFlags::None};
762473eff1cSWhisperity     }
763473eff1cSWhisperity 
764473eff1cSWhisperity     MixData UnqualifiedMixability =
765473eff1cSWhisperity         calculateMixability(Check, LType.getLocalUnqualifiedType(),
7668b0cc4a6SWhisperity                             RType.getLocalUnqualifiedType(), Ctx, ImplicitMode)
7678b0cc4a6SWhisperity             .withCommonTypeTransformed([&AdditionalQuals, &Ctx](QualType QT) {
7688b0cc4a6SWhisperity               // Once the mixability was deduced, apply the qualifiers common
7698b0cc4a6SWhisperity               // to the two type back onto the diagnostic printout.
7708b0cc4a6SWhisperity               return Ctx.getQualifiedType(QT, AdditionalQuals.CommonQualifiers);
7718b0cc4a6SWhisperity             });
772473eff1cSWhisperity 
7738b0cc4a6SWhisperity     if (!OriginallySameQualifiers)
7748b0cc4a6SWhisperity       // User-enabled qualifier change modelled for the mix.
775473eff1cSWhisperity       return UnqualifiedMixability | MixFlags::Qualifiers;
776473eff1cSWhisperity 
7778b0cc4a6SWhisperity     // Apply the same qualifier back into the found common type if they were
7788b0cc4a6SWhisperity     // the same.
7798b0cc4a6SWhisperity     return UnqualifiedMixability.withCommonTypeTransformed(
7808b0cc4a6SWhisperity         [&Ctx, LType](QualType QT) {
7818b0cc4a6SWhisperity           return Ctx.getQualifiedType(QT, LType.getLocalQualifiers());
7828b0cc4a6SWhisperity         });
783961e9e6aSWhisperity   }
784961e9e6aSWhisperity 
785473eff1cSWhisperity   // Certain constructs match on the last catch-all getCanonicalType() equality,
786473eff1cSWhisperity   // which is perhaps something not what we want. If this variable is true,
787473eff1cSWhisperity   // the canonical type equality will be ignored.
788473eff1cSWhisperity   bool RecursiveReturnDiscardingCanonicalType = false;
789473eff1cSWhisperity 
790961e9e6aSWhisperity   if (LType->isPointerType() && RType->isPointerType()) {
791961e9e6aSWhisperity     // If both types are pointers, and pointed to the exact same type,
792e33d0478SWhisperity     // LType == RType took care of that. Try to see if the pointee type has
793e33d0478SWhisperity     // some other match. However, this must not consider implicit conversions.
794961e9e6aSWhisperity     LLVM_DEBUG(llvm::dbgs()
795961e9e6aSWhisperity                << "--- calculateMixability. LHS and RHS are Ptrs.\n");
7968b0cc4a6SWhisperity     MixData MixOfPointee =
7978b0cc4a6SWhisperity         calculateMixability(Check, LType->getPointeeType(),
7988b0cc4a6SWhisperity                             RType->getPointeeType(), Ctx,
7998b0cc4a6SWhisperity                             ImplicitConversionModellingMode::None)
8008b0cc4a6SWhisperity             .withCommonTypeTransformed(
8018b0cc4a6SWhisperity                 [&Ctx](QualType QT) { return Ctx.getPointerType(QT); });
802e33d0478SWhisperity     if (hasFlag(MixOfPointee.Flags,
803e33d0478SWhisperity                 MixFlags::WorkaroundDisableCanonicalEquivalence))
804e33d0478SWhisperity       RecursiveReturnDiscardingCanonicalType = true;
805e33d0478SWhisperity 
806e33d0478SWhisperity     MixOfPointee.sanitize();
807e33d0478SWhisperity     if (MixOfPointee.indicatesMixability()) {
808e33d0478SWhisperity       LLVM_DEBUG(llvm::dbgs()
809e33d0478SWhisperity                  << "<<< calculateMixability. Pointees are mixable.\n");
810e33d0478SWhisperity       return MixOfPointee;
811961e9e6aSWhisperity     }
812e33d0478SWhisperity   }
813e33d0478SWhisperity 
814f3b55a8aSWhisperity   if (ImplicitMode > ImplicitConversionModellingMode::None) {
815e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. Start implicit...\n");
816e33d0478SWhisperity     MixData MixLTR =
817e33d0478SWhisperity         approximateImplicitConversion(Check, LType, RType, Ctx, ImplicitMode);
818e33d0478SWhisperity     LLVM_DEBUG(
819e33d0478SWhisperity         if (hasFlag(MixLTR.Flags, MixFlags::ImplicitConversion)) llvm::dbgs()
820e33d0478SWhisperity             << "--- calculateMixability. Implicit Left -> Right found.\n";);
821e33d0478SWhisperity 
822f3b55a8aSWhisperity     if (ImplicitMode ==
823f3b55a8aSWhisperity             ImplicitConversionModellingMode::OneWaySingleStandardOnly &&
824f3b55a8aSWhisperity         MixLTR.Conversion && !MixLTR.Conversion.AfterFirstStandard.isNull() &&
825e33d0478SWhisperity         MixLTR.Conversion.UDConvKind == ConversionSequence::UDCK_None &&
826e33d0478SWhisperity         MixLTR.Conversion.AfterSecondStandard.isNull()) {
827e33d0478SWhisperity       // The invoker of the method requested only modelling a single standard
828e33d0478SWhisperity       // conversion, in only the forward direction, and they got just that.
829e33d0478SWhisperity       LLVM_DEBUG(llvm::dbgs() << "<<< calculateMixability. Implicit "
830e33d0478SWhisperity                                  "conversion, one-way, standard-only.\n");
831e33d0478SWhisperity       return {MixFlags::ImplicitConversion, MixLTR.Conversion};
832e33d0478SWhisperity     }
833e33d0478SWhisperity 
834e33d0478SWhisperity     // Otherwise if the invoker requested a full modelling, do the other
835e33d0478SWhisperity     // direction as well.
836e33d0478SWhisperity     MixData MixRTL =
837e33d0478SWhisperity         approximateImplicitConversion(Check, RType, LType, Ctx, ImplicitMode);
838e33d0478SWhisperity     LLVM_DEBUG(
839e33d0478SWhisperity         if (hasFlag(MixRTL.Flags, MixFlags::ImplicitConversion)) llvm::dbgs()
840e33d0478SWhisperity             << "--- calculateMixability. Implicit Right -> Left found.\n";);
841e33d0478SWhisperity 
842e33d0478SWhisperity     if (MixLTR.Conversion && MixRTL.Conversion) {
843e33d0478SWhisperity       LLVM_DEBUG(
844e33d0478SWhisperity           llvm::dbgs()
845e33d0478SWhisperity           << "<<< calculateMixability. Implicit conversion, bidirectional.\n");
846e33d0478SWhisperity       return {MixFlags::ImplicitConversion, MixLTR.Conversion,
847e33d0478SWhisperity               MixRTL.Conversion};
848e33d0478SWhisperity     }
849e33d0478SWhisperity   }
850e33d0478SWhisperity 
851e33d0478SWhisperity   if (RecursiveReturnDiscardingCanonicalType)
852e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. Before CanonicalType, "
853e33d0478SWhisperity                                "Discard was enabled.\n");
854e33d0478SWhisperity 
855e33d0478SWhisperity   // Certain kinds unfortunately need to be side-stepped for canonical type
856e33d0478SWhisperity   // matching.
857e33d0478SWhisperity   if (LType->getAs<FunctionProtoType>() || RType->getAs<FunctionProtoType>()) {
858e33d0478SWhisperity     // Unfortunately, the canonical type of a function pointer becomes the
859e33d0478SWhisperity     // same even if exactly one is "noexcept" and the other isn't, making us
860e33d0478SWhisperity     // give a false positive report irrespective of implicit conversions.
861e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs()
862e33d0478SWhisperity                << "--- calculateMixability. Discarding potential canonical "
863e33d0478SWhisperity                   "equivalence on FunctionProtoTypes.\n");
864e33d0478SWhisperity     RecursiveReturnDiscardingCanonicalType = true;
865e33d0478SWhisperity   }
866e33d0478SWhisperity 
867e33d0478SWhisperity   MixData MixToReturn{MixFlags::None};
868961e9e6aSWhisperity 
869499e39c5SWhisperity   // If none of the previous logic found a match, try if Clang otherwise
870499e39c5SWhisperity   // believes the types to be the same.
871e33d0478SWhisperity   QualType LCanonical = LType.getCanonicalType();
872e33d0478SWhisperity   if (LCanonical == RType.getCanonicalType()) {
873499e39c5SWhisperity     LLVM_DEBUG(llvm::dbgs()
874499e39c5SWhisperity                << "<<< calculateMixability. Same CanonicalType.\n");
875e33d0478SWhisperity     MixToReturn = {MixFlags::Canonical, LCanonical};
876499e39c5SWhisperity   }
877499e39c5SWhisperity 
878e33d0478SWhisperity   if (RecursiveReturnDiscardingCanonicalType)
879e33d0478SWhisperity     MixToReturn |= MixFlags::WorkaroundDisableCanonicalEquivalence;
880e33d0478SWhisperity 
881e33d0478SWhisperity   LLVM_DEBUG(if (MixToReturn.Flags == MixFlags::None) llvm::dbgs()
882e33d0478SWhisperity              << "<<< calculateMixability. No match found.\n");
883e33d0478SWhisperity   return MixToReturn;
884499e39c5SWhisperity }
885499e39c5SWhisperity 
88626d864b4SWhisperity /// Calculates if the reference binds an expression of the given type. This is
88726d864b4SWhisperity /// true iff 'LRef' is some 'const T &' type, and the 'Ty' is 'T' or 'const T'.
888e33d0478SWhisperity ///
889e33d0478SWhisperity /// \param ImplicitMode is forwarded in the possible recursive call to
890e33d0478SWhisperity /// calculateMixability.
891e33d0478SWhisperity static MixData
isLRefEquallyBindingToType(const TheCheck & Check,const LValueReferenceType * LRef,QualType Ty,const ASTContext & Ctx,bool IsRefRHS,ImplicitConversionModellingMode ImplicitMode)892e33d0478SWhisperity isLRefEquallyBindingToType(const TheCheck &Check,
893e33d0478SWhisperity                            const LValueReferenceType *LRef, QualType Ty,
894e33d0478SWhisperity                            const ASTContext &Ctx, bool IsRefRHS,
895e33d0478SWhisperity                            ImplicitConversionModellingMode ImplicitMode) {
89626d864b4SWhisperity   LLVM_DEBUG(llvm::dbgs() << ">>> isLRefEquallyBindingToType for LRef:\n";
89726d864b4SWhisperity              LRef->dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand Type:\n";
89826d864b4SWhisperity              Ty.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';);
89926d864b4SWhisperity 
90026d864b4SWhisperity   QualType ReferredType = LRef->getPointeeType();
901961e9e6aSWhisperity   if (!ReferredType.isLocalConstQualified() &&
902961e9e6aSWhisperity       ReferredType->getAs<TypedefType>()) {
903961e9e6aSWhisperity     LLVM_DEBUG(
904961e9e6aSWhisperity         llvm::dbgs()
905961e9e6aSWhisperity         << "--- isLRefEquallyBindingToType. Non-const LRef to Typedef.\n");
906961e9e6aSWhisperity     ReferredType = ReferredType.getDesugaredType(Ctx);
90726d864b4SWhisperity     if (!ReferredType.isLocalConstQualified()) {
90826d864b4SWhisperity       LLVM_DEBUG(llvm::dbgs()
909961e9e6aSWhisperity                  << "<<< isLRefEquallyBindingToType. Typedef is not const.\n");
910961e9e6aSWhisperity       return {MixFlags::None};
911961e9e6aSWhisperity     }
912961e9e6aSWhisperity 
913961e9e6aSWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- isLRefEquallyBindingToType. Typedef is "
914961e9e6aSWhisperity                                "const, considering as const LRef.\n");
915961e9e6aSWhisperity   } else if (!ReferredType.isLocalConstQualified()) {
916961e9e6aSWhisperity     LLVM_DEBUG(llvm::dbgs()
917961e9e6aSWhisperity                << "<<< isLRefEquallyBindingToType. Not const LRef.\n");
91826d864b4SWhisperity     return {MixFlags::None};
91926d864b4SWhisperity   };
92026d864b4SWhisperity 
921961e9e6aSWhisperity   assert(ReferredType.isLocalConstQualified() &&
922961e9e6aSWhisperity          "Reaching this point means we are sure LRef is effectively a const&.");
923961e9e6aSWhisperity 
924961e9e6aSWhisperity   if (ReferredType == Ty) {
92526d864b4SWhisperity     LLVM_DEBUG(
92626d864b4SWhisperity         llvm::dbgs()
92726d864b4SWhisperity         << "<<< isLRefEquallyBindingToType. Type of referred matches.\n");
92826d864b4SWhisperity     return {MixFlags::Trivial, ReferredType};
92926d864b4SWhisperity   }
93026d864b4SWhisperity 
931961e9e6aSWhisperity   QualType NonConstReferredType = ReferredType;
932961e9e6aSWhisperity   NonConstReferredType.removeLocalConst();
933961e9e6aSWhisperity   if (NonConstReferredType == Ty) {
934961e9e6aSWhisperity     LLVM_DEBUG(llvm::dbgs() << "<<< isLRefEquallyBindingToType. Type of "
935961e9e6aSWhisperity                                "referred matches to non-const qualified.\n");
936961e9e6aSWhisperity     return {MixFlags::Trivial, NonConstReferredType};
937961e9e6aSWhisperity   }
938961e9e6aSWhisperity 
93926d864b4SWhisperity   LLVM_DEBUG(
94026d864b4SWhisperity       llvm::dbgs()
94126d864b4SWhisperity       << "--- isLRefEquallyBindingToType. Checking mix for underlying type.\n");
942e33d0478SWhisperity   return IsRefRHS ? calculateMixability(Check, Ty, NonConstReferredType, Ctx,
943e33d0478SWhisperity                                         ImplicitMode)
944e33d0478SWhisperity                   : calculateMixability(Check, NonConstReferredType, Ty, Ctx,
945e33d0478SWhisperity                                         ImplicitMode);
946e33d0478SWhisperity }
947e33d0478SWhisperity 
isDerivedToBase(const CXXRecordDecl * Derived,const CXXRecordDecl * Base)948e33d0478SWhisperity static inline bool isDerivedToBase(const CXXRecordDecl *Derived,
949e33d0478SWhisperity                                    const CXXRecordDecl *Base) {
950e33d0478SWhisperity   return Derived && Base && Derived->isCompleteDefinition() &&
951e33d0478SWhisperity          Base->isCompleteDefinition() && Derived->isDerivedFrom(Base);
952e33d0478SWhisperity }
953e33d0478SWhisperity 
954f71ffd3bSKazu Hirata static std::optional<QualType>
approximateStandardConversionSequence(const TheCheck & Check,QualType From,QualType To,const ASTContext & Ctx)955e33d0478SWhisperity approximateStandardConversionSequence(const TheCheck &Check, QualType From,
956e33d0478SWhisperity                                       QualType To, const ASTContext &Ctx) {
957e33d0478SWhisperity   LLVM_DEBUG(llvm::dbgs() << ">>> approximateStdConv for LType:\n";
958e33d0478SWhisperity              From.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";
959e33d0478SWhisperity              To.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';);
960e33d0478SWhisperity 
961e33d0478SWhisperity   // A standard conversion sequence consists of the following, in order:
962e33d0478SWhisperity   //  * Maybe either LValue->RValue conv., Array->Ptr conv., Function->Ptr conv.
963e33d0478SWhisperity   //  * Maybe Numeric promotion or conversion.
964e33d0478SWhisperity   //  * Maybe function pointer conversion.
965e33d0478SWhisperity   //  * Maybe qualifier adjustments.
966e33d0478SWhisperity   QualType WorkType = From;
967e33d0478SWhisperity   // Get out the qualifiers of the original type. This will always be
968e33d0478SWhisperity   // re-applied to the WorkType to ensure it is the same qualification as the
969e33d0478SWhisperity   // original From was.
970*f4efa067SDaniil Kovalev   auto FastQualifiersToApply = static_cast<unsigned>(
971*f4efa067SDaniil Kovalev       From.split().Quals.getAsOpaqueValue() & Qualifiers::FastMask);
972e33d0478SWhisperity 
973e33d0478SWhisperity   // LValue->RValue is irrelevant for the check, because it is a thing to be
974e33d0478SWhisperity   // done at a call site, and will be performed if need be performed.
975e33d0478SWhisperity 
97621832121SWhisperity   // Array->Pointer decay is handled by the main method in desugaring
97721832121SWhisperity   // the parameter's DecayedType as "useless sugar".
978e33d0478SWhisperity 
979e33d0478SWhisperity   // Function->Pointer conversions are also irrelevant, because a
980e33d0478SWhisperity   // "FunctionType" cannot be the type of a parameter variable, so this
981e33d0478SWhisperity   // conversion is only meaningful at call sites.
982e33d0478SWhisperity 
983e33d0478SWhisperity   // Numeric promotions and conversions.
984e33d0478SWhisperity   const auto *FromBuiltin = WorkType->getAs<BuiltinType>();
985e33d0478SWhisperity   const auto *ToBuiltin = To->getAs<BuiltinType>();
986e33d0478SWhisperity   bool FromNumeric = FromBuiltin && (FromBuiltin->isIntegerType() ||
987e33d0478SWhisperity                                      FromBuiltin->isFloatingType());
988e33d0478SWhisperity   bool ToNumeric =
989e33d0478SWhisperity       ToBuiltin && (ToBuiltin->isIntegerType() || ToBuiltin->isFloatingType());
990e33d0478SWhisperity   if (FromNumeric && ToNumeric) {
991e33d0478SWhisperity     // If both are integral types, the numeric conversion is performed.
992e33d0478SWhisperity     // Reapply the qualifiers of the original type, however, so
993e33d0478SWhisperity     // "const int -> double" in this case moves over to
994e33d0478SWhisperity     // "const double -> double".
995e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs()
996e33d0478SWhisperity                << "--- approximateStdConv. Conversion between numerics.\n");
997*f4efa067SDaniil Kovalev     WorkType = QualType{ToBuiltin, FastQualifiersToApply};
998e33d0478SWhisperity   }
999e33d0478SWhisperity 
1000e33d0478SWhisperity   const auto *FromEnum = WorkType->getAs<EnumType>();
1001e33d0478SWhisperity   const auto *ToEnum = To->getAs<EnumType>();
1002e33d0478SWhisperity   if (FromEnum && ToNumeric && FromEnum->isUnscopedEnumerationType()) {
1003e33d0478SWhisperity     // Unscoped enumerations (or enumerations in C) convert to numerics.
1004e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs()
1005e33d0478SWhisperity                << "--- approximateStdConv. Unscoped enum to numeric.\n");
1006*f4efa067SDaniil Kovalev     WorkType = QualType{ToBuiltin, FastQualifiersToApply};
1007e33d0478SWhisperity   } else if (FromNumeric && ToEnum && ToEnum->isUnscopedEnumerationType()) {
1008e33d0478SWhisperity     // Numeric types convert to enumerations only in C.
1009e33d0478SWhisperity     if (Ctx.getLangOpts().CPlusPlus) {
1010e33d0478SWhisperity       LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Numeric to unscoped "
1011e33d0478SWhisperity                                  "enum, not possible in C++!\n");
1012e33d0478SWhisperity       return {};
1013e33d0478SWhisperity     }
1014e33d0478SWhisperity 
1015e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs()
1016e33d0478SWhisperity                << "--- approximateStdConv. Numeric to unscoped enum.\n");
1017*f4efa067SDaniil Kovalev     WorkType = QualType{ToEnum, FastQualifiersToApply};
1018e33d0478SWhisperity   }
1019e33d0478SWhisperity 
1020e33d0478SWhisperity   // Check for pointer conversions.
1021e33d0478SWhisperity   const auto *FromPtr = WorkType->getAs<PointerType>();
1022e33d0478SWhisperity   const auto *ToPtr = To->getAs<PointerType>();
1023e33d0478SWhisperity   if (FromPtr && ToPtr) {
1024e33d0478SWhisperity     if (ToPtr->isVoidPointerType()) {
1025e33d0478SWhisperity       LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. To void pointer.\n");
1026*f4efa067SDaniil Kovalev       WorkType = QualType{ToPtr, FastQualifiersToApply};
1027e33d0478SWhisperity     }
1028e33d0478SWhisperity 
1029e33d0478SWhisperity     const auto *FromRecordPtr = FromPtr->getPointeeCXXRecordDecl();
1030e33d0478SWhisperity     const auto *ToRecordPtr = ToPtr->getPointeeCXXRecordDecl();
1031e33d0478SWhisperity     if (isDerivedToBase(FromRecordPtr, ToRecordPtr)) {
1032e33d0478SWhisperity       LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Derived* to Base*\n");
1033*f4efa067SDaniil Kovalev       WorkType = QualType{ToPtr, FastQualifiersToApply};
1034e33d0478SWhisperity     }
1035e33d0478SWhisperity   }
1036e33d0478SWhisperity 
1037e33d0478SWhisperity   // Model the slicing Derived-to-Base too, as "BaseT temporary = derived;"
1038e33d0478SWhisperity   // can also be compiled.
1039e33d0478SWhisperity   const auto *FromRecord = WorkType->getAsCXXRecordDecl();
1040e33d0478SWhisperity   const auto *ToRecord = To->getAsCXXRecordDecl();
1041e33d0478SWhisperity   if (isDerivedToBase(FromRecord, ToRecord)) {
1042e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Derived To Base.\n");
1043*f4efa067SDaniil Kovalev     WorkType = QualType{ToRecord->getTypeForDecl(), FastQualifiersToApply};
1044e33d0478SWhisperity   }
1045e33d0478SWhisperity 
1046e33d0478SWhisperity   if (Ctx.getLangOpts().CPlusPlus17 && FromPtr && ToPtr) {
1047e33d0478SWhisperity     // Function pointer conversion: A noexcept function pointer can be passed
1048e33d0478SWhisperity     // to a non-noexcept one.
1049e33d0478SWhisperity     const auto *FromFunctionPtr =
1050e33d0478SWhisperity         FromPtr->getPointeeType()->getAs<FunctionProtoType>();
1051e33d0478SWhisperity     const auto *ToFunctionPtr =
1052e33d0478SWhisperity         ToPtr->getPointeeType()->getAs<FunctionProtoType>();
1053e33d0478SWhisperity     if (FromFunctionPtr && ToFunctionPtr &&
1054e33d0478SWhisperity         FromFunctionPtr->hasNoexceptExceptionSpec() &&
1055e33d0478SWhisperity         !ToFunctionPtr->hasNoexceptExceptionSpec()) {
1056e33d0478SWhisperity       LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. noexcept function "
1057e33d0478SWhisperity                                  "pointer to non-noexcept.\n");
1058*f4efa067SDaniil Kovalev       WorkType = QualType{ToPtr, FastQualifiersToApply};
1059e33d0478SWhisperity     }
1060e33d0478SWhisperity   }
1061e33d0478SWhisperity 
1062e33d0478SWhisperity   // Qualifier adjustments are modelled according to the user's request in
1063e33d0478SWhisperity   // the QualifiersMix check config.
1064e33d0478SWhisperity   LLVM_DEBUG(llvm::dbgs()
1065e33d0478SWhisperity              << "--- approximateStdConv. Trying qualifier adjustment...\n");
1066f3b55a8aSWhisperity   MixData QualConv = calculateMixability(Check, WorkType, To, Ctx,
1067f3b55a8aSWhisperity                                          ImplicitConversionModellingMode::None);
1068e33d0478SWhisperity   QualConv.sanitize();
1069e33d0478SWhisperity   if (hasFlag(QualConv.Flags, MixFlags::Qualifiers)) {
1070e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs()
1071e33d0478SWhisperity                << "<<< approximateStdConv. Qualifiers adjusted.\n");
1072e33d0478SWhisperity     WorkType = To;
1073e33d0478SWhisperity   }
1074e33d0478SWhisperity 
1075e33d0478SWhisperity   if (WorkType == To) {
1076e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Reached 'To' type.\n");
1077e33d0478SWhisperity     return {WorkType};
1078e33d0478SWhisperity   }
1079e33d0478SWhisperity 
1080e33d0478SWhisperity   LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Did not reach 'To'.\n");
1081e33d0478SWhisperity   return {};
1082e33d0478SWhisperity }
1083e33d0478SWhisperity 
1084e33d0478SWhisperity namespace {
1085e33d0478SWhisperity 
1086e33d0478SWhisperity /// Helper class for storing possible user-defined conversion calls that
1087e33d0478SWhisperity /// *could* take place in an implicit conversion, and selecting the one that
1088e33d0478SWhisperity /// most likely *does*, if any.
1089e33d0478SWhisperity class UserDefinedConversionSelector {
1090e33d0478SWhisperity public:
1091e33d0478SWhisperity   /// The conversion associated with a conversion function, together with the
1092e33d0478SWhisperity   /// mixability flags of the conversion function's parameter or return type
1093e33d0478SWhisperity   /// to the rest of the sequence the selector is used in, and the sequence
1094e33d0478SWhisperity   /// that applied through the conversion itself.
1095e33d0478SWhisperity   struct PreparedConversion {
1096e33d0478SWhisperity     const CXXMethodDecl *ConversionFun;
1097e33d0478SWhisperity     MixFlags Flags;
1098e33d0478SWhisperity     ConversionSequence Seq;
1099e33d0478SWhisperity 
PreparedConversionclang::tidy::bugprone::model::__anoneac3b3da0811::UserDefinedConversionSelector::PreparedConversion1100e33d0478SWhisperity     PreparedConversion(const CXXMethodDecl *CMD, MixFlags F,
1101e33d0478SWhisperity                        ConversionSequence S)
1102e33d0478SWhisperity         : ConversionFun(CMD), Flags(F), Seq(S) {}
1103e33d0478SWhisperity   };
1104e33d0478SWhisperity 
UserDefinedConversionSelector(const TheCheck & Check)1105e33d0478SWhisperity   UserDefinedConversionSelector(const TheCheck &Check) : Check(Check) {}
1106e33d0478SWhisperity 
1107e33d0478SWhisperity   /// Adds the conversion between the two types for the given function into
1108e33d0478SWhisperity   /// the possible implicit conversion set. FromType and ToType is either:
1109e33d0478SWhisperity   ///   * the result of a standard sequence and a converting ctor parameter
1110e33d0478SWhisperity   ///   * the return type of a conversion operator and the expected target of
1111e33d0478SWhisperity   ///     an implicit conversion.
addConversion(const CXXMethodDecl * ConvFun,QualType FromType,QualType ToType)1112e33d0478SWhisperity   void addConversion(const CXXMethodDecl *ConvFun, QualType FromType,
1113e33d0478SWhisperity                      QualType ToType) {
1114ade0662cSSalman Javed     // Try to go from the FromType to the ToType with only a single implicit
1115e33d0478SWhisperity     // conversion, to see if the conversion function is applicable.
1116f3b55a8aSWhisperity     MixData Mix = calculateMixability(
1117f3b55a8aSWhisperity         Check, FromType, ToType, ConvFun->getASTContext(),
1118f3b55a8aSWhisperity         ImplicitConversionModellingMode::OneWaySingleStandardOnly);
1119e33d0478SWhisperity     Mix.sanitize();
1120e33d0478SWhisperity     if (!Mix.indicatesMixability())
1121e33d0478SWhisperity       return;
1122e33d0478SWhisperity 
1123e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- tryConversion. Found viable with flags: "
1124e33d0478SWhisperity                             << formatMixFlags(Mix.Flags) << '\n');
1125e33d0478SWhisperity     FlaggedConversions.emplace_back(ConvFun, Mix.Flags, Mix.Conversion);
1126e33d0478SWhisperity   }
1127e33d0478SWhisperity 
1128e33d0478SWhisperity   /// Selects the best conversion function that is applicable from the
1129e33d0478SWhisperity   /// prepared set of potential conversion functions taken.
operator ()() const1130f71ffd3bSKazu Hirata   std::optional<PreparedConversion> operator()() const {
1131e33d0478SWhisperity     if (FlaggedConversions.empty()) {
1132e33d0478SWhisperity       LLVM_DEBUG(llvm::dbgs() << "--- selectUserDefinedConv. Empty.\n");
1133e33d0478SWhisperity       return {};
1134e33d0478SWhisperity     }
1135e33d0478SWhisperity     if (FlaggedConversions.size() == 1) {
1136e33d0478SWhisperity       LLVM_DEBUG(llvm::dbgs() << "--- selectUserDefinedConv. Single.\n");
1137e33d0478SWhisperity       return FlaggedConversions.front();
1138e33d0478SWhisperity     }
1139e33d0478SWhisperity 
1140f71ffd3bSKazu Hirata     std::optional<PreparedConversion> BestConversion;
1141e33d0478SWhisperity     unsigned short HowManyGoodConversions = 0;
1142e33d0478SWhisperity     for (const auto &Prepared : FlaggedConversions) {
1143e33d0478SWhisperity       LLVM_DEBUG(llvm::dbgs() << "--- selectUserDefinedConv. Candidate flags: "
1144e33d0478SWhisperity                               << formatMixFlags(Prepared.Flags) << '\n');
1145e33d0478SWhisperity       if (!BestConversion) {
1146e33d0478SWhisperity         BestConversion = Prepared;
1147e33d0478SWhisperity         ++HowManyGoodConversions;
1148e33d0478SWhisperity         continue;
1149e33d0478SWhisperity       }
1150e33d0478SWhisperity 
1151e33d0478SWhisperity       bool BestConversionHasImplicit =
1152e33d0478SWhisperity           hasFlag(BestConversion->Flags, MixFlags::ImplicitConversion);
1153e33d0478SWhisperity       bool ThisConversionHasImplicit =
1154e33d0478SWhisperity           hasFlag(Prepared.Flags, MixFlags::ImplicitConversion);
1155e33d0478SWhisperity       if (!BestConversionHasImplicit && ThisConversionHasImplicit)
1156e33d0478SWhisperity         // This is a worse conversion, because a better one was found earlier.
1157e33d0478SWhisperity         continue;
1158e33d0478SWhisperity 
1159e33d0478SWhisperity       if (BestConversionHasImplicit && !ThisConversionHasImplicit) {
1160e33d0478SWhisperity         // If the so far best selected conversion needs a previous implicit
1161e33d0478SWhisperity         // conversion to match the user-defined converting function, but this
1162e33d0478SWhisperity         // conversion does not, this is a better conversion, and we can throw
1163e33d0478SWhisperity         // away the previously selected conversion(s).
1164e33d0478SWhisperity         BestConversion = Prepared;
1165e33d0478SWhisperity         HowManyGoodConversions = 1;
1166e33d0478SWhisperity         continue;
1167e33d0478SWhisperity       }
1168e33d0478SWhisperity 
1169e33d0478SWhisperity       if (BestConversionHasImplicit == ThisConversionHasImplicit)
1170e33d0478SWhisperity         // The current conversion is the same in term of goodness than the
1171e33d0478SWhisperity         // already selected one.
1172e33d0478SWhisperity         ++HowManyGoodConversions;
1173e33d0478SWhisperity     }
1174e33d0478SWhisperity 
1175e33d0478SWhisperity     if (HowManyGoodConversions == 1) {
1176e33d0478SWhisperity       LLVM_DEBUG(llvm::dbgs()
1177e33d0478SWhisperity                  << "--- selectUserDefinedConv. Unique result. Flags: "
1178e33d0478SWhisperity                  << formatMixFlags(BestConversion->Flags) << '\n');
1179e33d0478SWhisperity       return BestConversion;
1180e33d0478SWhisperity     }
1181e33d0478SWhisperity 
1182e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs()
1183e33d0478SWhisperity                << "--- selectUserDefinedConv. No, or ambiguous.\n");
1184e33d0478SWhisperity     return {};
1185e33d0478SWhisperity   }
1186e33d0478SWhisperity 
1187e33d0478SWhisperity private:
1188e33d0478SWhisperity   llvm::SmallVector<PreparedConversion, 2> FlaggedConversions;
1189e33d0478SWhisperity   const TheCheck &Check;
1190e33d0478SWhisperity };
1191e33d0478SWhisperity 
1192e33d0478SWhisperity } // namespace
1193e33d0478SWhisperity 
1194f71ffd3bSKazu Hirata static std::optional<ConversionSequence>
tryConversionOperators(const TheCheck & Check,const CXXRecordDecl * RD,QualType ToType)1195e33d0478SWhisperity tryConversionOperators(const TheCheck &Check, const CXXRecordDecl *RD,
1196e33d0478SWhisperity                        QualType ToType) {
1197e33d0478SWhisperity   if (!RD || !RD->isCompleteDefinition())
1198e33d0478SWhisperity     return {};
1199e33d0478SWhisperity   RD = RD->getDefinition();
1200e33d0478SWhisperity 
1201e33d0478SWhisperity   LLVM_DEBUG(llvm::dbgs() << ">>> tryConversionOperators: " << RD->getName()
1202e33d0478SWhisperity                           << " to:\n";
1203e33d0478SWhisperity              ToType.dump(llvm::dbgs(), RD->getASTContext());
1204e33d0478SWhisperity              llvm::dbgs() << '\n';);
1205e33d0478SWhisperity 
1206e33d0478SWhisperity   UserDefinedConversionSelector ConversionSet{Check};
1207e33d0478SWhisperity 
1208e33d0478SWhisperity   for (const NamedDecl *Method : RD->getVisibleConversionFunctions()) {
1209e33d0478SWhisperity     const auto *Con = dyn_cast<CXXConversionDecl>(Method);
1210e33d0478SWhisperity     if (!Con || Con->isExplicit())
1211e33d0478SWhisperity       continue;
1212e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- tryConversionOperators. Trying:\n";
1213e33d0478SWhisperity                Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';);
1214e33d0478SWhisperity 
1215e33d0478SWhisperity     // Try to go from the result of conversion operator to the expected type,
1216e33d0478SWhisperity     // without calculating another user-defined conversion.
1217e33d0478SWhisperity     ConversionSet.addConversion(Con, Con->getConversionType(), ToType);
1218e33d0478SWhisperity   }
1219e33d0478SWhisperity 
1220f71ffd3bSKazu Hirata   if (std::optional<UserDefinedConversionSelector::PreparedConversion>
1221e33d0478SWhisperity           SelectedConversion = ConversionSet()) {
1222e33d0478SWhisperity     QualType RecordType{RD->getTypeForDecl(), 0};
1223e33d0478SWhisperity 
1224e33d0478SWhisperity     ConversionSequence Result{RecordType, ToType};
1225e33d0478SWhisperity     // The conversion from the operator call's return type to ToType was
1226e33d0478SWhisperity     // modelled as a "pre-conversion" in the operator call, but it is the
1227e33d0478SWhisperity     // "post-conversion" from the point of view of the original conversion
1228e33d0478SWhisperity     // we are modelling.
1229e33d0478SWhisperity     Result.AfterSecondStandard = SelectedConversion->Seq.AfterFirstStandard;
1230e33d0478SWhisperity 
1231e33d0478SWhisperity     ConversionSequence::UserDefinedConversionOperator ConvOp;
1232e33d0478SWhisperity     ConvOp.Fun = cast<CXXConversionDecl>(SelectedConversion->ConversionFun);
1233e33d0478SWhisperity     ConvOp.UserDefinedType = RecordType;
1234e33d0478SWhisperity     ConvOp.ConversionOperatorResultType = ConvOp.Fun->getConversionType();
1235e33d0478SWhisperity     Result.setConversion(ConvOp);
1236e33d0478SWhisperity 
1237e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs() << "<<< tryConversionOperators. Found result.\n");
1238e33d0478SWhisperity     return Result;
1239e33d0478SWhisperity   }
1240e33d0478SWhisperity 
1241e33d0478SWhisperity   LLVM_DEBUG(llvm::dbgs() << "<<< tryConversionOperators. No conversion.\n");
1242e33d0478SWhisperity   return {};
1243e33d0478SWhisperity }
1244e33d0478SWhisperity 
1245f71ffd3bSKazu Hirata static std::optional<ConversionSequence>
tryConvertingConstructors(const TheCheck & Check,QualType FromType,const CXXRecordDecl * RD)1246e33d0478SWhisperity tryConvertingConstructors(const TheCheck &Check, QualType FromType,
1247e33d0478SWhisperity                           const CXXRecordDecl *RD) {
1248e33d0478SWhisperity   if (!RD || !RD->isCompleteDefinition())
1249e33d0478SWhisperity     return {};
1250e33d0478SWhisperity   RD = RD->getDefinition();
1251e33d0478SWhisperity 
1252e33d0478SWhisperity   LLVM_DEBUG(llvm::dbgs() << ">>> tryConveringConstructors: " << RD->getName()
1253e33d0478SWhisperity                           << " from:\n";
1254e33d0478SWhisperity              FromType.dump(llvm::dbgs(), RD->getASTContext());
1255e33d0478SWhisperity              llvm::dbgs() << '\n';);
1256e33d0478SWhisperity 
1257e33d0478SWhisperity   UserDefinedConversionSelector ConversionSet{Check};
1258e33d0478SWhisperity 
1259e33d0478SWhisperity   for (const CXXConstructorDecl *Con : RD->ctors()) {
1260e33d0478SWhisperity     if (Con->isCopyOrMoveConstructor() ||
1261e33d0478SWhisperity         !Con->isConvertingConstructor(/* AllowExplicit =*/false))
1262e33d0478SWhisperity       continue;
1263e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- tryConvertingConstructors. Trying:\n";
1264e33d0478SWhisperity                Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';);
1265e33d0478SWhisperity 
1266e33d0478SWhisperity     // Try to go from the original FromType to the converting constructor's
1267e33d0478SWhisperity     // parameter type without another user-defined conversion.
1268e33d0478SWhisperity     ConversionSet.addConversion(Con, FromType, Con->getParamDecl(0)->getType());
1269e33d0478SWhisperity   }
1270e33d0478SWhisperity 
1271f71ffd3bSKazu Hirata   if (std::optional<UserDefinedConversionSelector::PreparedConversion>
1272e33d0478SWhisperity           SelectedConversion = ConversionSet()) {
1273e33d0478SWhisperity     QualType RecordType{RD->getTypeForDecl(), 0};
1274e33d0478SWhisperity 
1275e33d0478SWhisperity     ConversionSequence Result{FromType, RecordType};
1276e33d0478SWhisperity     Result.AfterFirstStandard = SelectedConversion->Seq.AfterFirstStandard;
1277e33d0478SWhisperity 
1278e33d0478SWhisperity     ConversionSequence::UserDefinedConvertingConstructor Ctor;
1279e33d0478SWhisperity     Ctor.Fun = cast<CXXConstructorDecl>(SelectedConversion->ConversionFun);
1280e33d0478SWhisperity     Ctor.ConstructorParameterType = Ctor.Fun->getParamDecl(0)->getType();
1281e33d0478SWhisperity     Ctor.UserDefinedType = RecordType;
1282e33d0478SWhisperity     Result.setConversion(Ctor);
1283e33d0478SWhisperity 
1284e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs()
1285e33d0478SWhisperity                << "<<< tryConvertingConstructors. Found result.\n");
1286e33d0478SWhisperity     return Result;
1287e33d0478SWhisperity   }
1288e33d0478SWhisperity 
1289e33d0478SWhisperity   LLVM_DEBUG(llvm::dbgs() << "<<< tryConvertingConstructors. No conversion.\n");
1290e33d0478SWhisperity   return {};
1291e33d0478SWhisperity }
1292e33d0478SWhisperity 
1293e33d0478SWhisperity /// Returns whether an expression of LType can be used in an RType context, as
1294e33d0478SWhisperity /// per the implicit conversion rules.
1295e33d0478SWhisperity ///
1296e33d0478SWhisperity /// Note: the result of this operation, unlike that of calculateMixability, is
1297e33d0478SWhisperity /// **NOT** symmetric.
1298e33d0478SWhisperity static MixData
approximateImplicitConversion(const TheCheck & Check,QualType LType,QualType RType,const ASTContext & Ctx,ImplicitConversionModellingMode ImplicitMode)1299e33d0478SWhisperity approximateImplicitConversion(const TheCheck &Check, QualType LType,
1300e33d0478SWhisperity                               QualType RType, const ASTContext &Ctx,
1301e33d0478SWhisperity                               ImplicitConversionModellingMode ImplicitMode) {
1302e33d0478SWhisperity   LLVM_DEBUG(llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n";
1303e33d0478SWhisperity              LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";
1304e33d0478SWhisperity              RType.dump(llvm::dbgs(), Ctx);
1305f3b55a8aSWhisperity              llvm::dbgs() << "\nimplicit mode: "; switch (ImplicitMode) {
1306f3b55a8aSWhisperity                case ImplicitConversionModellingMode::None:
1307f3b55a8aSWhisperity                  llvm::dbgs() << "None";
1308f3b55a8aSWhisperity                  break;
1309f3b55a8aSWhisperity                case ImplicitConversionModellingMode::All:
1310f3b55a8aSWhisperity                  llvm::dbgs() << "All";
1311f3b55a8aSWhisperity                  break;
1312f3b55a8aSWhisperity                case ImplicitConversionModellingMode::OneWaySingleStandardOnly:
1313f3b55a8aSWhisperity                  llvm::dbgs() << "OneWay, Single, STD Only";
1314f3b55a8aSWhisperity                  break;
1315f3b55a8aSWhisperity              } llvm::dbgs() << '\n';);
1316e33d0478SWhisperity   if (LType == RType)
1317e33d0478SWhisperity     return {MixFlags::Trivial, LType};
1318e33d0478SWhisperity 
1319e33d0478SWhisperity   // An implicit conversion sequence consists of the following, in order:
1320e33d0478SWhisperity   //  * Maybe standard conversion sequence.
1321e33d0478SWhisperity   //  * Maybe user-defined conversion.
1322e33d0478SWhisperity   //  * Maybe standard conversion sequence.
1323e33d0478SWhisperity   ConversionSequence ImplicitSeq{LType, RType};
1324e33d0478SWhisperity   QualType WorkType = LType;
1325e33d0478SWhisperity 
1326f71ffd3bSKazu Hirata   std::optional<QualType> AfterFirstStdConv =
1327e33d0478SWhisperity       approximateStandardConversionSequence(Check, LType, RType, Ctx);
1328e33d0478SWhisperity   if (AfterFirstStdConv) {
1329e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Standard "
1330e33d0478SWhisperity                                "Pre-Conversion found!\n");
1331ed8fceaaSKazu Hirata     ImplicitSeq.AfterFirstStandard = *AfterFirstStdConv;
1332e33d0478SWhisperity     WorkType = ImplicitSeq.AfterFirstStandard;
1333e33d0478SWhisperity   }
1334e33d0478SWhisperity 
1335f3b55a8aSWhisperity   if (ImplicitMode == ImplicitConversionModellingMode::OneWaySingleStandardOnly)
1336e33d0478SWhisperity     // If the caller only requested modelling of a standard conversion, bail.
1337e33d0478SWhisperity     return {ImplicitSeq.AfterFirstStandard.isNull()
1338e33d0478SWhisperity                 ? MixFlags::None
1339e33d0478SWhisperity                 : MixFlags::ImplicitConversion,
1340e33d0478SWhisperity             ImplicitSeq};
1341e33d0478SWhisperity 
1342e33d0478SWhisperity   if (Ctx.getLangOpts().CPlusPlus) {
1343e33d0478SWhisperity     bool FoundConversionOperator = false, FoundConvertingCtor = false;
1344e33d0478SWhisperity 
1345e33d0478SWhisperity     if (const auto *LRD = WorkType->getAsCXXRecordDecl()) {
1346f71ffd3bSKazu Hirata       std::optional<ConversionSequence> ConversionOperatorResult =
1347e33d0478SWhisperity           tryConversionOperators(Check, LRD, RType);
1348e33d0478SWhisperity       if (ConversionOperatorResult) {
1349e33d0478SWhisperity         LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Found "
1350e33d0478SWhisperity                                    "conversion operator.\n");
1351ed8fceaaSKazu Hirata         ImplicitSeq.update(*ConversionOperatorResult);
1352e33d0478SWhisperity         WorkType = ImplicitSeq.getTypeAfterUserDefinedConversion();
1353e33d0478SWhisperity         FoundConversionOperator = true;
1354e33d0478SWhisperity       }
1355e33d0478SWhisperity     }
1356e33d0478SWhisperity 
1357e33d0478SWhisperity     if (const auto *RRD = RType->getAsCXXRecordDecl()) {
1358e33d0478SWhisperity       // Use the original "LType" here, and not WorkType, because the
1359e33d0478SWhisperity       // conversion to the converting constructors' parameters will be
1360e33d0478SWhisperity       // modelled in the recursive call.
1361f71ffd3bSKazu Hirata       std::optional<ConversionSequence> ConvCtorResult =
1362e33d0478SWhisperity           tryConvertingConstructors(Check, LType, RRD);
1363e33d0478SWhisperity       if (ConvCtorResult) {
1364e33d0478SWhisperity         LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Found "
1365e33d0478SWhisperity                                    "converting constructor.\n");
1366ed8fceaaSKazu Hirata         ImplicitSeq.update(*ConvCtorResult);
1367e33d0478SWhisperity         WorkType = ImplicitSeq.getTypeAfterUserDefinedConversion();
1368e33d0478SWhisperity         FoundConvertingCtor = true;
1369e33d0478SWhisperity       }
1370e33d0478SWhisperity     }
1371e33d0478SWhisperity 
1372e33d0478SWhisperity     if (FoundConversionOperator && FoundConvertingCtor) {
1373e33d0478SWhisperity       // If both an operator and a ctor matches, the sequence is ambiguous.
1374e33d0478SWhisperity       LLVM_DEBUG(llvm::dbgs()
1375e33d0478SWhisperity                  << "<<< approximateImplicitConversion. Found both "
1376e33d0478SWhisperity                     "user-defined conversion kinds in the same sequence!\n");
1377e33d0478SWhisperity       return {MixFlags::None};
1378e33d0478SWhisperity     }
1379e33d0478SWhisperity   }
1380e33d0478SWhisperity 
1381e33d0478SWhisperity   // After the potential user-defined conversion, another standard conversion
1382e33d0478SWhisperity   // sequence might exist.
1383e33d0478SWhisperity   LLVM_DEBUG(
1384e33d0478SWhisperity       llvm::dbgs()
1385e33d0478SWhisperity       << "--- approximateImplicitConversion. Try to find post-conversion.\n");
1386e33d0478SWhisperity   MixData SecondStdConv = approximateImplicitConversion(
1387f3b55a8aSWhisperity       Check, WorkType, RType, Ctx,
1388f3b55a8aSWhisperity       ImplicitConversionModellingMode::OneWaySingleStandardOnly);
1389e33d0478SWhisperity   if (SecondStdConv.indicatesMixability()) {
1390e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Standard "
1391e33d0478SWhisperity                                "Post-Conversion found!\n");
1392e33d0478SWhisperity 
1393e33d0478SWhisperity     // The single-step modelling puts the modelled conversion into the "PreStd"
1394e33d0478SWhisperity     // variable in the recursive call, but from the PoV of this function, it is
1395e33d0478SWhisperity     // the post-conversion.
1396e33d0478SWhisperity     ImplicitSeq.AfterSecondStandard =
1397e33d0478SWhisperity         SecondStdConv.Conversion.AfterFirstStandard;
1398e33d0478SWhisperity     WorkType = ImplicitSeq.AfterSecondStandard;
1399e33d0478SWhisperity   }
1400e33d0478SWhisperity 
1401e33d0478SWhisperity   if (ImplicitSeq) {
1402e33d0478SWhisperity     LLVM_DEBUG(llvm::dbgs()
1403e33d0478SWhisperity                << "<<< approximateImplicitConversion. Found a conversion.\n");
1404e33d0478SWhisperity     return {MixFlags::ImplicitConversion, ImplicitSeq};
1405e33d0478SWhisperity   }
1406e33d0478SWhisperity 
1407e33d0478SWhisperity   LLVM_DEBUG(
1408e33d0478SWhisperity       llvm::dbgs() << "<<< approximateImplicitConversion. No match found.\n");
1409e33d0478SWhisperity   return {MixFlags::None};
141026d864b4SWhisperity }
141126d864b4SWhisperity 
modelMixingRange(const TheCheck & Check,const FunctionDecl * FD,std::size_t StartIndex,const filter::SimilarlyUsedParameterPairSuppressor & UsageBasedSuppressor)1412b9ece034SWhisperity static MixableParameterRange modelMixingRange(
1413b9ece034SWhisperity     const TheCheck &Check, const FunctionDecl *FD, std::size_t StartIndex,
1414b9ece034SWhisperity     const filter::SimilarlyUsedParameterPairSuppressor &UsageBasedSuppressor) {
1415499e39c5SWhisperity   std::size_t NumParams = FD->getNumParams();
1416499e39c5SWhisperity   assert(StartIndex < NumParams && "out of bounds for start");
1417499e39c5SWhisperity   const ASTContext &Ctx = FD->getASTContext();
1418499e39c5SWhisperity 
1419499e39c5SWhisperity   MixableParameterRange Ret;
1420499e39c5SWhisperity   // A parameter at index 'StartIndex' had been trivially "checked".
1421499e39c5SWhisperity   Ret.NumParamsChecked = 1;
1422499e39c5SWhisperity 
1423499e39c5SWhisperity   for (std::size_t I = StartIndex + 1; I < NumParams; ++I) {
1424499e39c5SWhisperity     const ParmVarDecl *Ith = FD->getParamDecl(I);
14250fba450bSWhisperity     StringRef ParamName = Ith->getName();
14260fba450bSWhisperity     LLVM_DEBUG(llvm::dbgs()
14270fba450bSWhisperity                << "Check param #" << I << " '" << ParamName << "'...\n");
1428499e39c5SWhisperity     if (filter::isIgnoredParameter(Check, Ith)) {
1429499e39c5SWhisperity       LLVM_DEBUG(llvm::dbgs() << "Param #" << I << " is ignored. Break!\n");
1430499e39c5SWhisperity       break;
1431499e39c5SWhisperity     }
1432499e39c5SWhisperity 
14330fba450bSWhisperity     StringRef PrevParamName = FD->getParamDecl(I - 1)->getName();
14340fba450bSWhisperity     if (!ParamName.empty() && !PrevParamName.empty() &&
14350fba450bSWhisperity         filter::prefixSuffixCoverUnderThreshold(
14360fba450bSWhisperity             Check.NamePrefixSuffixSilenceDissimilarityTreshold, PrevParamName,
14370fba450bSWhisperity             ParamName)) {
14380fba450bSWhisperity       LLVM_DEBUG(llvm::dbgs() << "Parameter '" << ParamName
14390fba450bSWhisperity                               << "' follows a pattern with previous parameter '"
14400fba450bSWhisperity                               << PrevParamName << "'. Break!\n");
14410fba450bSWhisperity       break;
14420fba450bSWhisperity     }
14430fba450bSWhisperity 
1444499e39c5SWhisperity     // Now try to go forward and build the range of [Start, ..., I, I + 1, ...]
1445499e39c5SWhisperity     // parameters that can be messed up at a call site.
1446499e39c5SWhisperity     MixableParameterRange::MixVector MixesOfIth;
1447499e39c5SWhisperity     for (std::size_t J = StartIndex; J < I; ++J) {
1448499e39c5SWhisperity       const ParmVarDecl *Jth = FD->getParamDecl(J);
1449499e39c5SWhisperity       LLVM_DEBUG(llvm::dbgs()
1450499e39c5SWhisperity                  << "Check mix of #" << J << " against #" << I << "...\n");
1451499e39c5SWhisperity 
1452b9ece034SWhisperity       if (isSimilarlyUsedParameter(UsageBasedSuppressor, Ith, Jth)) {
1453b9ece034SWhisperity         // Consider the two similarly used parameters to not be possible in a
1454b9ece034SWhisperity         // mix-up at the user's request, if they enabled this heuristic.
1455b9ece034SWhisperity         LLVM_DEBUG(llvm::dbgs() << "Parameters #" << I << " and #" << J
1456b9ece034SWhisperity                                 << " deemed related, ignoring...\n");
1457b9ece034SWhisperity 
1458b9ece034SWhisperity         // If the parameter #I and #J mixes, then I is mixable with something
1459b9ece034SWhisperity         // in the current range, so the range has to be broken and I not
1460b9ece034SWhisperity         // included.
1461b9ece034SWhisperity         MixesOfIth.clear();
1462b9ece034SWhisperity         break;
1463b9ece034SWhisperity       }
1464b9ece034SWhisperity 
1465499e39c5SWhisperity       Mix M{Jth, Ith,
1466e33d0478SWhisperity             calculateMixability(Check, Jth->getType(), Ith->getType(), Ctx,
1467f3b55a8aSWhisperity                                 Check.ModelImplicitConversions
1468f3b55a8aSWhisperity                                     ? ImplicitConversionModellingMode::All
1469f3b55a8aSWhisperity                                     : ImplicitConversionModellingMode::None)};
1470499e39c5SWhisperity       LLVM_DEBUG(llvm::dbgs() << "Mix flags (raw)           : "
1471499e39c5SWhisperity                               << formatMixFlags(M.flags()) << '\n');
1472499e39c5SWhisperity       M.sanitize();
1473499e39c5SWhisperity       LLVM_DEBUG(llvm::dbgs() << "Mix flags (after sanitize): "
1474499e39c5SWhisperity                               << formatMixFlags(M.flags()) << '\n');
1475499e39c5SWhisperity 
1476e33d0478SWhisperity       assert(M.flagsValid() && "All flags decayed!");
1477499e39c5SWhisperity 
1478e33d0478SWhisperity       if (M.mixable())
1479499e39c5SWhisperity         MixesOfIth.emplace_back(std::move(M));
1480499e39c5SWhisperity     }
1481499e39c5SWhisperity 
1482499e39c5SWhisperity     if (MixesOfIth.empty()) {
1483499e39c5SWhisperity       // If there weren't any new mixes stored for Ith, the range is
1484499e39c5SWhisperity       // [Start, ..., I].
1485499e39c5SWhisperity       LLVM_DEBUG(llvm::dbgs()
1486499e39c5SWhisperity                  << "Param #" << I
1487499e39c5SWhisperity                  << " does not mix with any in the current range. Break!\n");
1488499e39c5SWhisperity       break;
1489499e39c5SWhisperity     }
1490499e39c5SWhisperity 
1491499e39c5SWhisperity     Ret.Mixes.insert(Ret.Mixes.end(), MixesOfIth.begin(), MixesOfIth.end());
1492499e39c5SWhisperity     ++Ret.NumParamsChecked; // Otherwise a new param was iterated.
1493499e39c5SWhisperity   }
1494499e39c5SWhisperity 
1495499e39c5SWhisperity   return Ret;
1496499e39c5SWhisperity }
1497499e39c5SWhisperity 
1498499e39c5SWhisperity } // namespace model
1499499e39c5SWhisperity 
1500b9ece034SWhisperity /// Matches DeclRefExprs and their ignorable wrappers to ParmVarDecls.
AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<Stmt>,paramRefExpr)1501b9ece034SWhisperity AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<Stmt>, paramRefExpr) {
1502b9ece034SWhisperity   return expr(ignoringParenImpCasts(ignoringElidableConstructorCall(
1503b9ece034SWhisperity       declRefExpr(to(parmVarDecl().bind("param"))))));
1504b9ece034SWhisperity }
1505b9ece034SWhisperity 
1506499e39c5SWhisperity namespace filter {
1507499e39c5SWhisperity 
1508499e39c5SWhisperity /// Returns whether the parameter's name or the parameter's type's name is
1509499e39c5SWhisperity /// configured by the user to be ignored from analysis and diagnostic.
isIgnoredParameter(const TheCheck & Check,const ParmVarDecl * Node)1510499e39c5SWhisperity static bool isIgnoredParameter(const TheCheck &Check, const ParmVarDecl *Node) {
1511499e39c5SWhisperity   LLVM_DEBUG(llvm::dbgs() << "Checking if '" << Node->getName()
1512499e39c5SWhisperity                           << "' is ignored.\n");
1513499e39c5SWhisperity 
1514499e39c5SWhisperity   if (!Node->getIdentifier())
15157542e721SKazu Hirata     return llvm::is_contained(Check.IgnoredParameterNames, "\"\"");
1516499e39c5SWhisperity 
1517499e39c5SWhisperity   StringRef NodeName = Node->getName();
15187542e721SKazu Hirata   if (llvm::is_contained(Check.IgnoredParameterNames, NodeName)) {
1519499e39c5SWhisperity     LLVM_DEBUG(llvm::dbgs() << "\tName ignored.\n");
1520499e39c5SWhisperity     return true;
1521499e39c5SWhisperity   }
1522499e39c5SWhisperity 
1523499e39c5SWhisperity   StringRef NodeTypeName = [Node] {
1524499e39c5SWhisperity     const ASTContext &Ctx = Node->getASTContext();
1525499e39c5SWhisperity     const SourceManager &SM = Ctx.getSourceManager();
1526499e39c5SWhisperity     SourceLocation B = Node->getTypeSpecStartLoc();
1527499e39c5SWhisperity     SourceLocation E = Node->getTypeSpecEndLoc();
1528499e39c5SWhisperity     LangOptions LO;
1529499e39c5SWhisperity 
1530499e39c5SWhisperity     LLVM_DEBUG(llvm::dbgs() << "\tType name code is '"
1531499e39c5SWhisperity                             << Lexer::getSourceText(
1532499e39c5SWhisperity                                    CharSourceRange::getTokenRange(B, E), SM, LO)
1533499e39c5SWhisperity                             << "'...\n");
1534499e39c5SWhisperity     if (B.isMacroID()) {
1535499e39c5SWhisperity       LLVM_DEBUG(llvm::dbgs() << "\t\tBeginning is macro.\n");
1536499e39c5SWhisperity       B = SM.getTopMacroCallerLoc(B);
1537499e39c5SWhisperity     }
1538499e39c5SWhisperity     if (E.isMacroID()) {
1539499e39c5SWhisperity       LLVM_DEBUG(llvm::dbgs() << "\t\tEnding is macro.\n");
1540499e39c5SWhisperity       E = Lexer::getLocForEndOfToken(SM.getTopMacroCallerLoc(E), 0, SM, LO);
1541499e39c5SWhisperity     }
1542499e39c5SWhisperity     LLVM_DEBUG(llvm::dbgs() << "\tType name code is '"
1543499e39c5SWhisperity                             << Lexer::getSourceText(
1544499e39c5SWhisperity                                    CharSourceRange::getTokenRange(B, E), SM, LO)
1545499e39c5SWhisperity                             << "'...\n");
1546499e39c5SWhisperity 
1547499e39c5SWhisperity     return Lexer::getSourceText(CharSourceRange::getTokenRange(B, E), SM, LO);
1548499e39c5SWhisperity   }();
1549499e39c5SWhisperity 
1550499e39c5SWhisperity   LLVM_DEBUG(llvm::dbgs() << "\tType name is '" << NodeTypeName << "'\n");
1551499e39c5SWhisperity   if (!NodeTypeName.empty()) {
1552499e39c5SWhisperity     if (llvm::any_of(Check.IgnoredParameterTypeSuffixes,
155312cb5405SNathan James                      [NodeTypeName](StringRef E) {
155476bbbcb4SKazu Hirata                        return !E.empty() && NodeTypeName.ends_with(E);
1555499e39c5SWhisperity                      })) {
1556499e39c5SWhisperity       LLVM_DEBUG(llvm::dbgs() << "\tType suffix ignored.\n");
1557499e39c5SWhisperity       return true;
1558499e39c5SWhisperity     }
1559499e39c5SWhisperity   }
1560499e39c5SWhisperity 
1561499e39c5SWhisperity   return false;
1562499e39c5SWhisperity }
1563499e39c5SWhisperity 
1564b9ece034SWhisperity /// This namespace contains the implementations for the suppression of
1565ade0662cSSalman Javed /// diagnostics from similarly-used ("related") parameters.
1566b9ece034SWhisperity namespace relatedness_heuristic {
1567b9ece034SWhisperity 
1568b9ece034SWhisperity static constexpr std::size_t SmallDataStructureSize = 4;
1569b9ece034SWhisperity 
1570b9ece034SWhisperity template <typename T, std::size_t N = SmallDataStructureSize>
1571b9ece034SWhisperity using ParamToSmallSetMap =
1572b9ece034SWhisperity     llvm::DenseMap<const ParmVarDecl *, llvm::SmallSet<T, N>>;
1573b9ece034SWhisperity 
1574b9ece034SWhisperity /// Returns whether the sets mapped to the two elements in the map have at
1575b9ece034SWhisperity /// least one element in common.
1576b9ece034SWhisperity template <typename MapTy, typename ElemTy>
lazyMapOfSetsIntersectionExists(const MapTy & Map,const ElemTy & E1,const ElemTy & E2)1577b9ece034SWhisperity bool lazyMapOfSetsIntersectionExists(const MapTy &Map, const ElemTy &E1,
1578b9ece034SWhisperity                                      const ElemTy &E2) {
1579b9ece034SWhisperity   auto E1Iterator = Map.find(E1);
1580b9ece034SWhisperity   auto E2Iterator = Map.find(E2);
1581b9ece034SWhisperity   if (E1Iterator == Map.end() || E2Iterator == Map.end())
1582b9ece034SWhisperity     return false;
1583b9ece034SWhisperity 
1584b9ece034SWhisperity   for (const auto &E1SetElem : E1Iterator->second)
15858bdf3878SKazu Hirata     if (E2Iterator->second.contains(E1SetElem))
1586b9ece034SWhisperity       return true;
1587b9ece034SWhisperity 
1588b9ece034SWhisperity   return false;
1589b9ece034SWhisperity }
1590b9ece034SWhisperity 
1591b9ece034SWhisperity /// Implements the heuristic that marks two parameters related if there is
1592b9ece034SWhisperity /// a usage for both in the same strict expression subtree. A strict
1593b9ece034SWhisperity /// expression subtree is a tree which only includes Expr nodes, i.e. no
1594b9ece034SWhisperity /// Stmts and no Decls.
1595b9ece034SWhisperity class AppearsInSameExpr : public RecursiveASTVisitor<AppearsInSameExpr> {
1596b9ece034SWhisperity   using Base = RecursiveASTVisitor<AppearsInSameExpr>;
1597b9ece034SWhisperity 
1598b9ece034SWhisperity   const FunctionDecl *FD;
1599b9ece034SWhisperity   const Expr *CurrentExprOnlyTreeRoot = nullptr;
1600b9ece034SWhisperity   llvm::DenseMap<const ParmVarDecl *,
1601b9ece034SWhisperity                  llvm::SmallPtrSet<const Expr *, SmallDataStructureSize>>
1602b9ece034SWhisperity       ParentExprsForParamRefs;
1603b9ece034SWhisperity 
1604b9ece034SWhisperity public:
setup(const FunctionDecl * FD)1605b9ece034SWhisperity   void setup(const FunctionDecl *FD) {
1606b9ece034SWhisperity     this->FD = FD;
1607b9ece034SWhisperity     TraverseFunctionDecl(const_cast<FunctionDecl *>(FD));
1608b9ece034SWhisperity   }
1609b9ece034SWhisperity 
operator ()(const ParmVarDecl * Param1,const ParmVarDecl * Param2) const1610b9ece034SWhisperity   bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1611b9ece034SWhisperity     return lazyMapOfSetsIntersectionExists(ParentExprsForParamRefs, Param1,
1612b9ece034SWhisperity                                            Param2);
1613b9ece034SWhisperity   }
1614b9ece034SWhisperity 
TraverseDecl(Decl * D)1615b9ece034SWhisperity   bool TraverseDecl(Decl *D) {
1616b9ece034SWhisperity     CurrentExprOnlyTreeRoot = nullptr;
1617b9ece034SWhisperity     return Base::TraverseDecl(D);
1618b9ece034SWhisperity   }
1619b9ece034SWhisperity 
TraverseStmt(Stmt * S,DataRecursionQueue * Queue=nullptr)1620b9ece034SWhisperity   bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue = nullptr) {
1621b9ece034SWhisperity     if (auto *E = dyn_cast_or_null<Expr>(S)) {
1622b9ece034SWhisperity       bool RootSetInCurrentStackFrame = false;
1623b9ece034SWhisperity       if (!CurrentExprOnlyTreeRoot) {
1624b9ece034SWhisperity         CurrentExprOnlyTreeRoot = E;
1625b9ece034SWhisperity         RootSetInCurrentStackFrame = true;
1626b9ece034SWhisperity       }
1627b9ece034SWhisperity 
1628b9ece034SWhisperity       bool Ret = Base::TraverseStmt(S);
1629b9ece034SWhisperity 
1630b9ece034SWhisperity       if (RootSetInCurrentStackFrame)
1631b9ece034SWhisperity         CurrentExprOnlyTreeRoot = nullptr;
1632b9ece034SWhisperity 
1633b9ece034SWhisperity       return Ret;
1634b9ece034SWhisperity     }
1635b9ece034SWhisperity 
1636b9ece034SWhisperity     // A Stmt breaks the strictly Expr subtree.
1637b9ece034SWhisperity     CurrentExprOnlyTreeRoot = nullptr;
1638b9ece034SWhisperity     return Base::TraverseStmt(S);
1639b9ece034SWhisperity   }
1640b9ece034SWhisperity 
VisitDeclRefExpr(DeclRefExpr * DRE)1641b9ece034SWhisperity   bool VisitDeclRefExpr(DeclRefExpr *DRE) {
1642b9ece034SWhisperity     if (!CurrentExprOnlyTreeRoot)
1643b9ece034SWhisperity       return true;
1644b9ece034SWhisperity 
1645b9ece034SWhisperity     if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
1646b9ece034SWhisperity       if (llvm::find(FD->parameters(), PVD))
1647b9ece034SWhisperity         ParentExprsForParamRefs[PVD].insert(CurrentExprOnlyTreeRoot);
1648b9ece034SWhisperity 
1649b9ece034SWhisperity     return true;
1650b9ece034SWhisperity   }
1651b9ece034SWhisperity };
1652b9ece034SWhisperity 
1653b9ece034SWhisperity /// Implements the heuristic that marks two parameters related if there are
1654b9ece034SWhisperity /// two separate calls to the same function (overload) and the parameters are
1655b9ece034SWhisperity /// passed to the same index in both calls, i.e f(a, b) and f(a, c) passes
1656b9ece034SWhisperity /// b and c to the same index (2) of f(), marking them related.
1657b9ece034SWhisperity class PassedToSameFunction {
1658b9ece034SWhisperity   ParamToSmallSetMap<std::pair<const FunctionDecl *, unsigned>> TargetParams;
1659b9ece034SWhisperity 
1660b9ece034SWhisperity public:
setup(const FunctionDecl * FD)1661b9ece034SWhisperity   void setup(const FunctionDecl *FD) {
1662b9ece034SWhisperity     auto ParamsAsArgsInFnCalls =
1663b9ece034SWhisperity         match(functionDecl(forEachDescendant(
1664b9ece034SWhisperity                   callExpr(forEachArgumentWithParam(
1665b9ece034SWhisperity                                paramRefExpr(), parmVarDecl().bind("passed-to")))
1666b9ece034SWhisperity                       .bind("call-expr"))),
1667b9ece034SWhisperity               *FD, FD->getASTContext());
1668b9ece034SWhisperity     for (const auto &Match : ParamsAsArgsInFnCalls) {
1669b9ece034SWhisperity       const auto *PassedParamOfThisFn = Match.getNodeAs<ParmVarDecl>("param");
1670b9ece034SWhisperity       const auto *CE = Match.getNodeAs<CallExpr>("call-expr");
1671b9ece034SWhisperity       const auto *PassedToParam = Match.getNodeAs<ParmVarDecl>("passed-to");
1672b9ece034SWhisperity       assert(PassedParamOfThisFn && CE && PassedToParam);
1673b9ece034SWhisperity 
1674b9ece034SWhisperity       const FunctionDecl *CalledFn = CE->getDirectCallee();
1675b9ece034SWhisperity       if (!CalledFn)
1676b9ece034SWhisperity         continue;
1677b9ece034SWhisperity 
1678f71ffd3bSKazu Hirata       std::optional<unsigned> TargetIdx;
1679b9ece034SWhisperity       unsigned NumFnParams = CalledFn->getNumParams();
1680b9ece034SWhisperity       for (unsigned Idx = 0; Idx < NumFnParams; ++Idx)
1681b9ece034SWhisperity         if (CalledFn->getParamDecl(Idx) == PassedToParam)
1682b9ece034SWhisperity           TargetIdx.emplace(Idx);
1683b9ece034SWhisperity 
16845413bf1bSKazu Hirata       assert(TargetIdx && "Matched, but didn't find index?");
1685b9ece034SWhisperity       TargetParams[PassedParamOfThisFn].insert(
1686b9ece034SWhisperity           {CalledFn->getCanonicalDecl(), *TargetIdx});
1687b9ece034SWhisperity     }
1688b9ece034SWhisperity   }
1689b9ece034SWhisperity 
operator ()(const ParmVarDecl * Param1,const ParmVarDecl * Param2) const1690b9ece034SWhisperity   bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1691b9ece034SWhisperity     return lazyMapOfSetsIntersectionExists(TargetParams, Param1, Param2);
1692b9ece034SWhisperity   }
1693b9ece034SWhisperity };
1694b9ece034SWhisperity 
1695b9ece034SWhisperity /// Implements the heuristic that marks two parameters related if the same
1696b9ece034SWhisperity /// member is accessed (referred to) inside the current function's body.
1697b9ece034SWhisperity class AccessedSameMemberOf {
1698b9ece034SWhisperity   ParamToSmallSetMap<const Decl *> AccessedMembers;
1699b9ece034SWhisperity 
1700b9ece034SWhisperity public:
setup(const FunctionDecl * FD)1701b9ece034SWhisperity   void setup(const FunctionDecl *FD) {
1702b9ece034SWhisperity     auto MembersCalledOnParams = match(
1703b9ece034SWhisperity         functionDecl(forEachDescendant(
1704b9ece034SWhisperity             memberExpr(hasObjectExpression(paramRefExpr())).bind("mem-expr"))),
1705b9ece034SWhisperity         *FD, FD->getASTContext());
1706b9ece034SWhisperity 
1707b9ece034SWhisperity     for (const auto &Match : MembersCalledOnParams) {
1708b9ece034SWhisperity       const auto *AccessedParam = Match.getNodeAs<ParmVarDecl>("param");
1709b9ece034SWhisperity       const auto *ME = Match.getNodeAs<MemberExpr>("mem-expr");
1710b9ece034SWhisperity       assert(AccessedParam && ME);
1711b9ece034SWhisperity       AccessedMembers[AccessedParam].insert(
1712b9ece034SWhisperity           ME->getMemberDecl()->getCanonicalDecl());
1713b9ece034SWhisperity     }
1714b9ece034SWhisperity   }
1715b9ece034SWhisperity 
operator ()(const ParmVarDecl * Param1,const ParmVarDecl * Param2) const1716b9ece034SWhisperity   bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1717b9ece034SWhisperity     return lazyMapOfSetsIntersectionExists(AccessedMembers, Param1, Param2);
1718b9ece034SWhisperity   }
1719b9ece034SWhisperity };
1720b9ece034SWhisperity 
1721b9ece034SWhisperity /// Implements the heuristic that marks two parameters related if different
1722b9ece034SWhisperity /// ReturnStmts return them from the function.
1723b9ece034SWhisperity class Returned {
1724b9ece034SWhisperity   llvm::SmallVector<const ParmVarDecl *, SmallDataStructureSize> ReturnedParams;
1725b9ece034SWhisperity 
1726b9ece034SWhisperity public:
setup(const FunctionDecl * FD)1727b9ece034SWhisperity   void setup(const FunctionDecl *FD) {
1728b9ece034SWhisperity     // TODO: Handle co_return.
1729b9ece034SWhisperity     auto ParamReturns = match(functionDecl(forEachDescendant(
1730b9ece034SWhisperity                                   returnStmt(hasReturnValue(paramRefExpr())))),
1731b9ece034SWhisperity                               *FD, FD->getASTContext());
1732b9ece034SWhisperity     for (const auto &Match : ParamReturns) {
1733b9ece034SWhisperity       const auto *ReturnedParam = Match.getNodeAs<ParmVarDecl>("param");
1734b9ece034SWhisperity       assert(ReturnedParam);
1735b9ece034SWhisperity 
1736b9ece034SWhisperity       if (find(FD->parameters(), ReturnedParam) == FD->param_end())
1737b9ece034SWhisperity         // Inside the subtree of a FunctionDecl there might be ReturnStmts of
1738b9ece034SWhisperity         // a parameter that isn't the parameter of the function, e.g. in the
1739b9ece034SWhisperity         // case of lambdas.
1740b9ece034SWhisperity         continue;
1741b9ece034SWhisperity 
1742b9ece034SWhisperity       ReturnedParams.emplace_back(ReturnedParam);
1743b9ece034SWhisperity     }
1744b9ece034SWhisperity   }
1745b9ece034SWhisperity 
operator ()(const ParmVarDecl * Param1,const ParmVarDecl * Param2) const1746b9ece034SWhisperity   bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
17477542e721SKazu Hirata     return llvm::is_contained(ReturnedParams, Param1) &&
17487542e721SKazu Hirata            llvm::is_contained(ReturnedParams, Param2);
1749b9ece034SWhisperity   }
1750b9ece034SWhisperity };
1751b9ece034SWhisperity 
1752b9ece034SWhisperity } // namespace relatedness_heuristic
1753b9ece034SWhisperity 
1754b9ece034SWhisperity /// Helper class that is used to detect if two parameters of the same function
1755b9ece034SWhisperity /// are used in a similar fashion, to suppress the result.
1756b9ece034SWhisperity class SimilarlyUsedParameterPairSuppressor {
1757b9ece034SWhisperity   const bool Enabled;
1758b9ece034SWhisperity   relatedness_heuristic::AppearsInSameExpr SameExpr;
1759b9ece034SWhisperity   relatedness_heuristic::PassedToSameFunction PassToFun;
1760b9ece034SWhisperity   relatedness_heuristic::AccessedSameMemberOf SameMember;
1761b9ece034SWhisperity   relatedness_heuristic::Returned Returns;
1762b9ece034SWhisperity 
1763b9ece034SWhisperity public:
SimilarlyUsedParameterPairSuppressor(const FunctionDecl * FD,bool Enable)1764b9ece034SWhisperity   SimilarlyUsedParameterPairSuppressor(const FunctionDecl *FD, bool Enable)
1765b9ece034SWhisperity       : Enabled(Enable) {
1766b9ece034SWhisperity     if (!Enable)
1767b9ece034SWhisperity       return;
1768b9ece034SWhisperity 
1769b9ece034SWhisperity     SameExpr.setup(FD);
1770b9ece034SWhisperity     PassToFun.setup(FD);
1771b9ece034SWhisperity     SameMember.setup(FD);
1772b9ece034SWhisperity     Returns.setup(FD);
1773b9ece034SWhisperity   }
1774b9ece034SWhisperity 
1775b9ece034SWhisperity   /// Returns whether the specified two parameters are deemed similarly used
1776b9ece034SWhisperity   /// or related by the heuristics.
operator ()(const ParmVarDecl * Param1,const ParmVarDecl * Param2) const1777b9ece034SWhisperity   bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1778b9ece034SWhisperity     if (!Enabled)
1779b9ece034SWhisperity       return false;
1780b9ece034SWhisperity 
1781b9ece034SWhisperity     LLVM_DEBUG(llvm::dbgs()
1782b9ece034SWhisperity                << "::: Matching similar usage / relatedness heuristic...\n");
1783b9ece034SWhisperity 
1784b9ece034SWhisperity     if (SameExpr(Param1, Param2)) {
1785b9ece034SWhisperity       LLVM_DEBUG(llvm::dbgs() << "::: Used in the same expression.\n");
1786b9ece034SWhisperity       return true;
1787b9ece034SWhisperity     }
1788b9ece034SWhisperity 
1789b9ece034SWhisperity     if (PassToFun(Param1, Param2)) {
1790b9ece034SWhisperity       LLVM_DEBUG(llvm::dbgs()
1791b9ece034SWhisperity                  << "::: Passed to same function in different calls.\n");
1792b9ece034SWhisperity       return true;
1793b9ece034SWhisperity     }
1794b9ece034SWhisperity 
1795b9ece034SWhisperity     if (SameMember(Param1, Param2)) {
1796b9ece034SWhisperity       LLVM_DEBUG(llvm::dbgs()
1797b9ece034SWhisperity                  << "::: Same member field access or method called.\n");
1798b9ece034SWhisperity       return true;
1799b9ece034SWhisperity     }
1800b9ece034SWhisperity 
1801b9ece034SWhisperity     if (Returns(Param1, Param2)) {
1802b9ece034SWhisperity       LLVM_DEBUG(llvm::dbgs() << "::: Both parameter returned.\n");
1803b9ece034SWhisperity       return true;
1804b9ece034SWhisperity     }
1805b9ece034SWhisperity 
1806b9ece034SWhisperity     LLVM_DEBUG(llvm::dbgs() << "::: None.\n");
1807b9ece034SWhisperity     return false;
1808b9ece034SWhisperity   }
1809b9ece034SWhisperity };
1810b9ece034SWhisperity 
1811b9ece034SWhisperity // (This function hoists the call to operator() of the wrapper, so we do not
1812b9ece034SWhisperity // need to define the previous class at the top of the file.)
1813b9ece034SWhisperity static inline bool
isSimilarlyUsedParameter(const SimilarlyUsedParameterPairSuppressor & Suppressor,const ParmVarDecl * Param1,const ParmVarDecl * Param2)1814b9ece034SWhisperity isSimilarlyUsedParameter(const SimilarlyUsedParameterPairSuppressor &Suppressor,
1815b9ece034SWhisperity                          const ParmVarDecl *Param1, const ParmVarDecl *Param2) {
1816b9ece034SWhisperity   return Suppressor(Param1, Param2);
1817b9ece034SWhisperity }
1818b9ece034SWhisperity 
padStringAtEnd(SmallVectorImpl<char> & Str,std::size_t ToLen)18190fba450bSWhisperity static void padStringAtEnd(SmallVectorImpl<char> &Str, std::size_t ToLen) {
18200fba450bSWhisperity   while (Str.size() < ToLen)
18210fba450bSWhisperity     Str.emplace_back('\0');
18220fba450bSWhisperity }
18230fba450bSWhisperity 
padStringAtBegin(SmallVectorImpl<char> & Str,std::size_t ToLen)18240fba450bSWhisperity static void padStringAtBegin(SmallVectorImpl<char> &Str, std::size_t ToLen) {
18250fba450bSWhisperity   while (Str.size() < ToLen)
18260fba450bSWhisperity     Str.insert(Str.begin(), '\0');
18270fba450bSWhisperity }
18280fba450bSWhisperity 
isCommonPrefixWithoutSomeCharacters(std::size_t N,StringRef S1,StringRef S2)18290fba450bSWhisperity static bool isCommonPrefixWithoutSomeCharacters(std::size_t N, StringRef S1,
18300fba450bSWhisperity                                                 StringRef S2) {
18310fba450bSWhisperity   assert(S1.size() >= N && S2.size() >= N);
18320fba450bSWhisperity   StringRef S1Prefix = S1.take_front(S1.size() - N),
18330fba450bSWhisperity             S2Prefix = S2.take_front(S2.size() - N);
18340fba450bSWhisperity   return S1Prefix == S2Prefix && !S1Prefix.empty();
18350fba450bSWhisperity }
18360fba450bSWhisperity 
isCommonSuffixWithoutSomeCharacters(std::size_t N,StringRef S1,StringRef S2)18370fba450bSWhisperity static bool isCommonSuffixWithoutSomeCharacters(std::size_t N, StringRef S1,
18380fba450bSWhisperity                                                 StringRef S2) {
18390fba450bSWhisperity   assert(S1.size() >= N && S2.size() >= N);
18400fba450bSWhisperity   StringRef S1Suffix = S1.take_back(S1.size() - N),
18410fba450bSWhisperity             S2Suffix = S2.take_back(S2.size() - N);
18420fba450bSWhisperity   return S1Suffix == S2Suffix && !S1Suffix.empty();
18430fba450bSWhisperity }
18440fba450bSWhisperity 
18450fba450bSWhisperity /// Returns whether the two strings are prefixes or suffixes of each other with
18460fba450bSWhisperity /// at most Threshold characters differing on the non-common end.
prefixSuffixCoverUnderThreshold(std::size_t Threshold,StringRef Str1,StringRef Str2)18470fba450bSWhisperity static bool prefixSuffixCoverUnderThreshold(std::size_t Threshold,
18480fba450bSWhisperity                                             StringRef Str1, StringRef Str2) {
18490fba450bSWhisperity   if (Threshold == 0)
18500fba450bSWhisperity     return false;
18510fba450bSWhisperity 
18520fba450bSWhisperity   // Pad the two strings to the longer length.
18530fba450bSWhisperity   std::size_t BiggerLength = std::max(Str1.size(), Str2.size());
18540fba450bSWhisperity 
18550fba450bSWhisperity   if (BiggerLength <= Threshold)
18560fba450bSWhisperity     // If the length of the strings is still smaller than the threshold, they
18570fba450bSWhisperity     // would be covered by an empty prefix/suffix with the rest differing.
18580fba450bSWhisperity     // (E.g. "A" and "X" with Threshold = 1 would mean we think they are
18590fba450bSWhisperity     // similar and do not warn about them, which is a too eager assumption.)
18600fba450bSWhisperity     return false;
18610fba450bSWhisperity 
18620fba450bSWhisperity   SmallString<32> S1PadE{Str1}, S2PadE{Str2};
18630fba450bSWhisperity   padStringAtEnd(S1PadE, BiggerLength);
18640fba450bSWhisperity   padStringAtEnd(S2PadE, BiggerLength);
18650fba450bSWhisperity 
18660fba450bSWhisperity   if (isCommonPrefixWithoutSomeCharacters(
18670fba450bSWhisperity           Threshold, StringRef{S1PadE.begin(), BiggerLength},
18680fba450bSWhisperity           StringRef{S2PadE.begin(), BiggerLength}))
18690fba450bSWhisperity     return true;
18700fba450bSWhisperity 
18710fba450bSWhisperity   SmallString<32> S1PadB{Str1}, S2PadB{Str2};
18720fba450bSWhisperity   padStringAtBegin(S1PadB, BiggerLength);
18730fba450bSWhisperity   padStringAtBegin(S2PadB, BiggerLength);
18740fba450bSWhisperity 
18750fba450bSWhisperity   if (isCommonSuffixWithoutSomeCharacters(
18760fba450bSWhisperity           Threshold, StringRef{S1PadB.begin(), BiggerLength},
18770fba450bSWhisperity           StringRef{S2PadB.begin(), BiggerLength}))
18780fba450bSWhisperity     return true;
18790fba450bSWhisperity 
18800fba450bSWhisperity   return false;
18810fba450bSWhisperity }
18820fba450bSWhisperity 
1883499e39c5SWhisperity } // namespace filter
1884499e39c5SWhisperity 
1885499e39c5SWhisperity /// Matches functions that have at least the specified amount of parameters.
AST_MATCHER_P(FunctionDecl,parameterCountGE,unsigned,N)1886499e39c5SWhisperity AST_MATCHER_P(FunctionDecl, parameterCountGE, unsigned, N) {
1887499e39c5SWhisperity   return Node.getNumParams() >= N;
1888499e39c5SWhisperity }
1889499e39c5SWhisperity 
1890499e39c5SWhisperity /// Matches *any* overloaded unary and binary operators.
AST_MATCHER(FunctionDecl,isOverloadedUnaryOrBinaryOperator)1891499e39c5SWhisperity AST_MATCHER(FunctionDecl, isOverloadedUnaryOrBinaryOperator) {
1892499e39c5SWhisperity   switch (Node.getOverloadedOperator()) {
1893499e39c5SWhisperity   case OO_None:
1894499e39c5SWhisperity   case OO_New:
1895499e39c5SWhisperity   case OO_Delete:
1896499e39c5SWhisperity   case OO_Array_New:
1897499e39c5SWhisperity   case OO_Array_Delete:
1898499e39c5SWhisperity   case OO_Conditional:
1899499e39c5SWhisperity   case OO_Coawait:
1900499e39c5SWhisperity     return false;
1901499e39c5SWhisperity 
1902499e39c5SWhisperity   default:
1903499e39c5SWhisperity     return Node.getNumParams() <= 2;
1904499e39c5SWhisperity   }
1905499e39c5SWhisperity }
1906499e39c5SWhisperity 
1907499e39c5SWhisperity /// Returns the DefaultMinimumLength if the Value of requested minimum length
1908499e39c5SWhisperity /// is less than 2. Minimum lengths of 0 or 1 are not accepted.
clampMinimumLength(const unsigned Value)1909499e39c5SWhisperity static inline unsigned clampMinimumLength(const unsigned Value) {
1910499e39c5SWhisperity   return Value < 2 ? DefaultMinimumLength : Value;
1911499e39c5SWhisperity }
1912499e39c5SWhisperity 
1913499e39c5SWhisperity // FIXME: Maybe unneeded, getNameForDiagnostic() is expected to change to return
1914499e39c5SWhisperity // a crafted location when the node itself is unnamed. (See D84658, D85033.)
1915499e39c5SWhisperity /// Returns the diagnostic-friendly name of the node, or empty string.
getName(const NamedDecl * ND)1916499e39c5SWhisperity static SmallString<64> getName(const NamedDecl *ND) {
1917499e39c5SWhisperity   SmallString<64> Name;
1918499e39c5SWhisperity   llvm::raw_svector_ostream OS{Name};
1919499e39c5SWhisperity   ND->getNameForDiagnostic(OS, ND->getASTContext().getPrintingPolicy(), false);
1920499e39c5SWhisperity   return Name;
1921499e39c5SWhisperity }
1922499e39c5SWhisperity 
1923499e39c5SWhisperity /// Returns the diagnostic-friendly name of the node, or a constant value.
getNameOrUnnamed(const NamedDecl * ND)1924499e39c5SWhisperity static SmallString<64> getNameOrUnnamed(const NamedDecl *ND) {
1925499e39c5SWhisperity   auto Name = getName(ND);
1926499e39c5SWhisperity   if (Name.empty())
1927499e39c5SWhisperity     Name = "<unnamed>";
1928499e39c5SWhisperity   return Name;
1929499e39c5SWhisperity }
1930499e39c5SWhisperity 
193126d864b4SWhisperity /// Returns whether a particular Mix between two parameters should have the
193226d864b4SWhisperity /// types involved diagnosed to the user. This is only a flag check.
needsToPrintTypeInDiagnostic(const model::Mix & M)193326d864b4SWhisperity static inline bool needsToPrintTypeInDiagnostic(const model::Mix &M) {
1934961e9e6aSWhisperity   using namespace model;
1935961e9e6aSWhisperity   return static_cast<bool>(
1936961e9e6aSWhisperity       M.flags() &
1937961e9e6aSWhisperity       (MixFlags::TypeAlias | MixFlags::ReferenceBind | MixFlags::Qualifiers));
193826d864b4SWhisperity }
193926d864b4SWhisperity 
1940e33d0478SWhisperity /// Returns whether a particular Mix between the two parameters should have
1941e33d0478SWhisperity /// implicit conversions elaborated.
needsToElaborateImplicitConversion(const model::Mix & M)1942e33d0478SWhisperity static inline bool needsToElaborateImplicitConversion(const model::Mix &M) {
1943e33d0478SWhisperity   return hasFlag(M.flags(), model::MixFlags::ImplicitConversion);
1944e33d0478SWhisperity }
1945e33d0478SWhisperity 
194626d864b4SWhisperity namespace {
194726d864b4SWhisperity 
1948e33d0478SWhisperity /// This class formats a conversion sequence into a "Ty1 -> Ty2 -> Ty3" line
1949e33d0478SWhisperity /// that can be used in diagnostics.
1950e33d0478SWhisperity struct FormattedConversionSequence {
1951e33d0478SWhisperity   std::string DiagnosticText;
1952e33d0478SWhisperity 
1953e33d0478SWhisperity   /// The formatted sequence is trivial if it is "Ty1 -> Ty2", but Ty1 and
1954e33d0478SWhisperity   /// Ty2 are the types that are shown in the code. A trivial diagnostic
1955e33d0478SWhisperity   /// does not need to be printed.
195609c1b2e1SPiotr Zegar   bool Trivial = true;
1957e33d0478SWhisperity 
FormattedConversionSequenceclang::tidy::bugprone::__anoneac3b3da0b11::FormattedConversionSequence1958e33d0478SWhisperity   FormattedConversionSequence(const PrintingPolicy &PP,
1959e33d0478SWhisperity                               StringRef StartTypeAsDiagnosed,
1960e33d0478SWhisperity                               const model::ConversionSequence &Conv,
1961e33d0478SWhisperity                               StringRef DestinationTypeAsDiagnosed) {
1962e33d0478SWhisperity     llvm::raw_string_ostream OS{DiagnosticText};
1963e33d0478SWhisperity 
1964e33d0478SWhisperity     // Print the type name as it is printed in other places in the diagnostic.
1965e33d0478SWhisperity     OS << '\'' << StartTypeAsDiagnosed << '\'';
1966e33d0478SWhisperity     std::string LastAddedType = StartTypeAsDiagnosed.str();
1967e33d0478SWhisperity     std::size_t NumElementsAdded = 1;
1968e33d0478SWhisperity 
1969e33d0478SWhisperity     // However, the parameter's defined type might not be what the implicit
1970e33d0478SWhisperity     // conversion started with, e.g. if a typedef is found to convert.
1971e33d0478SWhisperity     std::string SeqBeginTypeStr = Conv.Begin.getAsString(PP);
1972e33d0478SWhisperity     std::string SeqEndTypeStr = Conv.End.getAsString(PP);
1973e33d0478SWhisperity     if (StartTypeAsDiagnosed != SeqBeginTypeStr) {
1974e33d0478SWhisperity       OS << " (as '" << SeqBeginTypeStr << "')";
1975e33d0478SWhisperity       LastAddedType = SeqBeginTypeStr;
1976e33d0478SWhisperity       Trivial = false;
1977e33d0478SWhisperity     }
1978e33d0478SWhisperity 
1979e33d0478SWhisperity     auto AddType = [&](StringRef ToAdd) {
1980e33d0478SWhisperity       if (LastAddedType != ToAdd && ToAdd != SeqEndTypeStr) {
1981e33d0478SWhisperity         OS << " -> '" << ToAdd << "'";
1982e33d0478SWhisperity         LastAddedType = ToAdd.str();
1983e33d0478SWhisperity         ++NumElementsAdded;
1984e33d0478SWhisperity       }
1985e33d0478SWhisperity     };
1986e33d0478SWhisperity     for (QualType InvolvedType : Conv.getInvolvedTypesInSequence())
1987e33d0478SWhisperity       // Print every type that's unique in the sequence into the diagnosis.
1988e33d0478SWhisperity       AddType(InvolvedType.getAsString(PP));
1989e33d0478SWhisperity 
1990e33d0478SWhisperity     if (LastAddedType != DestinationTypeAsDiagnosed) {
1991e33d0478SWhisperity       OS << " -> '" << DestinationTypeAsDiagnosed << "'";
1992e33d0478SWhisperity       LastAddedType = DestinationTypeAsDiagnosed.str();
1993e33d0478SWhisperity       ++NumElementsAdded;
1994e33d0478SWhisperity     }
1995e33d0478SWhisperity 
1996e33d0478SWhisperity     // Same reasoning as with the Begin, e.g. if the converted-to type is a
1997e33d0478SWhisperity     // typedef, it will not be the same inside the conversion sequence (where
1998e33d0478SWhisperity     // the model already tore off typedefs) as in the code.
1999e33d0478SWhisperity     if (DestinationTypeAsDiagnosed != SeqEndTypeStr) {
2000e33d0478SWhisperity       OS << " (as '" << SeqEndTypeStr << "')";
2001e33d0478SWhisperity       LastAddedType = SeqEndTypeStr;
2002e33d0478SWhisperity       Trivial = false;
2003e33d0478SWhisperity     }
2004e33d0478SWhisperity 
2005e33d0478SWhisperity     if (Trivial && NumElementsAdded > 2)
2006e33d0478SWhisperity       // If the thing is still marked trivial but we have more than the
2007e33d0478SWhisperity       // from and to types added, it should not be trivial, and elaborated
2008e33d0478SWhisperity       // when printing the diagnostic.
2009e33d0478SWhisperity       Trivial = false;
2010e33d0478SWhisperity   }
2011e33d0478SWhisperity };
2012e33d0478SWhisperity 
201326d864b4SWhisperity /// Retains the elements called with and returns whether the call is done with
201426d864b4SWhisperity /// a new element.
201526d864b4SWhisperity template <typename E, std::size_t N> class InsertOnce {
201626d864b4SWhisperity   llvm::SmallSet<E, N> CalledWith;
201726d864b4SWhisperity 
201826d864b4SWhisperity public:
operator ()(E El)201926d864b4SWhisperity   bool operator()(E El) { return CalledWith.insert(std::move(El)).second; }
202026d864b4SWhisperity 
calledWith(const E & El) const202126d864b4SWhisperity   bool calledWith(const E &El) const { return CalledWith.contains(El); }
202226d864b4SWhisperity };
202326d864b4SWhisperity 
202426d864b4SWhisperity struct SwappedEqualQualTypePair {
202526d864b4SWhisperity   QualType LHSType, RHSType;
202626d864b4SWhisperity 
operator ==clang::tidy::bugprone::__anoneac3b3da0b11::SwappedEqualQualTypePair202726d864b4SWhisperity   bool operator==(const SwappedEqualQualTypePair &Other) const {
202826d864b4SWhisperity     return (LHSType == Other.LHSType && RHSType == Other.RHSType) ||
202926d864b4SWhisperity            (LHSType == Other.RHSType && RHSType == Other.LHSType);
203026d864b4SWhisperity   }
203126d864b4SWhisperity 
operator <clang::tidy::bugprone::__anoneac3b3da0b11::SwappedEqualQualTypePair203226d864b4SWhisperity   bool operator<(const SwappedEqualQualTypePair &Other) const {
203326d864b4SWhisperity     return LHSType < Other.LHSType && RHSType < Other.RHSType;
203426d864b4SWhisperity   }
203526d864b4SWhisperity };
203626d864b4SWhisperity 
203726d864b4SWhisperity struct TypeAliasDiagnosticTuple {
203826d864b4SWhisperity   QualType LHSType, RHSType, CommonType;
203926d864b4SWhisperity 
operator ==clang::tidy::bugprone::__anoneac3b3da0b11::TypeAliasDiagnosticTuple204026d864b4SWhisperity   bool operator==(const TypeAliasDiagnosticTuple &Other) const {
204126d864b4SWhisperity     return CommonType == Other.CommonType &&
204226d864b4SWhisperity            ((LHSType == Other.LHSType && RHSType == Other.RHSType) ||
204326d864b4SWhisperity             (LHSType == Other.RHSType && RHSType == Other.LHSType));
204426d864b4SWhisperity   }
204526d864b4SWhisperity 
operator <clang::tidy::bugprone::__anoneac3b3da0b11::TypeAliasDiagnosticTuple204626d864b4SWhisperity   bool operator<(const TypeAliasDiagnosticTuple &Other) const {
204726d864b4SWhisperity     return CommonType < Other.CommonType && LHSType < Other.LHSType &&
204826d864b4SWhisperity            RHSType < Other.RHSType;
204926d864b4SWhisperity   }
205026d864b4SWhisperity };
205126d864b4SWhisperity 
205226d864b4SWhisperity /// Helper class to only emit a diagnostic related to MixFlags::TypeAlias once.
205326d864b4SWhisperity class UniqueTypeAliasDiagnosticHelper
205426d864b4SWhisperity     : public InsertOnce<TypeAliasDiagnosticTuple, 8> {
205526d864b4SWhisperity   using Base = InsertOnce<TypeAliasDiagnosticTuple, 8>;
205626d864b4SWhisperity 
205726d864b4SWhisperity public:
205826d864b4SWhisperity   /// Returns whether the diagnostic for LHSType and RHSType which are both
205926d864b4SWhisperity   /// referring to CommonType being the same has not been emitted already.
operator ()(QualType LHSType,QualType RHSType,QualType CommonType)206026d864b4SWhisperity   bool operator()(QualType LHSType, QualType RHSType, QualType CommonType) {
206126d864b4SWhisperity     if (CommonType.isNull() || CommonType == LHSType || CommonType == RHSType)
206226d864b4SWhisperity       return Base::operator()({LHSType, RHSType, {}});
206326d864b4SWhisperity 
206426d864b4SWhisperity     TypeAliasDiagnosticTuple ThreeTuple{LHSType, RHSType, CommonType};
206526d864b4SWhisperity     if (!Base::operator()(ThreeTuple))
206626d864b4SWhisperity       return false;
206726d864b4SWhisperity 
206826d864b4SWhisperity     bool AlreadySaidLHSAndCommonIsSame = calledWith({LHSType, CommonType, {}});
206926d864b4SWhisperity     bool AlreadySaidRHSAndCommonIsSame = calledWith({RHSType, CommonType, {}});
207026d864b4SWhisperity     if (AlreadySaidLHSAndCommonIsSame && AlreadySaidRHSAndCommonIsSame) {
207126d864b4SWhisperity       // "SomeInt == int" && "SomeOtherInt == int" => "Common(SomeInt,
207226d864b4SWhisperity       // SomeOtherInt) == int", no need to diagnose it. Save the 3-tuple only
207326d864b4SWhisperity       // for shortcut if it ever appears again.
207426d864b4SWhisperity       return false;
207526d864b4SWhisperity     }
207626d864b4SWhisperity 
207726d864b4SWhisperity     return true;
207826d864b4SWhisperity   }
207926d864b4SWhisperity };
208026d864b4SWhisperity 
208126d864b4SWhisperity } // namespace
208226d864b4SWhisperity 
EasilySwappableParametersCheck(StringRef Name,ClangTidyContext * Context)2083499e39c5SWhisperity EasilySwappableParametersCheck::EasilySwappableParametersCheck(
2084499e39c5SWhisperity     StringRef Name, ClangTidyContext *Context)
2085499e39c5SWhisperity     : ClangTidyCheck(Name, Context),
2086499e39c5SWhisperity       MinimumLength(clampMinimumLength(
2087499e39c5SWhisperity           Options.get("MinimumLength", DefaultMinimumLength))),
2088499e39c5SWhisperity       IgnoredParameterNames(optutils::parseStringList(
2089499e39c5SWhisperity           Options.get("IgnoredParameterNames", DefaultIgnoredParameterNames))),
2090499e39c5SWhisperity       IgnoredParameterTypeSuffixes(optutils::parseStringList(
2091499e39c5SWhisperity           Options.get("IgnoredParameterTypeSuffixes",
2092961e9e6aSWhisperity                       DefaultIgnoredParameterTypeSuffixes))),
2093e33d0478SWhisperity       QualifiersMix(Options.get("QualifiersMix", DefaultQualifiersMix)),
2094e33d0478SWhisperity       ModelImplicitConversions(Options.get("ModelImplicitConversions",
2095b9ece034SWhisperity                                            DefaultModelImplicitConversions)),
2096b9ece034SWhisperity       SuppressParametersUsedTogether(
2097b9ece034SWhisperity           Options.get("SuppressParametersUsedTogether",
20980fba450bSWhisperity                       DefaultSuppressParametersUsedTogether)),
20990fba450bSWhisperity       NamePrefixSuffixSilenceDissimilarityTreshold(
21000fba450bSWhisperity           Options.get("NamePrefixSuffixSilenceDissimilarityTreshold",
21010fba450bSWhisperity                       DefaultNamePrefixSuffixSilenceDissimilarityTreshold)) {}
2102499e39c5SWhisperity 
storeOptions(ClangTidyOptions::OptionMap & Opts)2103499e39c5SWhisperity void EasilySwappableParametersCheck::storeOptions(
2104499e39c5SWhisperity     ClangTidyOptions::OptionMap &Opts) {
2105499e39c5SWhisperity   Options.store(Opts, "MinimumLength", MinimumLength);
2106499e39c5SWhisperity   Options.store(Opts, "IgnoredParameterNames",
2107499e39c5SWhisperity                 optutils::serializeStringList(IgnoredParameterNames));
2108499e39c5SWhisperity   Options.store(Opts, "IgnoredParameterTypeSuffixes",
2109499e39c5SWhisperity                 optutils::serializeStringList(IgnoredParameterTypeSuffixes));
2110961e9e6aSWhisperity   Options.store(Opts, "QualifiersMix", QualifiersMix);
2111e33d0478SWhisperity   Options.store(Opts, "ModelImplicitConversions", ModelImplicitConversions);
2112b9ece034SWhisperity   Options.store(Opts, "SuppressParametersUsedTogether",
2113b9ece034SWhisperity                 SuppressParametersUsedTogether);
21140fba450bSWhisperity   Options.store(Opts, "NamePrefixSuffixSilenceDissimilarityTreshold",
21150fba450bSWhisperity                 NamePrefixSuffixSilenceDissimilarityTreshold);
2116499e39c5SWhisperity }
2117499e39c5SWhisperity 
registerMatchers(MatchFinder * Finder)2118499e39c5SWhisperity void EasilySwappableParametersCheck::registerMatchers(MatchFinder *Finder) {
2119499e39c5SWhisperity   const auto BaseConstraints = functionDecl(
2120499e39c5SWhisperity       // Only report for definition nodes, as fixing the issues reported
2121499e39c5SWhisperity       // requires the user to be able to change code.
2122499e39c5SWhisperity       isDefinition(), parameterCountGE(MinimumLength),
2123499e39c5SWhisperity       unless(isOverloadedUnaryOrBinaryOperator()));
2124499e39c5SWhisperity 
2125499e39c5SWhisperity   Finder->addMatcher(
2126499e39c5SWhisperity       functionDecl(BaseConstraints,
2127499e39c5SWhisperity                    unless(ast_matchers::isTemplateInstantiation()))
2128499e39c5SWhisperity           .bind("func"),
2129499e39c5SWhisperity       this);
2130499e39c5SWhisperity   Finder->addMatcher(
2131499e39c5SWhisperity       functionDecl(BaseConstraints, isExplicitTemplateSpecialization())
2132499e39c5SWhisperity           .bind("func"),
2133499e39c5SWhisperity       this);
2134499e39c5SWhisperity }
2135499e39c5SWhisperity 
check(const MatchFinder::MatchResult & Result)2136499e39c5SWhisperity void EasilySwappableParametersCheck::check(
2137499e39c5SWhisperity     const MatchFinder::MatchResult &Result) {
213826d864b4SWhisperity   using namespace model;
213926d864b4SWhisperity   using namespace filter;
214026d864b4SWhisperity 
2141499e39c5SWhisperity   const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("func");
2142499e39c5SWhisperity   assert(FD);
2143499e39c5SWhisperity 
2144499e39c5SWhisperity   const PrintingPolicy &PP = FD->getASTContext().getPrintingPolicy();
2145499e39c5SWhisperity   std::size_t NumParams = FD->getNumParams();
2146499e39c5SWhisperity   std::size_t MixableRangeStartIndex = 0;
2147499e39c5SWhisperity 
2148b9ece034SWhisperity   // Spawn one suppressor and if the user requested, gather information from
2149b9ece034SWhisperity   // the AST for the parameters' usages.
2150b9ece034SWhisperity   filter::SimilarlyUsedParameterPairSuppressor UsageBasedSuppressor{
2151b9ece034SWhisperity       FD, SuppressParametersUsedTogether};
2152b9ece034SWhisperity 
2153499e39c5SWhisperity   LLVM_DEBUG(llvm::dbgs() << "Begin analysis of " << getName(FD) << " with "
2154499e39c5SWhisperity                           << NumParams << " parameters...\n");
2155499e39c5SWhisperity   while (MixableRangeStartIndex < NumParams) {
215626d864b4SWhisperity     if (isIgnoredParameter(*this, FD->getParamDecl(MixableRangeStartIndex))) {
2157499e39c5SWhisperity       LLVM_DEBUG(llvm::dbgs()
2158499e39c5SWhisperity                  << "Parameter #" << MixableRangeStartIndex << " ignored.\n");
2159499e39c5SWhisperity       ++MixableRangeStartIndex;
2160499e39c5SWhisperity       continue;
2161499e39c5SWhisperity     }
2162499e39c5SWhisperity 
2163b9ece034SWhisperity     MixableParameterRange R = modelMixingRange(
2164b9ece034SWhisperity         *this, FD, MixableRangeStartIndex, UsageBasedSuppressor);
2165499e39c5SWhisperity     assert(R.NumParamsChecked > 0 && "Ensure forward progress!");
2166499e39c5SWhisperity     MixableRangeStartIndex += R.NumParamsChecked;
2167499e39c5SWhisperity     if (R.NumParamsChecked < MinimumLength) {
2168499e39c5SWhisperity       LLVM_DEBUG(llvm::dbgs() << "Ignoring range of " << R.NumParamsChecked
2169499e39c5SWhisperity                               << " lower than limit.\n");
2170499e39c5SWhisperity       continue;
2171499e39c5SWhisperity     }
2172499e39c5SWhisperity 
217326d864b4SWhisperity     bool NeedsAnyTypeNote = llvm::any_of(R.Mixes, needsToPrintTypeInDiagnostic);
2174e33d0478SWhisperity     bool HasAnyImplicits =
2175e33d0478SWhisperity         llvm::any_of(R.Mixes, needsToElaborateImplicitConversion);
2176499e39c5SWhisperity     const ParmVarDecl *First = R.getFirstParam(), *Last = R.getLastParam();
2177499e39c5SWhisperity     std::string FirstParamTypeAsWritten = First->getType().getAsString(PP);
2178499e39c5SWhisperity     {
217926d864b4SWhisperity       StringRef DiagText;
218026d864b4SWhisperity 
2181e33d0478SWhisperity       if (HasAnyImplicits)
2182e33d0478SWhisperity         DiagText = "%0 adjacent parameters of %1 of convertible types are "
2183e33d0478SWhisperity                    "easily swapped by mistake";
2184e33d0478SWhisperity       else if (NeedsAnyTypeNote)
218526d864b4SWhisperity         DiagText = "%0 adjacent parameters of %1 of similar type are easily "
218626d864b4SWhisperity                    "swapped by mistake";
218726d864b4SWhisperity       else
218826d864b4SWhisperity         DiagText = "%0 adjacent parameters of %1 of similar type ('%2') are "
218926d864b4SWhisperity                    "easily swapped by mistake";
2190499e39c5SWhisperity 
2191499e39c5SWhisperity       auto Diag = diag(First->getOuterLocStart(), DiagText)
219226d864b4SWhisperity                   << static_cast<unsigned>(R.NumParamsChecked) << FD;
219326d864b4SWhisperity       if (!NeedsAnyTypeNote)
219426d864b4SWhisperity         Diag << FirstParamTypeAsWritten;
2195499e39c5SWhisperity 
2196499e39c5SWhisperity       CharSourceRange HighlightRange = CharSourceRange::getTokenRange(
2197499e39c5SWhisperity           First->getBeginLoc(), Last->getEndLoc());
2198499e39c5SWhisperity       Diag << HighlightRange;
2199499e39c5SWhisperity     }
2200499e39c5SWhisperity 
2201499e39c5SWhisperity     // There is a chance that the previous highlight did not succeed, e.g. when
2202499e39c5SWhisperity     // the two parameters are on different lines. For clarity, show the user
2203499e39c5SWhisperity     // the involved variable explicitly.
2204499e39c5SWhisperity     diag(First->getLocation(), "the first parameter in the range is '%0'",
2205499e39c5SWhisperity          DiagnosticIDs::Note)
2206499e39c5SWhisperity         << getNameOrUnnamed(First)
2207499e39c5SWhisperity         << CharSourceRange::getTokenRange(First->getLocation(),
2208499e39c5SWhisperity                                           First->getLocation());
2209499e39c5SWhisperity     diag(Last->getLocation(), "the last parameter in the range is '%0'",
2210499e39c5SWhisperity          DiagnosticIDs::Note)
2211499e39c5SWhisperity         << getNameOrUnnamed(Last)
2212499e39c5SWhisperity         << CharSourceRange::getTokenRange(Last->getLocation(),
2213499e39c5SWhisperity                                           Last->getLocation());
221426d864b4SWhisperity 
221526d864b4SWhisperity     // Helper classes to silence elaborative diagnostic notes that would be
221626d864b4SWhisperity     // too verbose.
221726d864b4SWhisperity     UniqueTypeAliasDiagnosticHelper UniqueTypeAlias;
221826d864b4SWhisperity     InsertOnce<SwappedEqualQualTypePair, 8> UniqueBindPower;
2219e33d0478SWhisperity     InsertOnce<SwappedEqualQualTypePair, 8> UniqueImplicitConversion;
222026d864b4SWhisperity 
2221e33d0478SWhisperity     for (const model::Mix &M : R.Mixes) {
2222e33d0478SWhisperity       assert(M.mixable() && "Sentinel or false mix in result.");
2223e33d0478SWhisperity       if (!needsToPrintTypeInDiagnostic(M) &&
2224e33d0478SWhisperity           !needsToElaborateImplicitConversion(M))
2225e33d0478SWhisperity         continue;
222626d864b4SWhisperity 
222726d864b4SWhisperity       // Typedefs might result in the type of the variable needing to be
222826d864b4SWhisperity       // emitted to a note diagnostic, so prepare it.
222926d864b4SWhisperity       const ParmVarDecl *LVar = M.First;
223026d864b4SWhisperity       const ParmVarDecl *RVar = M.Second;
223126d864b4SWhisperity       QualType LType = LVar->getType();
223226d864b4SWhisperity       QualType RType = RVar->getType();
223326d864b4SWhisperity       QualType CommonType = M.commonUnderlyingType();
2234961e9e6aSWhisperity       std::string LTypeStr = LType.getAsString(PP);
2235961e9e6aSWhisperity       std::string RTypeStr = RType.getAsString(PP);
223626d864b4SWhisperity       std::string CommonTypeStr = CommonType.getAsString(PP);
223726d864b4SWhisperity 
223826d864b4SWhisperity       if (hasFlag(M.flags(), MixFlags::TypeAlias) &&
223926d864b4SWhisperity           UniqueTypeAlias(LType, RType, CommonType)) {
224026d864b4SWhisperity         StringRef DiagText;
224126d864b4SWhisperity         bool ExplicitlyPrintCommonType = false;
22428b0cc4a6SWhisperity         if (LTypeStr == CommonTypeStr || RTypeStr == CommonTypeStr) {
2243961e9e6aSWhisperity           if (hasFlag(M.flags(), MixFlags::Qualifiers))
2244961e9e6aSWhisperity             DiagText = "after resolving type aliases, '%0' and '%1' share a "
2245961e9e6aSWhisperity                        "common type";
2246961e9e6aSWhisperity           else
224726d864b4SWhisperity             DiagText =
224826d864b4SWhisperity                 "after resolving type aliases, '%0' and '%1' are the same";
22498b0cc4a6SWhisperity         } else if (!CommonType.isNull()) {
225026d864b4SWhisperity           DiagText = "after resolving type aliases, the common type of '%0' "
225126d864b4SWhisperity                      "and '%1' is '%2'";
225226d864b4SWhisperity           ExplicitlyPrintCommonType = true;
225326d864b4SWhisperity         }
225426d864b4SWhisperity 
225526d864b4SWhisperity         auto Diag =
225626d864b4SWhisperity             diag(LVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2257961e9e6aSWhisperity             << LTypeStr << RTypeStr;
225826d864b4SWhisperity         if (ExplicitlyPrintCommonType)
225926d864b4SWhisperity           Diag << CommonTypeStr;
226026d864b4SWhisperity       }
226126d864b4SWhisperity 
2262961e9e6aSWhisperity       if ((hasFlag(M.flags(), MixFlags::ReferenceBind) ||
2263961e9e6aSWhisperity            hasFlag(M.flags(), MixFlags::Qualifiers)) &&
226426d864b4SWhisperity           UniqueBindPower({LType, RType})) {
226526d864b4SWhisperity         StringRef DiagText = "'%0' and '%1' parameters accept and bind the "
226626d864b4SWhisperity                              "same kind of values";
226726d864b4SWhisperity         diag(RVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2268961e9e6aSWhisperity             << LTypeStr << RTypeStr;
226926d864b4SWhisperity       }
2270e33d0478SWhisperity 
2271e33d0478SWhisperity       if (needsToElaborateImplicitConversion(M) &&
2272e33d0478SWhisperity           UniqueImplicitConversion({LType, RType})) {
2273e33d0478SWhisperity         const model::ConversionSequence &LTR =
2274e33d0478SWhisperity             M.leftToRightConversionSequence();
2275e33d0478SWhisperity         const model::ConversionSequence &RTL =
2276e33d0478SWhisperity             M.rightToLeftConversionSequence();
2277e33d0478SWhisperity         FormattedConversionSequence LTRFmt{PP, LTypeStr, LTR, RTypeStr};
2278e33d0478SWhisperity         FormattedConversionSequence RTLFmt{PP, RTypeStr, RTL, LTypeStr};
2279e33d0478SWhisperity 
2280e33d0478SWhisperity         StringRef DiagText = "'%0' and '%1' may be implicitly converted";
2281e33d0478SWhisperity         if (!LTRFmt.Trivial || !RTLFmt.Trivial)
2282e33d0478SWhisperity           DiagText = "'%0' and '%1' may be implicitly converted: %2, %3";
2283e33d0478SWhisperity 
2284e33d0478SWhisperity         {
2285e33d0478SWhisperity           auto Diag =
2286e33d0478SWhisperity               diag(RVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2287e33d0478SWhisperity               << LTypeStr << RTypeStr;
2288e33d0478SWhisperity 
2289e33d0478SWhisperity           if (!LTRFmt.Trivial || !RTLFmt.Trivial)
2290e33d0478SWhisperity             Diag << LTRFmt.DiagnosticText << RTLFmt.DiagnosticText;
2291e33d0478SWhisperity         }
2292e33d0478SWhisperity 
2293e33d0478SWhisperity         StringRef ConversionFunctionDiagText =
2294e33d0478SWhisperity             "the implicit conversion involves the "
2295e33d0478SWhisperity             "%select{|converting constructor|conversion operator}0 "
2296e33d0478SWhisperity             "declared here";
2297e33d0478SWhisperity         if (const FunctionDecl *LFD = LTR.getUserDefinedConversionFunction())
2298e33d0478SWhisperity           diag(LFD->getLocation(), ConversionFunctionDiagText,
2299e33d0478SWhisperity                DiagnosticIDs::Note)
2300e33d0478SWhisperity               << static_cast<unsigned>(LTR.UDConvKind)
2301e33d0478SWhisperity               << LTR.getUserDefinedConversionHighlight();
2302e33d0478SWhisperity         if (const FunctionDecl *RFD = RTL.getUserDefinedConversionFunction())
2303e33d0478SWhisperity           diag(RFD->getLocation(), ConversionFunctionDiagText,
2304e33d0478SWhisperity                DiagnosticIDs::Note)
2305e33d0478SWhisperity               << static_cast<unsigned>(RTL.UDConvKind)
2306e33d0478SWhisperity               << RTL.getUserDefinedConversionHighlight();
230726d864b4SWhisperity       }
230826d864b4SWhisperity     }
2309499e39c5SWhisperity   }
2310499e39c5SWhisperity }
2311499e39c5SWhisperity 
23127d2ea6c4SCarlos Galvez } // namespace clang::tidy::bugprone
2313