brintos

brintos / llvm-project-archived public Read only

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