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 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 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 MixData UnqualifiedMixability =
765 calculateMixability(Check, LType.getLocalUnqualifiedType(),
766 RType.getLocalUnqualifiedType(), Ctx, ImplicitMode)
767 .withCommonTypeTransformed([&AdditionalQuals, &Ctx](QualType QT) {
768 // Once the mixability was deduced, apply the qualifiers common
769 // to the two type back onto the diagnostic printout.
770 return Ctx.getQualifiedType(QT, AdditionalQuals.CommonQualifiers);
771 });
772
773 if (!OriginallySameQualifiers)
774 // User-enabled qualifier change modelled for the mix.
775 return UnqualifiedMixability | MixFlags::Qualifiers;
776
777 // Apply the same qualifier back into the found common type if they were
778 // the same.
779 return UnqualifiedMixability.withCommonTypeTransformed(
780 [&Ctx, LType](QualType QT) {
781 return Ctx.getQualifiedType(QT, LType.getLocalQualifiers());
782 });
783 }
784
785 // Certain constructs match on the last catch-all getCanonicalType() equality,
786 // which is perhaps something not what we want. If this variable is true,
787 // the canonical type equality will be ignored.
788 bool RecursiveReturnDiscardingCanonicalType = false;
789
790 if (LType->isPointerType() && RType->isPointerType()) {
791 // If both types are pointers, and pointed to the exact same type,
792 // LType == RType took care of that. Try to see if the pointee type has
793 // some other match. However, this must not consider implicit conversions.
794 LLVM_DEBUG(llvm::dbgs()
795 << "--- calculateMixability. LHS and RHS are Ptrs.\n");
796 MixData MixOfPointee =
797 calculateMixability(Check, LType->getPointeeType(),
798 RType->getPointeeType(), Ctx,
801 [&Ctx](QualType QT) { return Ctx.getPointerType(QT); });
802 if (hasFlag(MixOfPointee.Flags,
804 RecursiveReturnDiscardingCanonicalType = true;
805
806 MixOfPointee.sanitize();
807 if (MixOfPointee.indicatesMixability()) {
808 LLVM_DEBUG(llvm::dbgs()
809 << "<<< calculateMixability. Pointees are mixable.\n");
810 return MixOfPointee;
811 }
812 }
813
814 if (ImplicitMode > ImplicitConversionModellingMode::None) {
815 LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. Start implicit...\n");
816 MixData MixLTR =
817 approximateImplicitConversion(Check, LType, RType, Ctx, ImplicitMode);
818 LLVM_DEBUG(
819 if (hasFlag(MixLTR.Flags, MixFlags::ImplicitConversion)) llvm::dbgs()
820 << "--- calculateMixability. Implicit Left -> Right found.\n";);
821
822 if (ImplicitMode ==
824 MixLTR.Conversion && !MixLTR.Conversion.AfterFirstStandard.isNull() &&
826 MixLTR.Conversion.AfterSecondStandard.isNull()) {
827 // The invoker of the method requested only modelling a single standard
828 // conversion, in only the forward direction, and they got just that.
829 LLVM_DEBUG(llvm::dbgs() << "<<< calculateMixability. Implicit "
830 "conversion, one-way, standard-only.\n");
832 }
833
834 // Otherwise if the invoker requested a full modelling, do the other
835 // direction as well.
836 MixData MixRTL =
837 approximateImplicitConversion(Check, RType, LType, Ctx, ImplicitMode);
838 LLVM_DEBUG(
839 if (hasFlag(MixRTL.Flags, MixFlags::ImplicitConversion)) llvm::dbgs()
840 << "--- calculateMixability. Implicit Right -> Left found.\n";);
841
842 if (MixLTR.Conversion && MixRTL.Conversion) {
843 LLVM_DEBUG(
844 llvm::dbgs()
845 << "<<< calculateMixability. Implicit conversion, bidirectional.\n");
847 MixRTL.Conversion};
848 }
849 }
850
851 if (RecursiveReturnDiscardingCanonicalType)
852 LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. Before CanonicalType, "
853 "Discard was enabled.\n");
854
855 // Certain kinds unfortunately need to be side-stepped for canonical type
856 // matching.
857 if (LType->getAs<FunctionProtoType>() || RType->getAs<FunctionProtoType>()) {
858 // Unfortunately, the canonical type of a function pointer becomes the
859 // same even if exactly one is "noexcept" and the other isn't, making us
860 // give a false positive report irrespective of implicit conversions.
861 LLVM_DEBUG(llvm::dbgs()
862 << "--- calculateMixability. Discarding potential canonical "
863 "equivalence on FunctionProtoTypes.\n");
864 RecursiveReturnDiscardingCanonicalType = true;
865 }
866
867 MixData MixToReturn{MixFlags::None};
868
869 // If none of the previous logic found a match, try if Clang otherwise
870 // believes the types to be the same.
871 QualType LCanonical = LType.getCanonicalType();
872 if (LCanonical == RType.getCanonicalType()) {
873 LLVM_DEBUG(llvm::dbgs()
874 << "<<< calculateMixability. Same CanonicalType.\n");
875 MixToReturn = {MixFlags::Canonical, LCanonical};
876 }
877
878 if (RecursiveReturnDiscardingCanonicalType)
880
881 LLVM_DEBUG(if (MixToReturn.Flags == MixFlags::None) llvm::dbgs()
882 << "<<< calculateMixability. No match found.\n");
883 return MixToReturn;
884}
885
886/// Calculates if the reference binds an expression of the given type. This is
887/// true iff 'LRef' is some 'const T &' type, and the 'Ty' is 'T' or 'const T'.
888///
889/// \param ImplicitMode is forwarded in the possible recursive call to
890/// calculateMixability.
891static MixData
893 const LValueReferenceType *LRef, QualType Ty,
894 const ASTContext &Ctx, bool IsRefRHS,
895 ImplicitConversionModellingMode ImplicitMode) {
896 LLVM_DEBUG(llvm::dbgs() << ">>> isLRefEquallyBindingToType for LRef:\n";
897 LRef->dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand Type:\n";
898 Ty.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';);
899
900 QualType ReferredType = LRef->getPointeeType();
901 if (!ReferredType.isLocalConstQualified() &&
902 ReferredType->getAs<TypedefType>()) {
903 LLVM_DEBUG(
904 llvm::dbgs()
905 << "--- isLRefEquallyBindingToType. Non-const LRef to Typedef.\n");
906 ReferredType = ReferredType.getDesugaredType(Ctx);
907 if (!ReferredType.isLocalConstQualified()) {
908 LLVM_DEBUG(llvm::dbgs()
909 << "<<< isLRefEquallyBindingToType. Typedef is not const.\n");
910 return {MixFlags::None};
911 }
912
913 LLVM_DEBUG(llvm::dbgs() << "--- isLRefEquallyBindingToType. Typedef is "
914 "const, considering as const LRef.\n");
915 } else if (!ReferredType.isLocalConstQualified()) {
916 LLVM_DEBUG(llvm::dbgs()
917 << "<<< isLRefEquallyBindingToType. Not const LRef.\n");
918 return {MixFlags::None};
919 };
920
921 assert(ReferredType.isLocalConstQualified() &&
922 "Reaching this point means we are sure LRef is effectively a const&.");
923
924 if (ReferredType == Ty) {
925 LLVM_DEBUG(
926 llvm::dbgs()
927 << "<<< isLRefEquallyBindingToType. Type of referred matches.\n");
928 return {MixFlags::Trivial, ReferredType};
929 }
930
931 QualType NonConstReferredType = ReferredType;
932 NonConstReferredType.removeLocalConst();
933 if (NonConstReferredType == Ty) {
934 LLVM_DEBUG(llvm::dbgs() << "<<< isLRefEquallyBindingToType. Type of "
935 "referred matches to non-const qualified.\n");
936 return {MixFlags::Trivial, NonConstReferredType};
937 }
938
939 LLVM_DEBUG(
940 llvm::dbgs()
941 << "--- isLRefEquallyBindingToType. Checking mix for underlying type.\n");
942 return IsRefRHS ? calculateMixability(Check, Ty, NonConstReferredType, Ctx,
943 ImplicitMode)
944 : calculateMixability(Check, NonConstReferredType, Ty, Ctx,
945 ImplicitMode);
946}
947
948static inline bool isDerivedToBase(const CXXRecordDecl *Derived,
949 const CXXRecordDecl *Base) {
950 return Derived && Base && Derived->isCompleteDefinition() &&
951 Base->isCompleteDefinition() && Derived->isDerivedFrom(Base);
952}
953
954static std::optional<QualType>
956 QualType To, const ASTContext &Ctx) {
957 LLVM_DEBUG(llvm::dbgs() << ">>> approximateStdConv for LType:\n";
958 From.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";
959 To.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';);
960
961 // A standard conversion sequence consists of the following, in order:
962 // * Maybe either LValue->RValue conv., Array->Ptr conv., Function->Ptr conv.
963 // * Maybe Numeric promotion or conversion.
964 // * Maybe function pointer conversion.
965 // * Maybe qualifier adjustments.
966 QualType WorkType = From;
967 // Get out the qualifiers of the original type. This will always be
968 // re-applied to the WorkType to ensure it is the same qualification as the
969 // original From was.
970 auto FastQualifiersToApply = static_cast<unsigned>(
971 From.split().Quals.getAsOpaqueValue() & Qualifiers::FastMask);
972
973 // LValue->RValue is irrelevant for the check, because it is a thing to be
974 // done at a call site, and will be performed if need be performed.
975
976 // Array->Pointer decay is handled by the main method in desugaring
977 // the parameter's DecayedType as "useless sugar".
978
979 // Function->Pointer conversions are also irrelevant, because a
980 // "FunctionType" cannot be the type of a parameter variable, so this
981 // conversion is only meaningful at call sites.
982
983 // Numeric promotions and conversions.
984 const auto *FromBuiltin = WorkType->getAs<BuiltinType>();
985 const auto *ToBuiltin = To->getAs<BuiltinType>();
986 bool FromNumeric = FromBuiltin && (FromBuiltin->isIntegerType() ||
987 FromBuiltin->isFloatingType());
988 bool ToNumeric =
989 ToBuiltin && (ToBuiltin->isIntegerType() || ToBuiltin->isFloatingType());
990 if (FromNumeric && ToNumeric) {
991 // If both are integral types, the numeric conversion is performed.
992 // Reapply the qualifiers of the original type, however, so
993 // "const int -> double" in this case moves over to
994 // "const double -> double".
995 LLVM_DEBUG(llvm::dbgs()
996 << "--- approximateStdConv. Conversion between numerics.\n");
997 WorkType = QualType{ToBuiltin, FastQualifiersToApply};
998 }
999
1000 const auto *FromEnum = WorkType->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 (Ctx.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 bool BestConversionHasImplicit =
1154 hasFlag(BestConversion->Flags, MixFlags::ImplicitConversion);
1155 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 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 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 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 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 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 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 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 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 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 for (const auto &E1SetElem : E1Iterator->second)
1593 if (E2Iterator->second.contains(E1SetElem))
1594 return true;
1595
1596 return false;
1597}
1598
1599/// Implements the heuristic that marks two parameters related if there is
1600/// a usage for both in the same strict expression subtree. A strict
1601/// expression subtree is a tree which only includes Expr nodes, i.e. no
1602/// Stmts and no Decls.
1603class AppearsInSameExpr : public RecursiveASTVisitor<AppearsInSameExpr> {
1604 using Base = RecursiveASTVisitor<AppearsInSameExpr>;
1605
1606 const FunctionDecl *FD;
1607 const Expr *CurrentExprOnlyTreeRoot = nullptr;
1608 llvm::DenseMap<const ParmVarDecl *,
1609 llvm::SmallPtrSet<const Expr *, SmallDataStructureSize>>
1610 ParentExprsForParamRefs;
1611
1612public:
1613 void setup(const FunctionDecl *FD) {
1614 this->FD = FD;
1615 TraverseFunctionDecl(const_cast<FunctionDecl *>(FD));
1616 }
1617
1618 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1619 return lazyMapOfSetsIntersectionExists(ParentExprsForParamRefs, Param1,
1620 Param2);
1621 }
1622
1623 bool TraverseDecl(Decl *D) {
1624 CurrentExprOnlyTreeRoot = nullptr;
1625 return Base::TraverseDecl(D);
1626 }
1627
1628 bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue = nullptr) {
1629 if (auto *E = dyn_cast_or_null<Expr>(S)) {
1630 bool RootSetInCurrentStackFrame = false;
1631 if (!CurrentExprOnlyTreeRoot) {
1632 CurrentExprOnlyTreeRoot = E;
1633 RootSetInCurrentStackFrame = true;
1634 }
1635
1636 bool Ret = Base::TraverseStmt(S);
1637
1638 if (RootSetInCurrentStackFrame)
1639 CurrentExprOnlyTreeRoot = nullptr;
1640
1641 return Ret;
1642 }
1643
1644 // A Stmt breaks the strictly Expr subtree.
1645 CurrentExprOnlyTreeRoot = nullptr;
1646 return Base::TraverseStmt(S);
1647 }
1648
1649 bool VisitDeclRefExpr(DeclRefExpr *DRE) {
1650 if (!CurrentExprOnlyTreeRoot)
1651 return true;
1652
1653 if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
1654 if (llvm::find(FD->parameters(), PVD))
1655 ParentExprsForParamRefs[PVD].insert(CurrentExprOnlyTreeRoot);
1656
1657 return true;
1658 }
1659};
1660
1661/// Implements the heuristic that marks two parameters related if there are
1662/// two separate calls to the same function (overload) and the parameters are
1663/// passed to the same index in both calls, i.e f(a, b) and f(a, c) passes
1664/// b and c to the same index (2) of f(), marking them related.
1667
1668public:
1669 void setup(const FunctionDecl *FD) {
1670 auto ParamsAsArgsInFnCalls =
1671 match(functionDecl(forEachDescendant(
1672 callExpr(forEachArgumentWithParam(
1673 paramRefExpr(), parmVarDecl().bind("passed-to")))
1674 .bind("call-expr"))),
1675 *FD, FD->getASTContext());
1676 for (const auto &Match : ParamsAsArgsInFnCalls) {
1677 const auto *PassedParamOfThisFn = Match.getNodeAs<ParmVarDecl>("param");
1678 const auto *CE = Match.getNodeAs<CallExpr>("call-expr");
1679 const auto *PassedToParam = Match.getNodeAs<ParmVarDecl>("passed-to");
1680 assert(PassedParamOfThisFn && CE && PassedToParam);
1681
1682 const FunctionDecl *CalledFn = CE->getDirectCallee();
1683 if (!CalledFn)
1684 continue;
1685
1686 std::optional<unsigned> TargetIdx;
1687 unsigned NumFnParams = CalledFn->getNumParams();
1688 for (unsigned Idx = 0; Idx < NumFnParams; ++Idx)
1689 if (CalledFn->getParamDecl(Idx) == PassedToParam)
1690 TargetIdx.emplace(Idx);
1691
1692 assert(TargetIdx && "Matched, but didn't find index?");
1693 TargetParams[PassedParamOfThisFn].insert(
1694 {CalledFn->getCanonicalDecl(), *TargetIdx});
1695 }
1696 }
1697
1698 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1699 return lazyMapOfSetsIntersectionExists(TargetParams, Param1, Param2);
1700 }
1701};
1702
1703/// Implements the heuristic that marks two parameters related if the same
1704/// member is accessed (referred to) inside the current function's body.
1707
1708public:
1709 void setup(const FunctionDecl *FD) {
1710 auto MembersCalledOnParams = match(
1711 functionDecl(forEachDescendant(
1712 memberExpr(hasObjectExpression(paramRefExpr())).bind("mem-expr"))),
1713 *FD, FD->getASTContext());
1714
1715 for (const auto &Match : MembersCalledOnParams) {
1716 const auto *AccessedParam = Match.getNodeAs<ParmVarDecl>("param");
1717 const auto *ME = Match.getNodeAs<MemberExpr>("mem-expr");
1718 assert(AccessedParam && ME);
1719 AccessedMembers[AccessedParam].insert(
1720 ME->getMemberDecl()->getCanonicalDecl());
1721 }
1722 }
1723
1724 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1725 return lazyMapOfSetsIntersectionExists(AccessedMembers, Param1, Param2);
1726 }
1727};
1728
1729/// Implements the heuristic that marks two parameters related if different
1730/// ReturnStmts return them from the function.
1732 llvm::SmallVector<const ParmVarDecl *, SmallDataStructureSize> ReturnedParams;
1733
1734public:
1735 void setup(const FunctionDecl *FD) {
1736 // TODO: Handle co_return.
1737 auto ParamReturns = match(functionDecl(forEachDescendant(
1738 returnStmt(hasReturnValue(paramRefExpr())))),
1739 *FD, FD->getASTContext());
1740 for (const auto &Match : ParamReturns) {
1741 const auto *ReturnedParam = Match.getNodeAs<ParmVarDecl>("param");
1742 assert(ReturnedParam);
1743
1744 if (find(FD->parameters(), ReturnedParam) == FD->param_end())
1745 // Inside the subtree of a FunctionDecl there might be ReturnStmts of
1746 // a parameter that isn't the parameter of the function, e.g. in the
1747 // case of lambdas.
1748 continue;
1749
1750 ReturnedParams.emplace_back(ReturnedParam);
1751 }
1752 }
1753
1754 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1755 return llvm::is_contained(ReturnedParams, Param1) &&
1756 llvm::is_contained(ReturnedParams, Param2);
1757 }
1758};
1759
1760} // namespace relatedness_heuristic
1761
1762/// Helper class that is used to detect if two parameters of the same function
1763/// are used in a similar fashion, to suppress the result.
1765 const bool Enabled;
1770
1771public:
1772 SimilarlyUsedParameterPairSuppressor(const FunctionDecl *FD, bool Enable)
1773 : Enabled(Enable) {
1774 if (!Enable)
1775 return;
1776
1777 SameExpr.setup(FD);
1778 PassToFun.setup(FD);
1779 SameMember.setup(FD);
1780 Returns.setup(FD);
1781 }
1782
1783 /// Returns whether the specified two parameters are deemed similarly used
1784 /// or related by the heuristics.
1785 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1786 if (!Enabled)
1787 return false;
1788
1789 LLVM_DEBUG(llvm::dbgs()
1790 << "::: Matching similar usage / relatedness heuristic...\n");
1791
1792 if (SameExpr(Param1, Param2)) {
1793 LLVM_DEBUG(llvm::dbgs() << "::: Used in the same expression.\n");
1794 return true;
1795 }
1796
1797 if (PassToFun(Param1, Param2)) {
1798 LLVM_DEBUG(llvm::dbgs()
1799 << "::: Passed to same function in different calls.\n");
1800 return true;
1801 }
1802
1803 if (SameMember(Param1, Param2)) {
1804 LLVM_DEBUG(llvm::dbgs()
1805 << "::: Same member field access or method called.\n");
1806 return true;
1807 }
1808
1809 if (Returns(Param1, Param2)) {
1810 LLVM_DEBUG(llvm::dbgs() << "::: Both parameter returned.\n");
1811 return true;
1812 }
1813
1814 LLVM_DEBUG(llvm::dbgs() << "::: None.\n");
1815 return false;
1816 }
1817};
1818
1819// (This function hoists the call to operator() of the wrapper, so we do not
1820// need to define the previous class at the top of the file.)
1821static inline bool
1823 const ParmVarDecl *Param1, const ParmVarDecl *Param2) {
1824 return Suppressor(Param1, Param2);
1825}
1826
1827static void padStringAtEnd(SmallVectorImpl<char> &Str, std::size_t ToLen) {
1828 while (Str.size() < ToLen)
1829 Str.emplace_back('\0');
1830}
1831
1832static void padStringAtBegin(SmallVectorImpl<char> &Str, std::size_t ToLen) {
1833 while (Str.size() < ToLen)
1834 Str.insert(Str.begin(), '\0');
1835}
1836
1837static bool isCommonPrefixWithoutSomeCharacters(std::size_t N, StringRef S1,
1838 StringRef S2) {
1839 assert(S1.size() >= N && S2.size() >= N);
1840 StringRef S1Prefix = S1.take_front(S1.size() - N),
1841 S2Prefix = S2.take_front(S2.size() - N);
1842 return S1Prefix == S2Prefix && !S1Prefix.empty();
1843}
1844
1845static bool isCommonSuffixWithoutSomeCharacters(std::size_t N, StringRef S1,
1846 StringRef S2) {
1847 assert(S1.size() >= N && S2.size() >= N);
1848 StringRef S1Suffix = S1.take_back(S1.size() - N),
1849 S2Suffix = S2.take_back(S2.size() - N);
1850 return S1Suffix == S2Suffix && !S1Suffix.empty();
1851}
1852
1853/// Returns whether the two strings are prefixes or suffixes of each other with
1854/// at most Threshold characters differing on the non-common end.
1855static bool prefixSuffixCoverUnderThreshold(std::size_t Threshold,
1856 StringRef Str1, StringRef Str2) {
1857 if (Threshold == 0)
1858 return false;
1859
1860 // Pad the two strings to the longer length.
1861 std::size_t BiggerLength = std::max(Str1.size(), Str2.size());
1862
1863 if (BiggerLength <= Threshold)
1864 // If the length of the strings is still smaller than the threshold, they
1865 // would be covered by an empty prefix/suffix with the rest differing.
1866 // (E.g. "A" and "X" with Threshold = 1 would mean we think they are
1867 // similar and do not warn about them, which is a too eager assumption.)
1868 return false;
1869
1870 SmallString<32> S1PadE{Str1}, S2PadE{Str2};
1871 padStringAtEnd(S1PadE, BiggerLength);
1872 padStringAtEnd(S2PadE, BiggerLength);
1873
1875 Threshold, StringRef{S1PadE.begin(), BiggerLength},
1876 StringRef{S2PadE.begin(), BiggerLength}))
1877 return true;
1878
1879 SmallString<32> S1PadB{Str1}, S2PadB{Str2};
1880 padStringAtBegin(S1PadB, BiggerLength);
1881 padStringAtBegin(S2PadB, BiggerLength);
1882
1884 Threshold, StringRef{S1PadB.begin(), BiggerLength},
1885 StringRef{S2PadB.begin(), BiggerLength}))
1886 return true;
1887
1888 return false;
1889}
1890
1891} // namespace filter
1892
1893namespace {
1894
1895/// Matches functions that have at least the specified amount of parameters.
1896AST_MATCHER_P(FunctionDecl, parameterCountGE, unsigned, N) {
1897 return Node.getNumParams() >= N;
1898}
1899
1900/// Matches *any* overloaded unary and binary operators.
1901AST_MATCHER(FunctionDecl, isOverloadedUnaryOrBinaryOperator) {
1902 switch (Node.getOverloadedOperator()) {
1903 case OO_None:
1904 case OO_New:
1905 case OO_Delete:
1906 case OO_Array_New:
1907 case OO_Array_Delete:
1908 case OO_Conditional:
1909 case OO_Coawait:
1910 return false;
1911
1912 default:
1913 return Node.getNumParams() <= 2;
1914 }
1915}
1916
1917} // namespace
1918
1919/// Returns the DefaultMinimumLength if the Value of requested minimum length
1920/// is less than 2. Minimum lengths of 0 or 1 are not accepted.
1921static inline unsigned clampMinimumLength(const unsigned Value) {
1922 return Value < 2 ? DefaultMinimumLength : Value;
1923}
1924
1925// FIXME: Maybe unneeded, getNameForDiagnostic() is expected to change to return
1926// a crafted location when the node itself is unnamed. (See D84658, D85033.)
1927/// Returns the diagnostic-friendly name of the node, or empty string.
1928static SmallString<64> getName(const NamedDecl *ND) {
1929 SmallString<64> Name;
1930 llvm::raw_svector_ostream OS{Name};
1931 ND->getNameForDiagnostic(OS, ND->getASTContext().getPrintingPolicy(), false);
1932 return Name;
1933}
1934
1935/// Returns the diagnostic-friendly name of the node, or a constant value.
1936static SmallString<64> getNameOrUnnamed(const NamedDecl *ND) {
1937 auto Name = getName(ND);
1938 if (Name.empty())
1939 Name = "<unnamed>";
1940 return Name;
1941}
1942
1943/// Returns whether a particular Mix between two parameters should have the
1944/// types involved diagnosed to the user. This is only a flag check.
1945static inline bool needsToPrintTypeInDiagnostic(const model::Mix &M) {
1946 using namespace model;
1947 return static_cast<bool>(
1948 M.flags() &
1949 (MixFlags::TypeAlias | MixFlags::ReferenceBind | MixFlags::Qualifiers));
1950}
1951
1952/// Returns whether a particular Mix between the two parameters should have
1953/// implicit conversions elaborated.
1955 return hasFlag(M.flags(), model::MixFlags::ImplicitConversion);
1956}
1957
1958namespace {
1959
1960/// This class formats a conversion sequence into a "Ty1 -> Ty2 -> Ty3" line
1961/// that can be used in diagnostics.
1962struct FormattedConversionSequence {
1963 std::string DiagnosticText;
1964
1965 /// The formatted sequence is trivial if it is "Ty1 -> Ty2", but Ty1 and
1966 /// Ty2 are the types that are shown in the code. A trivial diagnostic
1967 /// does not need to be printed.
1968 bool Trivial = true;
1969
1970 FormattedConversionSequence(const PrintingPolicy &PP,
1971 StringRef StartTypeAsDiagnosed,
1972 const model::ConversionSequence &Conv,
1973 StringRef DestinationTypeAsDiagnosed) {
1974 llvm::raw_string_ostream OS{DiagnosticText};
1975
1976 // Print the type name as it is printed in other places in the diagnostic.
1977 OS << '\'' << StartTypeAsDiagnosed << '\'';
1978 std::string LastAddedType = StartTypeAsDiagnosed.str();
1979 std::size_t NumElementsAdded = 1;
1980
1981 // However, the parameter's defined type might not be what the implicit
1982 // conversion started with, e.g. if a typedef is found to convert.
1983 std::string SeqBeginTypeStr = Conv.Begin.getAsString(PP);
1984 std::string SeqEndTypeStr = Conv.End.getAsString(PP);
1985 if (StartTypeAsDiagnosed != SeqBeginTypeStr) {
1986 OS << " (as '" << SeqBeginTypeStr << "')";
1987 LastAddedType = SeqBeginTypeStr;
1988 Trivial = false;
1989 }
1990
1991 auto AddType = [&](StringRef ToAdd) {
1992 if (LastAddedType != ToAdd && ToAdd != SeqEndTypeStr) {
1993 OS << " -> '" << ToAdd << "'";
1994 LastAddedType = ToAdd.str();
1995 ++NumElementsAdded;
1996 }
1997 };
1998 for (QualType InvolvedType : Conv.getInvolvedTypesInSequence())
1999 // Print every type that's unique in the sequence into the diagnosis.
2000 AddType(InvolvedType.getAsString(PP));
2001
2002 if (LastAddedType != DestinationTypeAsDiagnosed) {
2003 OS << " -> '" << DestinationTypeAsDiagnosed << "'";
2004 LastAddedType = DestinationTypeAsDiagnosed.str();
2005 ++NumElementsAdded;
2006 }
2007
2008 // Same reasoning as with the Begin, e.g. if the converted-to type is a
2009 // typedef, it will not be the same inside the conversion sequence (where
2010 // the model already tore off typedefs) as in the code.
2011 if (DestinationTypeAsDiagnosed != SeqEndTypeStr) {
2012 OS << " (as '" << SeqEndTypeStr << "')";
2013 LastAddedType = SeqEndTypeStr;
2014 Trivial = false;
2015 }
2016
2017 if (Trivial && NumElementsAdded > 2)
2018 // If the thing is still marked trivial but we have more than the
2019 // from and to types added, it should not be trivial, and elaborated
2020 // when printing the diagnostic.
2021 Trivial = false;
2022 }
2023};
2024
2025/// Retains the elements called with and returns whether the call is done with
2026/// a new element.
2027template <typename E, std::size_t N> class InsertOnce {
2028 llvm::SmallSet<E, N> CalledWith;
2029
2030public:
2031 bool operator()(E El) { return CalledWith.insert(std::move(El)).second; }
2032
2033 bool calledWith(const E &El) const { return CalledWith.contains(El); }
2034};
2035
2036struct SwappedEqualQualTypePair {
2037 QualType LHSType, RHSType;
2038
2039 bool operator==(const SwappedEqualQualTypePair &Other) const {
2040 return (LHSType == Other.LHSType && RHSType == Other.RHSType) ||
2041 (LHSType == Other.RHSType && RHSType == Other.LHSType);
2042 }
2043
2044 bool operator<(const SwappedEqualQualTypePair &Other) const {
2045 return LHSType < Other.LHSType && RHSType < Other.RHSType;
2046 }
2047};
2048
2049struct TypeAliasDiagnosticTuple {
2050 QualType LHSType, RHSType, CommonType;
2051
2052 bool operator==(const TypeAliasDiagnosticTuple &Other) const {
2053 return CommonType == Other.CommonType &&
2054 ((LHSType == Other.LHSType && RHSType == Other.RHSType) ||
2055 (LHSType == Other.RHSType && RHSType == Other.LHSType));
2056 }
2057
2058 bool operator<(const TypeAliasDiagnosticTuple &Other) const {
2059 return CommonType < Other.CommonType && LHSType < Other.LHSType &&
2060 RHSType < Other.RHSType;
2061 }
2062};
2063
2064/// Helper class to only emit a diagnostic related to MixFlags::TypeAlias once.
2065class UniqueTypeAliasDiagnosticHelper
2066 : public InsertOnce<TypeAliasDiagnosticTuple, 8> {
2067 using Base = InsertOnce<TypeAliasDiagnosticTuple, 8>;
2068
2069public:
2070 /// Returns whether the diagnostic for LHSType and RHSType which are both
2071 /// referring to CommonType being the same has not been emitted already.
2072 bool operator()(QualType LHSType, QualType RHSType, QualType CommonType) {
2073 if (CommonType.isNull() || CommonType == LHSType || CommonType == RHSType)
2074 return Base::operator()({LHSType, RHSType, {}});
2075
2076 TypeAliasDiagnosticTuple ThreeTuple{LHSType, RHSType, CommonType};
2077 if (!Base::operator()(ThreeTuple))
2078 return false;
2079
2080 bool AlreadySaidLHSAndCommonIsSame = calledWith({LHSType, CommonType, {}});
2081 bool AlreadySaidRHSAndCommonIsSame = 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 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.
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 bool NeedsAnyTypeNote = llvm::any_of(R.Mixes, needsToPrintTypeInDiagnostic);
2186 bool HasAnyImplicits =
2187 llvm::any_of(R.Mixes, needsToElaborateImplicitConversion);
2188 const ParmVarDecl *First = R.getFirstParam(), *Last = R.getLastParam();
2189 std::string FirstParamTypeAsWritten = First->getType().getAsString(PP);
2190 {
2191 StringRef DiagText;
2192
2193 if (HasAnyImplicits)
2194 DiagText = "%0 adjacent parameters of %1 of convertible types are "
2195 "easily swapped by mistake";
2196 else if (NeedsAnyTypeNote)
2197 DiagText = "%0 adjacent parameters of %1 of similar type are easily "
2198 "swapped by mistake";
2199 else
2200 DiagText = "%0 adjacent parameters of %1 of similar type ('%2') are "
2201 "easily swapped by mistake";
2202
2203 auto Diag = diag(First->getOuterLocStart(), DiagText)
2204 << static_cast<unsigned>(R.NumParamsChecked) << FD;
2205 if (!NeedsAnyTypeNote)
2206 Diag << FirstParamTypeAsWritten;
2207
2208 CharSourceRange HighlightRange = CharSourceRange::getTokenRange(
2209 First->getBeginLoc(), Last->getEndLoc());
2210 Diag << HighlightRange;
2211 }
2212
2213 // There is a chance that the previous highlight did not succeed, e.g. when
2214 // the two parameters are on different lines. For clarity, show the user
2215 // the involved variable explicitly.
2216 diag(First->getLocation(), "the first parameter in the range is '%0'",
2217 DiagnosticIDs::Note)
2218 << getNameOrUnnamed(First)
2219 << CharSourceRange::getTokenRange(First->getLocation(),
2220 First->getLocation());
2221 diag(Last->getLocation(), "the last parameter in the range is '%0'",
2222 DiagnosticIDs::Note)
2223 << getNameOrUnnamed(Last)
2224 << CharSourceRange::getTokenRange(Last->getLocation(),
2225 Last->getLocation());
2226
2227 // Helper classes to silence elaborative diagnostic notes that would be
2228 // too verbose.
2229 UniqueTypeAliasDiagnosticHelper UniqueTypeAlias;
2230 InsertOnce<SwappedEqualQualTypePair, 8> UniqueBindPower;
2231 InsertOnce<SwappedEqualQualTypePair, 8> UniqueImplicitConversion;
2232
2233 for (const model::Mix &M : R.Mixes) {
2234 assert(M.mixable() && "Sentinel or false mix in result.");
2237 continue;
2238
2239 // Typedefs might result in the type of the variable needing to be
2240 // emitted to a note diagnostic, so prepare it.
2241 const ParmVarDecl *LVar = M.First;
2242 const ParmVarDecl *RVar = M.Second;
2243 QualType LType = LVar->getType();
2244 QualType RType = RVar->getType();
2245 QualType CommonType = M.commonUnderlyingType();
2246 std::string LTypeStr = LType.getAsString(PP);
2247 std::string RTypeStr = RType.getAsString(PP);
2248 std::string CommonTypeStr = CommonType.getAsString(PP);
2249
2250 if (hasFlag(M.flags(), MixFlags::TypeAlias) &&
2251 UniqueTypeAlias(LType, RType, CommonType)) {
2252 StringRef DiagText;
2253 bool ExplicitlyPrintCommonType = false;
2254 if (LTypeStr == CommonTypeStr || RTypeStr == CommonTypeStr) {
2255 if (hasFlag(M.flags(), MixFlags::Qualifiers))
2256 DiagText = "after resolving type aliases, '%0' and '%1' share a "
2257 "common type";
2258 else
2259 DiagText =
2260 "after resolving type aliases, '%0' and '%1' are the same";
2261 } else if (!CommonType.isNull()) {
2262 DiagText = "after resolving type aliases, the common type of '%0' "
2263 "and '%1' is '%2'";
2264 ExplicitlyPrintCommonType = true;
2265 }
2266
2267 auto Diag =
2268 diag(LVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2269 << LTypeStr << RTypeStr;
2270 if (ExplicitlyPrintCommonType)
2271 Diag << CommonTypeStr;
2272 }
2273
2274 if ((hasFlag(M.flags(), MixFlags::ReferenceBind) ||
2275 hasFlag(M.flags(), MixFlags::Qualifiers)) &&
2276 UniqueBindPower({LType, RType})) {
2277 StringRef DiagText = "'%0' and '%1' parameters accept and bind the "
2278 "same kind of values";
2279 diag(RVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2280 << LTypeStr << RTypeStr;
2281 }
2282
2284 UniqueImplicitConversion({LType, RType})) {
2285 const model::ConversionSequence &LTR =
2287 const model::ConversionSequence &RTL =
2289 FormattedConversionSequence LTRFmt{PP, LTypeStr, LTR, RTypeStr};
2290 FormattedConversionSequence RTLFmt{PP, RTypeStr, RTL, LTypeStr};
2291
2292 StringRef DiagText = "'%0' and '%1' may be implicitly converted";
2293 if (!LTRFmt.Trivial || !RTLFmt.Trivial)
2294 DiagText = "'%0' and '%1' may be implicitly converted: %2, %3";
2295
2296 {
2297 auto Diag =
2298 diag(RVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2299 << LTypeStr << RTypeStr;
2300
2301 if (!LTRFmt.Trivial || !RTLFmt.Trivial)
2302 Diag << LTRFmt.DiagnosticText << RTLFmt.DiagnosticText;
2303 }
2304
2305 StringRef ConversionFunctionDiagText =
2306 "the implicit conversion involves the "
2307 "%select{|converting constructor|conversion operator}0 "
2308 "declared here";
2309 if (const FunctionDecl *LFD = LTR.getUserDefinedConversionFunction())
2310 diag(LFD->getLocation(), ConversionFunctionDiagText,
2311 DiagnosticIDs::Note)
2312 << static_cast<unsigned>(LTR.UDConvKind)
2314 if (const FunctionDecl *RFD = RTL.getUserDefinedConversionFunction())
2315 diag(RFD->getLocation(), ConversionFunctionDiagText,
2316 DiagnosticIDs::Note)
2317 << static_cast<unsigned>(RTL.UDConvKind)
2319 }
2320 }
2321 }
2322}
2323
2324} // 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.