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