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