clang-tools 22.0.0git
EasilySwappableParametersCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
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 NamePrefixSuffixSilenceDissimilarityThreshold
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.
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:
344 return UDConvCtor.UserDefinedType;
345 case UDCK_Oper:
346 return UDConvOp.ConversionOperatorResultType;
347 case UDCK_None:
348 return {};
349 }
350 llvm_unreachable("Invalid UDConv kind.");
351 }
352
353 const CXXMethodDecl *getUserDefinedConversionFunction() const {
354 switch (UDConvKind) {
355 case UDCK_Ctor:
356 return UDConvCtor.Fun;
357 case UDCK_Oper:
358 return UDConvOp.Fun;
359 case UDCK_None:
360 return {};
361 }
362 llvm_unreachable("Invalid UDConv kind.");
363 }
364
365 /// Returns the SourceRange in the text that corresponds to the 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
416
417 void sanitize() {
418 assert(Flags != MixFlags::Invalid && "sanitize() called on invalid bitvec");
419
420 const 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};
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 const 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.
559
560 ///< The full implicit conversion sequence is modelled.
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, 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.
590 bool HasMixabilityBreakingQualifiers;
591
592 /// The set of equal qualifiers between the two types.
593 Qualifiers CommonQualifiers;
594};
595
596} // namespace
597
598/// Returns if the two types are qualified in a way that ever after equating or
599/// removing local CVR qualification, even if the unqualified types would mix,
600/// the qualified ones don't, because there are some other local qualifiers
601/// that aren't equal.
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 const MixData UnqualifiedMixability =
765 calculateMixability(Check, LType.getLocalUnqualifiedType(),
766 RType.getLocalUnqualifiedType(), Ctx, ImplicitMode)
767 .withCommonTypeTransformed([&AdditionalQuals, &Ctx](QualType QT) {
768 // Once the mixability was deduced, apply the qualifiers 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 const MixData MixLTR =
817 approximateImplicitConversion(Check, LType, RType, Ctx, ImplicitMode);
818 LLVM_DEBUG(
819 if (hasFlag(MixLTR.Flags, MixFlags::ImplicitConversion)) llvm::dbgs()
820 << "--- calculateMixability. Implicit Left -> Right found.\n";);
821
822 if (ImplicitMode ==
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 const MixData MixRTL =
837 approximateImplicitConversion(Check, RType, LType, Ctx, ImplicitMode);
838 LLVM_DEBUG(
839 if (hasFlag(MixRTL.Flags, MixFlags::ImplicitConversion)) llvm::dbgs()
840 << "--- calculateMixability. Implicit Right -> Left found.\n";);
841
842 if (MixLTR.Conversion && MixRTL.Conversion) {
843 LLVM_DEBUG(
844 llvm::dbgs()
845 << "<<< calculateMixability. Implicit conversion, bidirectional.\n");
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 const QualType LCanonical = LType.getCanonicalType();
872 if (LCanonical == RType.getCanonicalType()) {
873 LLVM_DEBUG(llvm::dbgs()
874 << "<<< calculateMixability. Same CanonicalType.\n");
875 MixToReturn = {MixFlags::Canonical, LCanonical};
876 }
877
878 if (RecursiveReturnDiscardingCanonicalType)
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 const bool FromNumeric = FromBuiltin && (FromBuiltin->isIntegerType() ||
987 FromBuiltin->isFloatingType());
988 const bool ToNumeric =
989 ToBuiltin && (ToBuiltin->isIntegerType() || ToBuiltin->isFloatingType());
990 if (FromNumeric && ToNumeric) {
991 // If both are integral types, the numeric conversion is performed.
992 // Reapply the qualifiers of the original type, however, 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->getAsCanonical<EnumType>();
1001 const auto *ToEnum = To->getAs<EnumType>();
1002 if (FromEnum && ToNumeric && FromEnum->isUnscopedEnumerationType()) {
1003 // Unscoped enumerations (or enumerations in C) convert to numerics.
1004 LLVM_DEBUG(llvm::dbgs()
1005 << "--- approximateStdConv. Unscoped enum to numeric.\n");
1006 WorkType = QualType{ToBuiltin, FastQualifiersToApply};
1007 } else if (FromNumeric && ToEnum && ToEnum->isUnscopedEnumerationType()) {
1008 // Numeric types convert to enumerations only in C.
1009 if (Ctx.getLangOpts().CPlusPlus) {
1010 LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Numeric to unscoped "
1011 "enum, not possible in C++!\n");
1012 return {};
1013 }
1014
1015 LLVM_DEBUG(llvm::dbgs()
1016 << "--- approximateStdConv. Numeric to unscoped enum.\n");
1017 WorkType = QualType{ToEnum, FastQualifiersToApply};
1018 }
1019
1020 // Check for pointer conversions.
1021 const auto *FromPtr = WorkType->getAs<PointerType>();
1022 const auto *ToPtr = To->getAs<PointerType>();
1023 if (FromPtr && ToPtr) {
1024 if (ToPtr->isVoidPointerType()) {
1025 LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. To void pointer.\n");
1026 WorkType = QualType{ToPtr, FastQualifiersToApply};
1027 }
1028
1029 const auto *FromRecordPtr = FromPtr->getPointeeCXXRecordDecl();
1030 const auto *ToRecordPtr = ToPtr->getPointeeCXXRecordDecl();
1031 if (isDerivedToBase(FromRecordPtr, ToRecordPtr)) {
1032 LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Derived* to Base*\n");
1033 WorkType = QualType{ToPtr, FastQualifiersToApply};
1034 }
1035 }
1036
1037 // Model the slicing Derived-to-Base too, as "BaseT temporary = derived;"
1038 // can also be compiled.
1039 const auto *FromRecord = WorkType->getAsCXXRecordDecl();
1040 const auto *ToRecord = To->getAsCXXRecordDecl();
1041 if (isDerivedToBase(FromRecord, ToRecord)) {
1042 LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Derived To Base.\n");
1043 WorkType = QualType{
1044 ToRecord->getASTContext().getCanonicalTagType(ToRecord)->getTypePtr(),
1045 FastQualifiersToApply};
1046 }
1047
1048 if (Ctx.getLangOpts().CPlusPlus17 && FromPtr && ToPtr) {
1049 // Function pointer conversion: A noexcept function pointer can be passed
1050 // to a non-noexcept one.
1051 const auto *FromFunctionPtr =
1052 FromPtr->getPointeeType()->getAs<FunctionProtoType>();
1053 const auto *ToFunctionPtr =
1054 ToPtr->getPointeeType()->getAs<FunctionProtoType>();
1055 if (FromFunctionPtr && ToFunctionPtr &&
1056 FromFunctionPtr->hasNoexceptExceptionSpec() &&
1057 !ToFunctionPtr->hasNoexceptExceptionSpec()) {
1058 LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. noexcept function "
1059 "pointer to non-noexcept.\n");
1060 WorkType = QualType{ToPtr, FastQualifiersToApply};
1061 }
1062 }
1063
1064 // Qualifier adjustments are modelled according to the user's request in
1065 // the QualifiersMix check config.
1066 LLVM_DEBUG(llvm::dbgs()
1067 << "--- approximateStdConv. Trying qualifier adjustment...\n");
1068 MixData QualConv = calculateMixability(Check, WorkType, To, Ctx,
1070 QualConv.sanitize();
1071 if (hasFlag(QualConv.Flags, MixFlags::Qualifiers)) {
1072 LLVM_DEBUG(llvm::dbgs()
1073 << "<<< approximateStdConv. Qualifiers adjusted.\n");
1074 WorkType = To;
1075 }
1076
1077 if (ASTContext::hasSameType(WorkType, To)) {
1078 LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Reached 'To' type.\n");
1079 return {Ctx.getCommonSugaredType(WorkType, To)};
1080 }
1081
1082 LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Did not reach 'To'.\n");
1083 return {};
1084}
1085
1086namespace {
1087
1088/// Helper class for storing possible user-defined conversion calls that
1089/// *could* take place in an implicit conversion, and selecting the one that
1090/// most likely *does*, if any.
1091class UserDefinedConversionSelector {
1092public:
1093 /// The conversion associated with a conversion function, together with the
1094 /// mixability flags of the conversion function's parameter or return type
1095 /// to the rest of the sequence the selector is used in, and the sequence
1096 /// that applied through the conversion itself.
1097 struct PreparedConversion {
1098 const CXXMethodDecl *ConversionFun;
1099 MixFlags Flags;
1100 ConversionSequence Seq;
1101
1102 PreparedConversion(const CXXMethodDecl *CMD, MixFlags F,
1103 ConversionSequence S)
1104 : ConversionFun(CMD), Flags(F), Seq(S) {}
1105 };
1106
1107 UserDefinedConversionSelector(const TheCheck &Check) : Check(Check) {}
1108
1109 /// Adds the conversion between the two types for the given function into
1110 /// the possible implicit conversion set. FromType and ToType is either:
1111 /// * the result of a standard sequence and a converting ctor parameter
1112 /// * the return type of a conversion operator and the expected target of
1113 /// an implicit conversion.
1114 void addConversion(const CXXMethodDecl *ConvFun, QualType FromType,
1115 QualType ToType) {
1116 // Try to go from the FromType to the ToType with only a single implicit
1117 // conversion, to see if the conversion function is applicable.
1118 MixData Mix = calculateMixability(
1119 Check, FromType, ToType, ConvFun->getASTContext(),
1121 Mix.sanitize();
1122 if (!Mix.indicatesMixability())
1123 return;
1124
1125 LLVM_DEBUG(llvm::dbgs() << "--- tryConversion. Found viable with flags: "
1126 << formatMixFlags(Mix.Flags) << '\n');
1127 FlaggedConversions.emplace_back(ConvFun, Mix.Flags, Mix.Conversion);
1128 }
1129
1130 /// Selects the best conversion function that is applicable from the
1131 /// prepared set of potential conversion functions taken.
1132 std::optional<PreparedConversion> operator()() const {
1133 if (FlaggedConversions.empty()) {
1134 LLVM_DEBUG(llvm::dbgs() << "--- selectUserDefinedConv. Empty.\n");
1135 return {};
1136 }
1137 if (FlaggedConversions.size() == 1) {
1138 LLVM_DEBUG(llvm::dbgs() << "--- selectUserDefinedConv. Single.\n");
1139 return FlaggedConversions.front();
1140 }
1141
1142 std::optional<PreparedConversion> BestConversion;
1143 unsigned short HowManyGoodConversions = 0;
1144 for (const auto &Prepared : FlaggedConversions) {
1145 LLVM_DEBUG(llvm::dbgs() << "--- selectUserDefinedConv. Candidate flags: "
1146 << formatMixFlags(Prepared.Flags) << '\n');
1147 if (!BestConversion) {
1148 BestConversion = Prepared;
1149 ++HowManyGoodConversions;
1150 continue;
1151 }
1152
1153 const bool BestConversionHasImplicit =
1154 hasFlag(BestConversion->Flags, MixFlags::ImplicitConversion);
1155 const bool ThisConversionHasImplicit =
1156 hasFlag(Prepared.Flags, MixFlags::ImplicitConversion);
1157 if (!BestConversionHasImplicit && ThisConversionHasImplicit)
1158 // This is a worse conversion, because a better one was found earlier.
1159 continue;
1160
1161 if (BestConversionHasImplicit && !ThisConversionHasImplicit) {
1162 // If the so far best selected conversion needs a previous implicit
1163 // conversion to match the user-defined converting function, but this
1164 // conversion does not, this is a better conversion, and we can throw
1165 // away the previously selected conversion(s).
1166 BestConversion = Prepared;
1167 HowManyGoodConversions = 1;
1168 continue;
1169 }
1170
1171 if (BestConversionHasImplicit == ThisConversionHasImplicit)
1172 // The current conversion is the same in term of goodness than the
1173 // already selected one.
1174 ++HowManyGoodConversions;
1175 }
1176
1177 if (HowManyGoodConversions == 1) {
1178 LLVM_DEBUG(llvm::dbgs()
1179 << "--- selectUserDefinedConv. Unique result. Flags: "
1180 << formatMixFlags(BestConversion->Flags) << '\n');
1181 return BestConversion;
1182 }
1183
1184 LLVM_DEBUG(llvm::dbgs()
1185 << "--- selectUserDefinedConv. No, or ambiguous.\n");
1186 return {};
1187 }
1188
1189private:
1190 llvm::SmallVector<PreparedConversion, 2> FlaggedConversions;
1191 const TheCheck &Check;
1192};
1193
1194} // namespace
1195
1196static std::optional<ConversionSequence>
1197tryConversionOperators(const TheCheck &Check, const CXXRecordDecl *RD,
1198 QualType ToType) {
1199 if (!RD || !RD->isCompleteDefinition())
1200 return {};
1201 RD = RD->getDefinition();
1202
1203 LLVM_DEBUG(llvm::dbgs() << ">>> tryConversionOperators: " << RD->getName()
1204 << " to:\n";
1205 ToType.dump(llvm::dbgs(), RD->getASTContext());
1206 llvm::dbgs() << '\n';);
1207
1208 UserDefinedConversionSelector ConversionSet{Check};
1209
1210 for (const NamedDecl *Method : RD->getVisibleConversionFunctions()) {
1211 const auto *Con = dyn_cast<CXXConversionDecl>(Method);
1212 if (!Con || Con->isExplicit())
1213 continue;
1214 LLVM_DEBUG(llvm::dbgs() << "--- tryConversionOperators. Trying:\n";
1215 Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';);
1216
1217 // Try to go from the result of conversion operator to the expected type,
1218 // without calculating another user-defined conversion.
1219 ConversionSet.addConversion(Con, Con->getConversionType(), ToType);
1220 }
1221
1222 if (std::optional<UserDefinedConversionSelector::PreparedConversion>
1223 SelectedConversion = ConversionSet()) {
1224 const CanQualType RecordType = RD->getASTContext().getCanonicalTagType(RD);
1225
1226 ConversionSequence Result{RecordType, ToType};
1227 // The conversion from the operator call's return type to ToType was
1228 // modelled as a "pre-conversion" in the operator call, but it is the
1229 // "post-conversion" from the point of view of the original conversion
1230 // we are modelling.
1231 Result.AfterSecondStandard = SelectedConversion->Seq.AfterFirstStandard;
1232
1234 ConvOp.Fun = cast<CXXConversionDecl>(SelectedConversion->ConversionFun);
1235 ConvOp.UserDefinedType = RecordType;
1236 ConvOp.ConversionOperatorResultType = ConvOp.Fun->getConversionType();
1237 Result.setConversion(ConvOp);
1238
1239 LLVM_DEBUG(llvm::dbgs() << "<<< tryConversionOperators. Found result.\n");
1240 return Result;
1241 }
1242
1243 LLVM_DEBUG(llvm::dbgs() << "<<< tryConversionOperators. No conversion.\n");
1244 return {};
1245}
1246
1247static std::optional<ConversionSequence>
1248tryConvertingConstructors(const TheCheck &Check, QualType FromType,
1249 const CXXRecordDecl *RD) {
1250 if (!RD || !RD->isCompleteDefinition())
1251 return {};
1252 RD = RD->getDefinition();
1253
1254 LLVM_DEBUG(llvm::dbgs() << ">>> tryConveringConstructors: " << RD->getName()
1255 << " from:\n";
1256 FromType.dump(llvm::dbgs(), RD->getASTContext());
1257 llvm::dbgs() << '\n';);
1258
1259 UserDefinedConversionSelector ConversionSet{Check};
1260
1261 for (const CXXConstructorDecl *Con : RD->ctors()) {
1262 if (Con->isCopyOrMoveConstructor() ||
1263 !Con->isConvertingConstructor(/* AllowExplicit =*/false))
1264 continue;
1265 LLVM_DEBUG(llvm::dbgs() << "--- tryConvertingConstructors. Trying:\n";
1266 Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';);
1267
1268 // Try to go from the original FromType to the converting constructor's
1269 // parameter type without another user-defined conversion.
1270 ConversionSet.addConversion(Con, FromType, Con->getParamDecl(0)->getType());
1271 }
1272
1273 if (std::optional<UserDefinedConversionSelector::PreparedConversion>
1274 SelectedConversion = ConversionSet()) {
1275 const CanQualType RecordType = RD->getASTContext().getCanonicalTagType(RD);
1276
1277 ConversionSequence Result{FromType, RecordType};
1278 Result.AfterFirstStandard = SelectedConversion->Seq.AfterFirstStandard;
1279
1281 Ctor.Fun = cast<CXXConstructorDecl>(SelectedConversion->ConversionFun);
1282 Ctor.ConstructorParameterType = Ctor.Fun->getParamDecl(0)->getType();
1283 Ctor.UserDefinedType = RecordType;
1284 Result.setConversion(Ctor);
1285
1286 LLVM_DEBUG(llvm::dbgs()
1287 << "<<< tryConvertingConstructors. Found result.\n");
1288 return Result;
1289 }
1290
1291 LLVM_DEBUG(llvm::dbgs() << "<<< tryConvertingConstructors. No conversion.\n");
1292 return {};
1293}
1294
1295/// Returns whether an expression of LType can be used in an RType context, as
1296/// per the implicit conversion rules.
1297///
1298/// Note: the result of this operation, unlike that of calculateMixability, is
1299/// **NOT** symmetric.
1300static MixData
1301approximateImplicitConversion(const TheCheck &Check, QualType LType,
1302 QualType RType, const ASTContext &Ctx,
1303 ImplicitConversionModellingMode ImplicitMode) {
1304 LLVM_DEBUG(llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n";
1305 LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";
1306 RType.dump(llvm::dbgs(), Ctx);
1307 llvm::dbgs() << "\nimplicit mode: "; switch (ImplicitMode) {
1309 llvm::dbgs() << "None";
1310 break;
1312 llvm::dbgs() << "All";
1313 break;
1315 llvm::dbgs() << "OneWay, Single, STD Only";
1316 break;
1317 } llvm::dbgs() << '\n';);
1318 if (LType == RType)
1319 return {MixFlags::Trivial, LType};
1320
1321 // An implicit conversion sequence consists of the following, in order:
1322 // * Maybe standard conversion sequence.
1323 // * Maybe user-defined conversion.
1324 // * Maybe standard conversion sequence.
1325 ConversionSequence ImplicitSeq{LType, RType};
1326 QualType WorkType = LType;
1327
1328 std::optional<QualType> AfterFirstStdConv =
1329 approximateStandardConversionSequence(Check, LType, RType, Ctx);
1330 if (AfterFirstStdConv) {
1331 LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Standard "
1332 "Pre-Conversion found!\n");
1333 ImplicitSeq.AfterFirstStandard = *AfterFirstStdConv;
1334 WorkType = ImplicitSeq.AfterFirstStandard;
1335 }
1336
1338 // If the caller only requested modelling of a standard conversion, bail.
1339 return {ImplicitSeq.AfterFirstStandard.isNull()
1342 ImplicitSeq};
1343
1344 if (Ctx.getLangOpts().CPlusPlus) {
1345 bool FoundConversionOperator = false, FoundConvertingCtor = false;
1346
1347 if (const auto *LRD = WorkType->getAsCXXRecordDecl()) {
1348 std::optional<ConversionSequence> ConversionOperatorResult =
1349 tryConversionOperators(Check, LRD, RType);
1350 if (ConversionOperatorResult) {
1351 LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Found "
1352 "conversion operator.\n");
1353 ImplicitSeq.update(*ConversionOperatorResult);
1354 WorkType = ImplicitSeq.getTypeAfterUserDefinedConversion();
1355 FoundConversionOperator = true;
1356 }
1357 }
1358
1359 if (const auto *RRD = RType->getAsCXXRecordDecl()) {
1360 // Use the original "LType" here, and not WorkType, because the
1361 // conversion to the converting constructors' parameters will be
1362 // modelled in the recursive call.
1363 std::optional<ConversionSequence> ConvCtorResult =
1364 tryConvertingConstructors(Check, LType, RRD);
1365 if (ConvCtorResult) {
1366 LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Found "
1367 "converting constructor.\n");
1368 ImplicitSeq.update(*ConvCtorResult);
1369 WorkType = ImplicitSeq.getTypeAfterUserDefinedConversion();
1370 FoundConvertingCtor = true;
1371 }
1372 }
1373
1374 if (FoundConversionOperator && FoundConvertingCtor) {
1375 // If both an operator and a ctor matches, the sequence is ambiguous.
1376 LLVM_DEBUG(llvm::dbgs()
1377 << "<<< approximateImplicitConversion. Found both "
1378 "user-defined conversion kinds in the same sequence!\n");
1379 return {MixFlags::None};
1380 }
1381 }
1382
1383 // After the potential user-defined conversion, another standard conversion
1384 // sequence might exist.
1385 LLVM_DEBUG(
1386 llvm::dbgs()
1387 << "--- approximateImplicitConversion. Try to find post-conversion.\n");
1388 const MixData SecondStdConv = approximateImplicitConversion(
1389 Check, WorkType, RType, Ctx,
1391 if (SecondStdConv.indicatesMixability()) {
1392 LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Standard "
1393 "Post-Conversion found!\n");
1394
1395 // The single-step modelling puts the modelled conversion into the "PreStd"
1396 // variable in the recursive call, but from the PoV of this function, it is
1397 // the post-conversion.
1398 ImplicitSeq.AfterSecondStandard =
1399 SecondStdConv.Conversion.AfterFirstStandard;
1400 WorkType = ImplicitSeq.AfterSecondStandard;
1401 }
1402
1403 if (ImplicitSeq) {
1404 LLVM_DEBUG(llvm::dbgs()
1405 << "<<< approximateImplicitConversion. Found a conversion.\n");
1406 return {MixFlags::ImplicitConversion, ImplicitSeq};
1407 }
1408
1409 LLVM_DEBUG(
1410 llvm::dbgs() << "<<< approximateImplicitConversion. No match found.\n");
1411 return {MixFlags::None};
1412}
1413
1415 const TheCheck &Check, const FunctionDecl *FD, std::size_t StartIndex,
1416 const filter::SimilarlyUsedParameterPairSuppressor &UsageBasedSuppressor) {
1417 const std::size_t NumParams = FD->getNumParams();
1418 assert(StartIndex < NumParams && "out of bounds for start");
1419 const ASTContext &Ctx = FD->getASTContext();
1420
1422 // A parameter at index 'StartIndex' had been trivially "checked".
1423 Ret.NumParamsChecked = 1;
1424
1425 for (std::size_t I = StartIndex + 1; I < NumParams; ++I) {
1426 const ParmVarDecl *Ith = FD->getParamDecl(I);
1427 const StringRef ParamName = Ith->getName();
1428 LLVM_DEBUG(llvm::dbgs()
1429 << "Check param #" << I << " '" << ParamName << "'...\n");
1430 if (filter::isIgnoredParameter(Check, Ith)) {
1431 LLVM_DEBUG(llvm::dbgs() << "Param #" << I << " is ignored. Break!\n");
1432 break;
1433 }
1434
1435 const StringRef PrevParamName = FD->getParamDecl(I - 1)->getName();
1436 if (!ParamName.empty() && !PrevParamName.empty() &&
1439 ParamName)) {
1440 LLVM_DEBUG(llvm::dbgs() << "Parameter '" << ParamName
1441 << "' follows a pattern with previous parameter '"
1442 << PrevParamName << "'. Break!\n");
1443 break;
1444 }
1445
1446 // Now try to go forward and build the range of [Start, ..., I, I + 1, ...]
1447 // parameters that can be messed up at a call site.
1449 for (std::size_t J = StartIndex; J < I; ++J) {
1450 const ParmVarDecl *Jth = FD->getParamDecl(J);
1451 LLVM_DEBUG(llvm::dbgs()
1452 << "Check mix of #" << J << " against #" << I << "...\n");
1453
1454 if (isSimilarlyUsedParameter(UsageBasedSuppressor, Ith, Jth)) {
1455 // Consider the two similarly used parameters to not be possible in a
1456 // mix-up at the user's request, if they enabled this heuristic.
1457 LLVM_DEBUG(llvm::dbgs() << "Parameters #" << I << " and #" << J
1458 << " deemed related, ignoring...\n");
1459
1460 // If the parameter #I and #J mixes, then I is mixable with something
1461 // in the current range, so the range has to be broken and I not
1462 // included.
1463 MixesOfIth.clear();
1464 break;
1465 }
1466
1467 Mix M{Jth, Ith,
1468 calculateMixability(Check, Jth->getType(), Ith->getType(), Ctx,
1472 LLVM_DEBUG(llvm::dbgs() << "Mix flags (raw) : "
1473 << formatMixFlags(M.flags()) << '\n');
1474 M.sanitize();
1475 LLVM_DEBUG(llvm::dbgs() << "Mix flags (after sanitize): "
1476 << formatMixFlags(M.flags()) << '\n');
1477
1478 assert(M.flagsValid() && "All flags decayed!");
1479
1480 if (M.mixable())
1481 MixesOfIth.emplace_back(std::move(M));
1482 }
1483
1484 if (MixesOfIth.empty()) {
1485 // If there weren't any new mixes stored for Ith, the range is
1486 // [Start, ..., I].
1487 LLVM_DEBUG(llvm::dbgs()
1488 << "Param #" << I
1489 << " does not mix with any in the current range. Break!\n");
1490 break;
1491 }
1492
1493 Ret.Mixes.insert(Ret.Mixes.end(), MixesOfIth.begin(), MixesOfIth.end());
1494 ++Ret.NumParamsChecked; // Otherwise a new param was iterated.
1495 }
1496
1497 return Ret;
1498}
1499
1500} // namespace model
1501
1502namespace {
1503/// Matches DeclRefExprs and their ignorable wrappers to ParmVarDecls.
1504AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<Stmt>, paramRefExpr) {
1505 return expr(ignoringParenImpCasts(ignoringElidableConstructorCall(
1506 declRefExpr(to(parmVarDecl().bind("param"))))));
1507}
1508} // namespace
1509
1510namespace filter {
1511
1512/// Returns whether the parameter's name or the parameter's type's name is
1513/// configured by the user to be ignored from analysis and diagnostic.
1514static bool isIgnoredParameter(const TheCheck &Check, const ParmVarDecl *Node) {
1515 LLVM_DEBUG(llvm::dbgs() << "Checking if '" << Node->getName()
1516 << "' is ignored.\n");
1517
1518 if (!Node->getIdentifier())
1519 return llvm::is_contained(Check.IgnoredParameterNames, "\"\"");
1520
1521 const StringRef NodeName = Node->getName();
1522 if (llvm::is_contained(Check.IgnoredParameterNames, NodeName)) {
1523 LLVM_DEBUG(llvm::dbgs() << "\tName ignored.\n");
1524 return true;
1525 }
1526
1527 const StringRef NodeTypeName = [Node] {
1528 const ASTContext &Ctx = Node->getASTContext();
1529 const SourceManager &SM = Ctx.getSourceManager();
1530 SourceLocation B = Node->getTypeSpecStartLoc();
1531 SourceLocation E = Node->getTypeSpecEndLoc();
1532 const LangOptions LO;
1533
1534 LLVM_DEBUG(llvm::dbgs() << "\tType name code is '"
1535 << Lexer::getSourceText(
1536 CharSourceRange::getTokenRange(B, E), SM, LO)
1537 << "'...\n");
1538 if (B.isMacroID()) {
1539 LLVM_DEBUG(llvm::dbgs() << "\t\tBeginning is macro.\n");
1540 B = SM.getTopMacroCallerLoc(B);
1541 }
1542 if (E.isMacroID()) {
1543 LLVM_DEBUG(llvm::dbgs() << "\t\tEnding is macro.\n");
1544 E = Lexer::getLocForEndOfToken(SM.getTopMacroCallerLoc(E), 0, SM, LO);
1545 }
1546 LLVM_DEBUG(llvm::dbgs() << "\tType name code is '"
1547 << Lexer::getSourceText(
1548 CharSourceRange::getTokenRange(B, E), SM, LO)
1549 << "'...\n");
1550
1551 return Lexer::getSourceText(CharSourceRange::getTokenRange(B, E), SM, LO);
1552 }();
1553
1554 LLVM_DEBUG(llvm::dbgs() << "\tType name is '" << NodeTypeName << "'\n");
1555 if (!NodeTypeName.empty()) {
1556 if (llvm::any_of(Check.IgnoredParameterTypeSuffixes,
1557 [NodeTypeName](StringRef E) {
1558 return !E.empty() && NodeTypeName.ends_with(E);
1559 })) {
1560 LLVM_DEBUG(llvm::dbgs() << "\tType suffix ignored.\n");
1561 return true;
1562 }
1563 }
1564
1565 return false;
1566}
1567
1568/// This namespace contains the implementations for the suppression of
1569/// diagnostics from similarly-used ("related") parameters.
1571
1572static constexpr std::size_t SmallDataStructureSize = 4;
1573
1574template <typename T, std::size_t N = SmallDataStructureSize>
1576 llvm::DenseMap<const ParmVarDecl *, llvm::SmallSet<T, N>>;
1577
1578template <typename T, std::size_t N = SmallDataStructureSize>
1580 llvm::DenseMap<const ParmVarDecl *, llvm::SmallPtrSet<T, N>>;
1581
1582/// Returns whether the sets mapped to the two elements in the map have at
1583/// least one element in common.
1584template <typename MapTy, typename ElemTy>
1585static bool lazyMapOfSetsIntersectionExists(const MapTy &Map, const ElemTy &E1,
1586 const ElemTy &E2) {
1587 auto E1Iterator = Map.find(E1);
1588 auto E2Iterator = Map.find(E2);
1589 if (E1Iterator == Map.end() || E2Iterator == Map.end())
1590 return false;
1591
1592 return llvm::any_of(E1Iterator->second, [&E2Iterator](const auto &E1SetElem) {
1593 return E2Iterator->second.contains(E1SetElem);
1594 });
1595}
1596
1597/// Implements the heuristic that marks two parameters related if there is
1598/// a usage for both in the same strict expression subtree. A strict
1599/// expression subtree is a tree which only includes Expr nodes, i.e. no
1600/// Stmts and no Decls.
1601class AppearsInSameExpr : public RecursiveASTVisitor<AppearsInSameExpr> {
1602 using Base = RecursiveASTVisitor<AppearsInSameExpr>;
1603
1604 const FunctionDecl *FD;
1605 const Expr *CurrentExprOnlyTreeRoot = nullptr;
1606 llvm::DenseMap<const ParmVarDecl *,
1607 llvm::SmallPtrSet<const Expr *, SmallDataStructureSize>>
1608 ParentExprsForParamRefs;
1609
1610public:
1611 void setup(const FunctionDecl *FD) {
1612 this->FD = FD;
1613 TraverseFunctionDecl(const_cast<FunctionDecl *>(FD));
1614 }
1615
1616 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1617 return lazyMapOfSetsIntersectionExists(ParentExprsForParamRefs, Param1,
1618 Param2);
1619 }
1620
1621 bool TraverseDecl(Decl *D) {
1622 CurrentExprOnlyTreeRoot = nullptr;
1623 return Base::TraverseDecl(D);
1624 }
1625
1626 bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue = nullptr) {
1627 if (auto *E = dyn_cast_or_null<Expr>(S)) {
1628 bool RootSetInCurrentStackFrame = false;
1629 if (!CurrentExprOnlyTreeRoot) {
1630 CurrentExprOnlyTreeRoot = E;
1631 RootSetInCurrentStackFrame = true;
1632 }
1633
1634 const bool Ret = Base::TraverseStmt(S);
1635
1636 if (RootSetInCurrentStackFrame)
1637 CurrentExprOnlyTreeRoot = nullptr;
1638
1639 return Ret;
1640 }
1641
1642 // A Stmt breaks the strictly Expr subtree.
1643 CurrentExprOnlyTreeRoot = nullptr;
1644 return Base::TraverseStmt(S);
1645 }
1646
1647 bool VisitDeclRefExpr(DeclRefExpr *DRE) {
1648 if (!CurrentExprOnlyTreeRoot)
1649 return true;
1650
1651 if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
1652 if (llvm::find(FD->parameters(), PVD))
1653 ParentExprsForParamRefs[PVD].insert(CurrentExprOnlyTreeRoot);
1654
1655 return true;
1656 }
1657};
1658
1659/// Implements the heuristic that marks two parameters related if there are
1660/// two separate calls to the same function (overload) and the parameters are
1661/// passed to the same index in both calls, i.e f(a, b) and f(a, c) passes
1662/// b and c to the same index (2) of f(), marking them related.
1665
1666public:
1667 void setup(const FunctionDecl *FD) {
1668 auto ParamsAsArgsInFnCalls =
1669 match(functionDecl(forEachDescendant(
1670 callExpr(forEachArgumentWithParam(
1671 paramRefExpr(), parmVarDecl().bind("passed-to")))
1672 .bind("call-expr"))),
1673 *FD, FD->getASTContext());
1674 for (const auto &Match : ParamsAsArgsInFnCalls) {
1675 const auto *PassedParamOfThisFn = Match.getNodeAs<ParmVarDecl>("param");
1676 const auto *CE = Match.getNodeAs<CallExpr>("call-expr");
1677 const auto *PassedToParam = Match.getNodeAs<ParmVarDecl>("passed-to");
1678 assert(PassedParamOfThisFn && CE && PassedToParam);
1679
1680 const FunctionDecl *CalledFn = CE->getDirectCallee();
1681 if (!CalledFn)
1682 continue;
1683
1684 std::optional<unsigned> TargetIdx;
1685 const unsigned NumFnParams = CalledFn->getNumParams();
1686 for (unsigned Idx = 0; Idx < NumFnParams; ++Idx)
1687 if (CalledFn->getParamDecl(Idx) == PassedToParam)
1688 TargetIdx.emplace(Idx);
1689
1690 assert(TargetIdx && "Matched, but didn't find index?");
1691 TargetParams[PassedParamOfThisFn].insert(
1692 {CalledFn->getCanonicalDecl(), *TargetIdx});
1693 }
1694 }
1695
1696 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1697 return lazyMapOfSetsIntersectionExists(TargetParams, Param1, Param2);
1698 }
1699};
1700
1701/// Implements the heuristic that marks two parameters related if the same
1702/// member is accessed (referred to) inside the current function's body.
1705
1706public:
1707 void setup(const FunctionDecl *FD) {
1708 auto MembersCalledOnParams = match(
1709 functionDecl(forEachDescendant(
1710 memberExpr(hasObjectExpression(paramRefExpr())).bind("mem-expr"))),
1711 *FD, FD->getASTContext());
1712
1713 for (const auto &Match : MembersCalledOnParams) {
1714 const auto *AccessedParam = Match.getNodeAs<ParmVarDecl>("param");
1715 const auto *ME = Match.getNodeAs<MemberExpr>("mem-expr");
1716 assert(AccessedParam && ME);
1717 AccessedMembers[AccessedParam].insert(
1718 ME->getMemberDecl()->getCanonicalDecl());
1719 }
1720 }
1721
1722 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1723 return lazyMapOfSetsIntersectionExists(AccessedMembers, Param1, Param2);
1724 }
1725};
1726
1727/// Implements the heuristic that marks two parameters related if different
1728/// ReturnStmts return them from the function.
1730 llvm::SmallVector<const ParmVarDecl *, SmallDataStructureSize> ReturnedParams;
1731
1732public:
1733 void setup(const FunctionDecl *FD) {
1734 // TODO: Handle co_return.
1735 auto ParamReturns = match(functionDecl(forEachDescendant(
1736 returnStmt(hasReturnValue(paramRefExpr())))),
1737 *FD, FD->getASTContext());
1738 for (const auto &Match : ParamReturns) {
1739 const auto *ReturnedParam = Match.getNodeAs<ParmVarDecl>("param");
1740 assert(ReturnedParam);
1741
1742 if (find(FD->parameters(), ReturnedParam) == FD->param_end())
1743 // Inside the subtree of a FunctionDecl there might be ReturnStmts of
1744 // a parameter that isn't the parameter of the function, e.g. in the
1745 // case of lambdas.
1746 continue;
1747
1748 ReturnedParams.emplace_back(ReturnedParam);
1749 }
1750 }
1751
1752 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1753 return llvm::is_contained(ReturnedParams, Param1) &&
1754 llvm::is_contained(ReturnedParams, Param2);
1755 }
1756};
1757
1758} // namespace relatedness_heuristic
1759
1760/// Helper class that is used to detect if two parameters of the same function
1761/// are used in a similar fashion, to suppress the result.
1763 const bool Enabled;
1768
1769public:
1770 SimilarlyUsedParameterPairSuppressor(const FunctionDecl *FD, bool Enable)
1771 : Enabled(Enable) {
1772 if (!Enable)
1773 return;
1774
1775 SameExpr.setup(FD);
1776 PassToFun.setup(FD);
1777 SameMember.setup(FD);
1778 Returns.setup(FD);
1779 }
1780
1781 /// Returns whether the specified two parameters are deemed similarly used
1782 /// or related by the heuristics.
1783 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1784 if (!Enabled)
1785 return false;
1786
1787 LLVM_DEBUG(llvm::dbgs()
1788 << "::: Matching similar usage / relatedness heuristic...\n");
1789
1790 if (SameExpr(Param1, Param2)) {
1791 LLVM_DEBUG(llvm::dbgs() << "::: Used in the same expression.\n");
1792 return true;
1793 }
1794
1795 if (PassToFun(Param1, Param2)) {
1796 LLVM_DEBUG(llvm::dbgs()
1797 << "::: Passed to same function in different calls.\n");
1798 return true;
1799 }
1800
1801 if (SameMember(Param1, Param2)) {
1802 LLVM_DEBUG(llvm::dbgs()
1803 << "::: Same member field access or method called.\n");
1804 return true;
1805 }
1806
1807 if (Returns(Param1, Param2)) {
1808 LLVM_DEBUG(llvm::dbgs() << "::: Both parameter returned.\n");
1809 return true;
1810 }
1811
1812 LLVM_DEBUG(llvm::dbgs() << "::: None.\n");
1813 return false;
1814 }
1815};
1816
1817// (This function hoists the call to operator() of the wrapper, so we do not
1818// need to define the previous class at the top of the file.)
1819static inline bool
1821 const ParmVarDecl *Param1, const ParmVarDecl *Param2) {
1822 return Suppressor(Param1, Param2);
1823}
1824
1825static void padStringAtEnd(SmallVectorImpl<char> &Str, std::size_t ToLen) {
1826 while (Str.size() < ToLen)
1827 Str.emplace_back('\0');
1828}
1829
1830static void padStringAtBegin(SmallVectorImpl<char> &Str, std::size_t ToLen) {
1831 while (Str.size() < ToLen)
1832 Str.insert(Str.begin(), '\0');
1833}
1834
1835static bool isCommonPrefixWithoutSomeCharacters(std::size_t N, StringRef S1,
1836 StringRef S2) {
1837 assert(S1.size() >= N && S2.size() >= N);
1838 const StringRef S1Prefix = S1.take_front(S1.size() - N),
1839 S2Prefix = S2.take_front(S2.size() - N);
1840 return S1Prefix == S2Prefix && !S1Prefix.empty();
1841}
1842
1843static bool isCommonSuffixWithoutSomeCharacters(std::size_t N, StringRef S1,
1844 StringRef S2) {
1845 assert(S1.size() >= N && S2.size() >= N);
1846 const StringRef S1Suffix = S1.take_back(S1.size() - N),
1847 S2Suffix = S2.take_back(S2.size() - N);
1848 return S1Suffix == S2Suffix && !S1Suffix.empty();
1849}
1850
1851/// Returns whether the two strings are prefixes or suffixes of each other with
1852/// at most Threshold characters differing on the non-common end.
1853static bool prefixSuffixCoverUnderThreshold(std::size_t Threshold,
1854 StringRef Str1, StringRef Str2) {
1855 if (Threshold == 0)
1856 return false;
1857
1858 // Pad the two strings to the longer length.
1859 const std::size_t BiggerLength = std::max(Str1.size(), Str2.size());
1860
1861 if (BiggerLength <= Threshold)
1862 // If the length of the strings is still smaller than the threshold, they
1863 // would be covered by an empty prefix/suffix with the rest differing.
1864 // (E.g. "A" and "X" with Threshold = 1 would mean we think they are
1865 // similar and do not warn about them, which is a too eager assumption.)
1866 return false;
1867
1868 SmallString<32> S1PadE{Str1}, S2PadE{Str2};
1869 padStringAtEnd(S1PadE, BiggerLength);
1870 padStringAtEnd(S2PadE, BiggerLength);
1871
1873 Threshold, StringRef{S1PadE.begin(), BiggerLength},
1874 StringRef{S2PadE.begin(), BiggerLength}))
1875 return true;
1876
1877 SmallString<32> S1PadB{Str1}, S2PadB{Str2};
1878 padStringAtBegin(S1PadB, BiggerLength);
1879 padStringAtBegin(S2PadB, BiggerLength);
1880
1882 Threshold, StringRef{S1PadB.begin(), BiggerLength},
1883 StringRef{S2PadB.begin(), BiggerLength}))
1884 return true;
1885
1886 return false;
1887}
1888
1889} // namespace filter
1890
1891namespace {
1892
1893/// Matches functions that have at least the specified amount of parameters.
1894AST_MATCHER_P(FunctionDecl, parameterCountGE, unsigned, N) {
1895 return Node.getNumParams() >= N;
1896}
1897
1898/// Matches *any* overloaded unary and binary operators.
1899AST_MATCHER(FunctionDecl, isOverloadedUnaryOrBinaryOperator) {
1900 switch (Node.getOverloadedOperator()) {
1901 case OO_None:
1902 case OO_New:
1903 case OO_Delete:
1904 case OO_Array_New:
1905 case OO_Array_Delete:
1906 case OO_Conditional:
1907 case OO_Coawait:
1908 return false;
1909
1910 default:
1911 return Node.getNumParams() <= 2;
1912 }
1913}
1914
1915} // namespace
1916
1917/// Returns the DefaultMinimumLength if the Value of requested minimum length
1918/// is less than 2. Minimum lengths of 0 or 1 are not accepted.
1919static inline unsigned clampMinimumLength(const unsigned Value) {
1920 return Value < 2 ? DefaultMinimumLength : Value;
1921}
1922
1923// FIXME: Maybe unneeded, getNameForDiagnostic() is expected to change to return
1924// a crafted location when the node itself is unnamed. (See D84658, D85033.)
1925/// Returns the diagnostic-friendly name of the node, or empty string.
1926static SmallString<64> getName(const NamedDecl *ND) {
1927 SmallString<64> Name;
1928 llvm::raw_svector_ostream OS{Name};
1929 ND->getNameForDiagnostic(OS, ND->getASTContext().getPrintingPolicy(), false);
1930 return Name;
1931}
1932
1933/// Returns the diagnostic-friendly name of the node, or a constant value.
1934static SmallString<64> getNameOrUnnamed(const NamedDecl *ND) {
1935 auto Name = getName(ND);
1936 if (Name.empty())
1937 Name = "<unnamed>";
1938 return Name;
1939}
1940
1941/// Returns whether a particular Mix between two parameters should have the
1942/// types involved diagnosed to the user. This is only a flag check.
1943static inline bool needsToPrintTypeInDiagnostic(const model::Mix &M) {
1944 using namespace model;
1945 return static_cast<bool>(
1946 M.flags() &
1947 (MixFlags::TypeAlias | MixFlags::ReferenceBind | MixFlags::Qualifiers));
1948}
1949
1950/// Returns whether a particular Mix between the two parameters should have
1951/// implicit conversions elaborated.
1953 return hasFlag(M.flags(), model::MixFlags::ImplicitConversion);
1954}
1955
1956namespace {
1957
1958/// This class formats a conversion sequence into a "Ty1 -> Ty2 -> Ty3" line
1959/// that can be used in diagnostics.
1960struct FormattedConversionSequence {
1961 std::string DiagnosticText;
1962
1963 /// The formatted sequence is trivial if it is "Ty1 -> Ty2", but Ty1 and
1964 /// Ty2 are the types that are shown in the code. A trivial diagnostic
1965 /// does not need to be printed.
1966 bool Trivial = true;
1967
1968 FormattedConversionSequence(const PrintingPolicy &PP,
1969 StringRef StartTypeAsDiagnosed,
1970 const model::ConversionSequence &Conv,
1971 StringRef DestinationTypeAsDiagnosed) {
1972 llvm::raw_string_ostream OS{DiagnosticText};
1973
1974 // Print the type name as it is printed in other places in the diagnostic.
1975 OS << '\'' << StartTypeAsDiagnosed << '\'';
1976 std::string LastAddedType = StartTypeAsDiagnosed.str();
1977 std::size_t NumElementsAdded = 1;
1978
1979 // However, the parameter's defined type might not be what the implicit
1980 // conversion started with, e.g. if a typedef is found to convert.
1981 const std::string SeqBeginTypeStr = Conv.Begin.getAsString(PP);
1982 std::string SeqEndTypeStr = Conv.End.getAsString(PP);
1983 if (StartTypeAsDiagnosed != SeqBeginTypeStr) {
1984 OS << " (as '" << SeqBeginTypeStr << "')";
1985 LastAddedType = SeqBeginTypeStr;
1986 Trivial = false;
1987 }
1988
1989 auto AddType = [&](StringRef ToAdd) {
1990 if (LastAddedType != ToAdd && ToAdd != SeqEndTypeStr) {
1991 OS << " -> '" << ToAdd << "'";
1992 LastAddedType = ToAdd.str();
1993 ++NumElementsAdded;
1994 }
1995 };
1996 for (const QualType InvolvedType : Conv.getInvolvedTypesInSequence())
1997 // Print every type that's unique in the sequence into the diagnosis.
1998 AddType(InvolvedType.getAsString(PP));
1999
2000 if (LastAddedType != DestinationTypeAsDiagnosed) {
2001 OS << " -> '" << DestinationTypeAsDiagnosed << "'";
2002 LastAddedType = DestinationTypeAsDiagnosed.str();
2003 ++NumElementsAdded;
2004 }
2005
2006 // Same reasoning as with the Begin, e.g. if the converted-to type is a
2007 // typedef, it will not be the same inside the conversion sequence (where
2008 // the model already tore off typedefs) as in the code.
2009 if (DestinationTypeAsDiagnosed != SeqEndTypeStr) {
2010 OS << " (as '" << SeqEndTypeStr << "')";
2011 LastAddedType = SeqEndTypeStr;
2012 Trivial = false;
2013 }
2014
2015 if (Trivial && NumElementsAdded > 2)
2016 // If the thing is still marked trivial but we have more than the
2017 // from and to types added, it should not be trivial, and elaborated
2018 // when printing the diagnostic.
2019 Trivial = false;
2020 }
2021};
2022
2023/// Retains the elements called with and returns whether the call is done with
2024/// a new element.
2025template <typename E, std::size_t N> class InsertOnce {
2026 llvm::SmallSet<E, N> CalledWith;
2027
2028public:
2029 bool operator()(E El) { return CalledWith.insert(std::move(El)).second; }
2030
2031 bool calledWith(const E &El) const { return CalledWith.contains(El); }
2032};
2033
2034struct SwappedEqualQualTypePair {
2035 QualType LHSType, RHSType;
2036
2037 bool operator==(const SwappedEqualQualTypePair &Other) const {
2038 return (LHSType == Other.LHSType && RHSType == Other.RHSType) ||
2039 (LHSType == Other.RHSType && RHSType == Other.LHSType);
2040 }
2041
2042 bool operator<(const SwappedEqualQualTypePair &Other) const {
2043 return LHSType < Other.LHSType && RHSType < Other.RHSType;
2044 }
2045};
2046
2047struct TypeAliasDiagnosticTuple {
2048 QualType LHSType, RHSType, CommonType;
2049
2050 bool operator==(const TypeAliasDiagnosticTuple &Other) const {
2051 return CommonType == Other.CommonType &&
2052 ((LHSType == Other.LHSType && RHSType == Other.RHSType) ||
2053 (LHSType == Other.RHSType && RHSType == Other.LHSType));
2054 }
2055
2056 bool operator<(const TypeAliasDiagnosticTuple &Other) const {
2057 return CommonType < Other.CommonType && LHSType < Other.LHSType &&
2058 RHSType < Other.RHSType;
2059 }
2060};
2061
2062/// Helper class to only emit a diagnostic related to MixFlags::TypeAlias once.
2063class UniqueTypeAliasDiagnosticHelper
2064 : public InsertOnce<TypeAliasDiagnosticTuple, 8> {
2065 using Base = InsertOnce<TypeAliasDiagnosticTuple, 8>;
2066
2067public:
2068 /// Returns whether the diagnostic for LHSType and RHSType which are both
2069 /// referring to CommonType being the same has not been emitted already.
2070 bool operator()(QualType LHSType, QualType RHSType, QualType CommonType) {
2071 if (CommonType.isNull() || CommonType == LHSType || CommonType == RHSType)
2072 return Base::operator()({LHSType, RHSType, {}});
2073
2074 const TypeAliasDiagnosticTuple ThreeTuple{LHSType, RHSType, CommonType};
2075 if (!Base::operator()(ThreeTuple))
2076 return false;
2077
2078 const bool AlreadySaidLHSAndCommonIsSame =
2079 calledWith({LHSType, CommonType, {}});
2080 const bool AlreadySaidRHSAndCommonIsSame =
2081 calledWith({RHSType, CommonType, {}});
2082 if (AlreadySaidLHSAndCommonIsSame && AlreadySaidRHSAndCommonIsSame) {
2083 // "SomeInt == int" && "SomeOtherInt == int" => "Common(SomeInt,
2084 // SomeOtherInt) == int", no need to diagnose it. Save the 3-tuple only
2085 // for shortcut if it ever appears again.
2086 return false;
2087 }
2088
2089 return true;
2090 }
2091};
2092
2093} // namespace
2094
2096 StringRef Name, ClangTidyContext *Context)
2097 : ClangTidyCheck(Name, Context),
2099 Options.get("MinimumLength", DefaultMinimumLength))),
2100 IgnoredParameterNames(optutils::parseStringList(
2101 Options.get("IgnoredParameterNames", DefaultIgnoredParameterNames))),
2102 IgnoredParameterTypeSuffixes(optutils::parseStringList(
2103 Options.get("IgnoredParameterTypeSuffixes",
2105 QualifiersMix(Options.get("QualifiersMix", DefaultQualifiersMix)),
2106 ModelImplicitConversions(Options.get("ModelImplicitConversions",
2109 Options.get("SuppressParametersUsedTogether",
2112 Options.get("NamePrefixSuffixSilenceDissimilarityThreshold",
2114
2117 Options.store(Opts, "MinimumLength", MinimumLength);
2118 Options.store(Opts, "IgnoredParameterNames",
2120 Options.store(Opts, "IgnoredParameterTypeSuffixes",
2122 Options.store(Opts, "QualifiersMix", QualifiersMix);
2123 Options.store(Opts, "ModelImplicitConversions", ModelImplicitConversions);
2124 Options.store(Opts, "SuppressParametersUsedTogether",
2126 Options.store(Opts, "NamePrefixSuffixSilenceDissimilarityThreshold",
2128}
2129
2131 const auto BaseConstraints = functionDecl(
2132 // Only report for definition nodes, as fixing the issues reported
2133 // requires the user to be able to change code.
2134 isDefinition(), parameterCountGE(MinimumLength),
2135 unless(isOverloadedUnaryOrBinaryOperator()));
2136
2137 Finder->addMatcher(
2138 functionDecl(BaseConstraints,
2139 unless(ast_matchers::isTemplateInstantiation()))
2140 .bind("func"),
2141 this);
2142 Finder->addMatcher(
2143 functionDecl(BaseConstraints, isExplicitTemplateSpecialization())
2144 .bind("func"),
2145 this);
2146}
2147
2149 const MatchFinder::MatchResult &Result) {
2150 using namespace model;
2151 using namespace filter;
2152
2153 const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("func");
2154 assert(FD);
2155
2156 const PrintingPolicy &PP = FD->getASTContext().getPrintingPolicy();
2157 const std::size_t NumParams = FD->getNumParams();
2158 std::size_t MixableRangeStartIndex = 0;
2159
2160 // Spawn one suppressor and if the user requested, gather information from
2161 // the AST for the parameters' usages.
2162 const filter::SimilarlyUsedParameterPairSuppressor UsageBasedSuppressor{
2164
2165 LLVM_DEBUG(llvm::dbgs() << "Begin analysis of " << getName(FD) << " with "
2166 << NumParams << " parameters...\n");
2167 while (MixableRangeStartIndex < NumParams) {
2168 if (isIgnoredParameter(*this, FD->getParamDecl(MixableRangeStartIndex))) {
2169 LLVM_DEBUG(llvm::dbgs()
2170 << "Parameter #" << MixableRangeStartIndex << " ignored.\n");
2171 ++MixableRangeStartIndex;
2172 continue;
2173 }
2174
2175 MixableParameterRange R = modelMixingRange(
2176 *this, FD, MixableRangeStartIndex, UsageBasedSuppressor);
2177 assert(R.NumParamsChecked > 0 && "Ensure forward progress!");
2178 MixableRangeStartIndex += R.NumParamsChecked;
2179 if (R.NumParamsChecked < MinimumLength) {
2180 LLVM_DEBUG(llvm::dbgs() << "Ignoring range of " << R.NumParamsChecked
2181 << " lower than limit.\n");
2182 continue;
2183 }
2184
2185 const bool NeedsAnyTypeNote =
2186 llvm::any_of(R.Mixes, needsToPrintTypeInDiagnostic);
2187 const bool HasAnyImplicits =
2188 llvm::any_of(R.Mixes, needsToElaborateImplicitConversion);
2189 const ParmVarDecl *First = R.getFirstParam(), *Last = R.getLastParam();
2190 const std::string FirstParamTypeAsWritten =
2191 First->getType().getAsString(PP);
2192 {
2193 StringRef DiagText;
2194
2195 if (HasAnyImplicits)
2196 DiagText = "%0 adjacent parameters of %1 of convertible types are "
2197 "easily swapped by mistake";
2198 else if (NeedsAnyTypeNote)
2199 DiagText = "%0 adjacent parameters of %1 of similar type are easily "
2200 "swapped by mistake";
2201 else
2202 DiagText = "%0 adjacent parameters of %1 of similar type ('%2') are "
2203 "easily swapped by mistake";
2204
2205 auto Diag = diag(First->getOuterLocStart(), DiagText)
2206 << static_cast<unsigned>(R.NumParamsChecked) << FD;
2207 if (!NeedsAnyTypeNote)
2208 Diag << FirstParamTypeAsWritten;
2209
2210 const CharSourceRange HighlightRange = CharSourceRange::getTokenRange(
2211 First->getBeginLoc(), Last->getEndLoc());
2212 Diag << HighlightRange;
2213 }
2214
2215 // There is a chance that the previous highlight did not succeed, e.g. when
2216 // the two parameters are on different lines. For clarity, show the user
2217 // the involved variable explicitly.
2218 diag(First->getLocation(), "the first parameter in the range is '%0'",
2219 DiagnosticIDs::Note)
2220 << getNameOrUnnamed(First)
2221 << CharSourceRange::getTokenRange(First->getLocation(),
2222 First->getLocation());
2223 diag(Last->getLocation(), "the last parameter in the range is '%0'",
2224 DiagnosticIDs::Note)
2225 << getNameOrUnnamed(Last)
2226 << CharSourceRange::getTokenRange(Last->getLocation(),
2227 Last->getLocation());
2228
2229 // Helper classes to silence elaborative diagnostic notes that would be
2230 // too verbose.
2231 UniqueTypeAliasDiagnosticHelper UniqueTypeAlias;
2232 InsertOnce<SwappedEqualQualTypePair, 8> UniqueBindPower;
2233 InsertOnce<SwappedEqualQualTypePair, 8> UniqueImplicitConversion;
2234
2235 for (const model::Mix &M : R.Mixes) {
2236 assert(M.mixable() && "Sentinel or false mix in result.");
2239 continue;
2240
2241 // Typedefs might result in the type of the variable needing to be
2242 // emitted to a note diagnostic, so prepare it.
2243 const ParmVarDecl *LVar = M.First;
2244 const ParmVarDecl *RVar = M.Second;
2245 const QualType LType = LVar->getType();
2246 const QualType RType = RVar->getType();
2247 const QualType CommonType = M.commonUnderlyingType();
2248 const std::string LTypeStr = LType.getAsString(PP);
2249 const std::string RTypeStr = RType.getAsString(PP);
2250 const std::string CommonTypeStr = CommonType.getAsString(PP);
2251
2252 if (hasFlag(M.flags(), MixFlags::TypeAlias) &&
2253 UniqueTypeAlias(LType, RType, CommonType)) {
2254 StringRef DiagText;
2255 bool ExplicitlyPrintCommonType = false;
2256 if (LTypeStr == CommonTypeStr || RTypeStr == CommonTypeStr) {
2257 if (hasFlag(M.flags(), MixFlags::Qualifiers))
2258 DiagText = "after resolving type aliases, '%0' and '%1' share a "
2259 "common type";
2260 else
2261 DiagText =
2262 "after resolving type aliases, '%0' and '%1' are the same";
2263 } else if (!CommonType.isNull()) {
2264 DiagText = "after resolving type aliases, the common type of '%0' "
2265 "and '%1' is '%2'";
2266 ExplicitlyPrintCommonType = true;
2267 }
2268
2269 auto Diag =
2270 diag(LVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2271 << LTypeStr << RTypeStr;
2272 if (ExplicitlyPrintCommonType)
2273 Diag << CommonTypeStr;
2274 }
2275
2276 if ((hasFlag(M.flags(), MixFlags::ReferenceBind) ||
2277 hasFlag(M.flags(), MixFlags::Qualifiers)) &&
2278 UniqueBindPower({LType, RType})) {
2279 const StringRef DiagText =
2280 "'%0' and '%1' parameters accept and bind the "
2281 "same kind of values";
2282 diag(RVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2283 << LTypeStr << RTypeStr;
2284 }
2285
2287 UniqueImplicitConversion({LType, RType})) {
2288 const model::ConversionSequence &LTR =
2290 const model::ConversionSequence &RTL =
2292 const FormattedConversionSequence LTRFmt{PP, LTypeStr, LTR, RTypeStr};
2293 const FormattedConversionSequence RTLFmt{PP, RTypeStr, RTL, LTypeStr};
2294
2295 StringRef DiagText = "'%0' and '%1' may be implicitly converted";
2296 if (!LTRFmt.Trivial || !RTLFmt.Trivial)
2297 DiagText = "'%0' and '%1' may be implicitly converted: %2, %3";
2298
2299 {
2300 auto Diag =
2301 diag(RVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2302 << LTypeStr << RTypeStr;
2303
2304 if (!LTRFmt.Trivial || !RTLFmt.Trivial)
2305 Diag << LTRFmt.DiagnosticText << RTLFmt.DiagnosticText;
2306 }
2307
2308 const StringRef ConversionFunctionDiagText =
2309 "the implicit conversion involves the "
2310 "%select{|converting constructor|conversion operator}0 "
2311 "declared here";
2312 if (const FunctionDecl *LFD = LTR.getUserDefinedConversionFunction())
2313 diag(LFD->getLocation(), ConversionFunctionDiagText,
2314 DiagnosticIDs::Note)
2315 << static_cast<unsigned>(LTR.UDConvKind)
2317 if (const FunctionDecl *RFD = RTL.getUserDefinedConversionFunction())
2318 diag(RFD->getLocation(), ConversionFunctionDiagText,
2319 DiagnosticIDs::Note)
2320 << static_cast<unsigned>(RTL.UDConvKind)
2322 }
2323 }
2324 }
2325}
2326
2327} // namespace clang::tidy::bugprone
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.
static constexpr bool DefaultQualifiersMix
The default value for the QualifiersMix check option.
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.
static constexpr llvm::StringLiteral DefaultIgnoredParameterTypeSuffixes
The default value for ignored parameter type suffixes.
static constexpr std::size_t DefaultNamePrefixSuffixSilenceDissimilarityTreshold
The default value for the NamePrefixSuffixSilenceDissimilarityThreshold check option.
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
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
void registerMatchers(ast_matchers::MatchFinder *Finder) override
const std::vector< StringRef > IgnoredParameterNames
The parameter names (as written in the source text) to be ignored.
const std::size_t NamePrefixSuffixSilenceDissimilarityThreshold
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 Inclusion &LHS, const Inclusion &RHS)
Definition Headers.cpp:356
bool operator<(const Ref &L, const Ref &R)
Definition Ref.h:98
This namespace contains the implementations for the suppression of diagnostics from similarly-used ("...
static 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.
llvm::DenseMap< const ParmVarDecl *, llvm::SmallSet< T, N > > ParamToSmallSetMap
llvm::DenseMap< const ParmVarDecl *, llvm::SmallPtrSet< T, N > > ParamToSmallPtrSetMap
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.
@ 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 thesame" 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.
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.
EasilySwappableParametersCheck TheCheck
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 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)
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.