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