clang-tools 24.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 const 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 const 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 assert(BestConversion &&
1188 "BestConversion must be set if HowManyGoodConversions is 1");
1189 LLVM_DEBUG(llvm::dbgs()
1190 << "--- selectUserDefinedConv. Unique result. Flags: "
1191 << formatMixFlags(BestConversion->Flags) << '\n');
1192 return BestConversion;
1193 }
1194
1195 LLVM_DEBUG(llvm::dbgs()
1196 << "--- selectUserDefinedConv. No, or ambiguous.\n");
1197 return {};
1198 }
1199
1200private:
1201 SmallVector<PreparedConversion, 2> FlaggedConversions;
1202 const TheCheck &Check;
1203};
1204
1205} // namespace
1206
1207static std::optional<ConversionSequence>
1208tryConversionOperators(const TheCheck &Check, const CXXRecordDecl *RD,
1209 QualType ToType) {
1210 if (!RD || !RD->isCompleteDefinition())
1211 return {};
1212 RD = RD->getDefinition();
1213
1214 LLVM_DEBUG(llvm::dbgs() << ">>> tryConversionOperators: " << RD->getName()
1215 << " to:\n";
1216 ToType.dump(llvm::dbgs(), RD->getASTContext());
1217 llvm::dbgs() << '\n';);
1218
1219 UserDefinedConversionSelector ConversionSet{Check};
1220
1221 for (const NamedDecl *Method : RD->getVisibleConversionFunctions()) {
1222 const auto *Con = dyn_cast<CXXConversionDecl>(Method);
1223 if (!Con || Con->isExplicit())
1224 continue;
1225 LLVM_DEBUG(llvm::dbgs() << "--- tryConversionOperators. Trying:\n";
1226 Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';);
1227
1228 // Try to go from the result of conversion operator to the expected type,
1229 // without calculating another user-defined conversion.
1230 ConversionSet.addConversion(Con, Con->getConversionType(), ToType);
1231 }
1232
1233 if (std::optional<UserDefinedConversionSelector::PreparedConversion>
1234 SelectedConversion = ConversionSet()) {
1235 const CanQualType RecordType = RD->getASTContext().getCanonicalTagType(RD);
1236
1237 ConversionSequence Result{RecordType, ToType};
1238 // The conversion from the operator call's return type to ToType was
1239 // modelled as a "pre-conversion" in the operator call, but it is the
1240 // "post-conversion" from the point of view of the original conversion
1241 // we are modelling.
1242 Result.AfterSecondStandard = SelectedConversion->Seq.AfterFirstStandard;
1243
1244 ConversionSequence::UserDefinedConversionOperator ConvOp;
1245 ConvOp.Fun = cast<CXXConversionDecl>(SelectedConversion->ConversionFun);
1246 ConvOp.UserDefinedType = RecordType;
1247 ConvOp.ConversionOperatorResultType = ConvOp.Fun->getConversionType();
1248 Result.setConversion(ConvOp);
1249
1250 LLVM_DEBUG(llvm::dbgs() << "<<< tryConversionOperators. Found result.\n");
1251 return Result;
1252 }
1253
1254 LLVM_DEBUG(llvm::dbgs() << "<<< tryConversionOperators. No conversion.\n");
1255 return {};
1256}
1257
1258static std::optional<ConversionSequence>
1259tryConvertingConstructors(const TheCheck &Check, QualType FromType,
1260 const CXXRecordDecl *RD) {
1261 if (!RD || !RD->isCompleteDefinition())
1262 return {};
1263 RD = RD->getDefinition();
1264
1265 LLVM_DEBUG(llvm::dbgs() << ">>> tryConveringConstructors: " << RD->getName()
1266 << " from:\n";
1267 FromType.dump(llvm::dbgs(), RD->getASTContext());
1268 llvm::dbgs() << '\n';);
1269
1270 UserDefinedConversionSelector ConversionSet{Check};
1271
1272 for (const CXXConstructorDecl *Con : RD->ctors()) {
1273 if (Con->isCopyOrMoveConstructor() ||
1274 !Con->isConvertingConstructor(/* AllowExplicit =*/false))
1275 continue;
1276 LLVM_DEBUG(llvm::dbgs() << "--- tryConvertingConstructors. Trying:\n";
1277 Con->dump(llvm::dbgs()); llvm::dbgs() << '\n';);
1278
1279 // Try to go from the original FromType to the converting constructor's
1280 // parameter type without another user-defined conversion.
1281 ConversionSet.addConversion(Con, FromType, Con->getParamDecl(0)->getType());
1282 }
1283
1284 if (std::optional<UserDefinedConversionSelector::PreparedConversion>
1285 SelectedConversion = ConversionSet()) {
1286 const CanQualType RecordType = RD->getASTContext().getCanonicalTagType(RD);
1287
1288 ConversionSequence Result{FromType, RecordType};
1289 Result.AfterFirstStandard = SelectedConversion->Seq.AfterFirstStandard;
1290
1291 ConversionSequence::UserDefinedConvertingConstructor Ctor;
1292 Ctor.Fun = cast<CXXConstructorDecl>(SelectedConversion->ConversionFun);
1293 Ctor.ConstructorParameterType = Ctor.Fun->getParamDecl(0)->getType();
1294 Ctor.UserDefinedType = RecordType;
1295 Result.setConversion(Ctor);
1296
1297 LLVM_DEBUG(llvm::dbgs()
1298 << "<<< tryConvertingConstructors. Found result.\n");
1299 return Result;
1300 }
1301
1302 LLVM_DEBUG(llvm::dbgs() << "<<< tryConvertingConstructors. No conversion.\n");
1303 return {};
1304}
1305
1306/// Returns whether an expression of LType can be used in an RType context, as
1307/// per the implicit conversion rules.
1308///
1309/// Note: the result of this operation, unlike that of calculateMixability, is
1310/// **NOT** symmetric.
1311static MixData
1312approximateImplicitConversion(const TheCheck &Check, QualType LType,
1313 QualType RType, const ASTContext &Ctx,
1314 ImplicitConversionModellingMode ImplicitMode) {
1315 LLVM_DEBUG(llvm::dbgs() << ">>> approximateImplicitConversion for LType:\n";
1316 LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n";
1317 RType.dump(llvm::dbgs(), Ctx);
1318 llvm::dbgs() << "\nimplicit mode: "; switch (ImplicitMode) {
1319 case ImplicitConversionModellingMode::None:
1320 llvm::dbgs() << "None";
1321 break;
1322 case ImplicitConversionModellingMode::All:
1323 llvm::dbgs() << "All";
1324 break;
1325 case ImplicitConversionModellingMode::OneWaySingleStandardOnly:
1326 llvm::dbgs() << "OneWay, Single, STD Only";
1327 break;
1328 } llvm::dbgs() << '\n';);
1329 if (LType == RType)
1330 return {MixFlags::Trivial, LType};
1331
1332 // An implicit conversion sequence consists of the following, in order:
1333 // * Maybe standard conversion sequence.
1334 // * Maybe user-defined conversion.
1335 // * Maybe standard conversion sequence.
1336 ConversionSequence ImplicitSeq{LType, RType};
1337 QualType WorkType = LType;
1338
1339 std::optional<QualType> AfterFirstStdConv =
1340 approximateStandardConversionSequence(Check, LType, RType, Ctx);
1341 if (AfterFirstStdConv) {
1342 LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Standard "
1343 "Pre-Conversion found!\n");
1344 ImplicitSeq.AfterFirstStandard = *AfterFirstStdConv;
1345 WorkType = ImplicitSeq.AfterFirstStandard;
1346 }
1347
1348 if (ImplicitMode == ImplicitConversionModellingMode::OneWaySingleStandardOnly)
1349 // If the caller only requested modelling of a standard conversion, bail.
1350 return {ImplicitSeq.AfterFirstStandard.isNull()
1351 ? MixFlags::None
1352 : MixFlags::ImplicitConversion,
1353 ImplicitSeq};
1354
1355 if (Ctx.getLangOpts().CPlusPlus) {
1356 bool FoundConversionOperator = false, FoundConvertingCtor = false;
1357
1358 if (const auto *LRD = WorkType->getAsCXXRecordDecl()) {
1359 std::optional<ConversionSequence> ConversionOperatorResult =
1360 tryConversionOperators(Check, LRD, RType);
1361 if (ConversionOperatorResult) {
1362 LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Found "
1363 "conversion operator.\n");
1364 ImplicitSeq.update(*ConversionOperatorResult);
1365 WorkType = ImplicitSeq.getTypeAfterUserDefinedConversion();
1366 FoundConversionOperator = true;
1367 }
1368 }
1369
1370 if (const auto *RRD = RType->getAsCXXRecordDecl()) {
1371 // Use the original "LType" here, and not WorkType, because the
1372 // conversion to the converting constructors' parameters will be
1373 // modelled in the recursive call.
1374 std::optional<ConversionSequence> ConvCtorResult =
1375 tryConvertingConstructors(Check, LType, RRD);
1376 if (ConvCtorResult) {
1377 LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Found "
1378 "converting constructor.\n");
1379 ImplicitSeq.update(*ConvCtorResult);
1380 WorkType = ImplicitSeq.getTypeAfterUserDefinedConversion();
1381 FoundConvertingCtor = true;
1382 }
1383 }
1384
1385 if (FoundConversionOperator && FoundConvertingCtor) {
1386 // If both an operator and a ctor matches, the sequence is ambiguous.
1387 LLVM_DEBUG(llvm::dbgs()
1388 << "<<< approximateImplicitConversion. Found both "
1389 "user-defined conversion kinds in the same sequence!\n");
1390 return {MixFlags::None};
1391 }
1392 }
1393
1394 // After the potential user-defined conversion, another standard conversion
1395 // sequence might exist.
1396 LLVM_DEBUG(
1397 llvm::dbgs()
1398 << "--- approximateImplicitConversion. Try to find post-conversion.\n");
1399 const MixData SecondStdConv = approximateImplicitConversion(
1400 Check, WorkType, RType, Ctx,
1401 ImplicitConversionModellingMode::OneWaySingleStandardOnly);
1402 if (SecondStdConv.indicatesMixability()) {
1403 LLVM_DEBUG(llvm::dbgs() << "--- approximateImplicitConversion. Standard "
1404 "Post-Conversion found!\n");
1405
1406 // The single-step modelling puts the modelled conversion into the "PreStd"
1407 // variable in the recursive call, but from the PoV of this function, it is
1408 // the post-conversion.
1409 ImplicitSeq.AfterSecondStandard =
1410 SecondStdConv.Conversion.AfterFirstStandard;
1411 WorkType = ImplicitSeq.AfterSecondStandard;
1412 }
1413
1414 if (ImplicitSeq) {
1415 LLVM_DEBUG(llvm::dbgs()
1416 << "<<< approximateImplicitConversion. Found a conversion.\n");
1417 return {MixFlags::ImplicitConversion, ImplicitSeq};
1418 }
1419
1420 LLVM_DEBUG(
1421 llvm::dbgs() << "<<< approximateImplicitConversion. No match found.\n");
1422 return {MixFlags::None};
1423}
1424
1425static MixableParameterRange modelMixingRange(
1426 const TheCheck &Check, const FunctionDecl *FD, std::size_t StartIndex,
1427 const filter::SimilarlyUsedParameterPairSuppressor &UsageBasedSuppressor) {
1428 const std::size_t NumParams = FD->getNumParams();
1429 assert(StartIndex < NumParams && "out of bounds for start");
1430 const ASTContext &Ctx = FD->getASTContext();
1431
1432 MixableParameterRange Ret;
1433 // A parameter at index 'StartIndex' had been trivially "checked".
1434 Ret.NumParamsChecked = 1;
1435
1436 for (std::size_t I = StartIndex + 1; I < NumParams; ++I) {
1437 const ParmVarDecl *Ith = FD->getParamDecl(I);
1438 const StringRef ParamName = Ith->getName();
1439 LLVM_DEBUG(llvm::dbgs()
1440 << "Check param #" << I << " '" << ParamName << "'...\n");
1441 if (filter::isIgnoredParameter(Check, Ith)) {
1442 LLVM_DEBUG(llvm::dbgs() << "Param #" << I << " is ignored. Break!\n");
1443 break;
1444 }
1445
1446 const StringRef PrevParamName = FD->getParamDecl(I - 1)->getName();
1447 if (!ParamName.empty() && !PrevParamName.empty() &&
1450 ParamName)) {
1451 LLVM_DEBUG(llvm::dbgs() << "Parameter '" << ParamName
1452 << "' follows a pattern with previous parameter '"
1453 << PrevParamName << "'. Break!\n");
1454 break;
1455 }
1456
1457 // Now try to go forward and build the range of [Start, ..., I, I + 1, ...]
1458 // parameters that can be messed up at a call site.
1459 MixableParameterRange::MixVector MixesOfIth;
1460 for (std::size_t J = StartIndex; J < I; ++J) {
1461 const ParmVarDecl *Jth = FD->getParamDecl(J);
1462 LLVM_DEBUG(llvm::dbgs()
1463 << "Check mix of #" << J << " against #" << I << "...\n");
1464
1465 if (isSimilarlyUsedParameter(UsageBasedSuppressor, Ith, Jth)) {
1466 // Consider the two similarly used parameters to not be possible in a
1467 // mix-up at the user's request, if they enabled this heuristic.
1468 LLVM_DEBUG(llvm::dbgs() << "Parameters #" << I << " and #" << J
1469 << " deemed related, ignoring...\n");
1470
1471 // If the parameter #I and #J mixes, then I is mixable with something
1472 // in the current range, so the range has to be broken and I not
1473 // included.
1474 MixesOfIth.clear();
1475 break;
1476 }
1477
1478 Mix M{Jth, Ith,
1479 calculateMixability(Check, Jth->getType(), Ith->getType(), Ctx,
1481 ? ImplicitConversionModellingMode::All
1482 : ImplicitConversionModellingMode::None)};
1483 LLVM_DEBUG(llvm::dbgs() << "Mix flags (raw) : "
1484 << formatMixFlags(M.flags()) << '\n');
1485 M.sanitize();
1486 LLVM_DEBUG(llvm::dbgs() << "Mix flags (after sanitize): "
1487 << formatMixFlags(M.flags()) << '\n');
1488
1489 assert(M.flagsValid() && "All flags decayed!");
1490
1491 if (M.mixable())
1492 MixesOfIth.emplace_back(std::move(M));
1493 }
1494
1495 if (MixesOfIth.empty()) {
1496 // If there weren't any new mixes stored for Ith, the range is
1497 // [Start, ..., I].
1498 LLVM_DEBUG(llvm::dbgs()
1499 << "Param #" << I
1500 << " does not mix with any in the current range. Break!\n");
1501 break;
1502 }
1503
1504 Ret.Mixes.insert(Ret.Mixes.end(), MixesOfIth.begin(), MixesOfIth.end());
1505 ++Ret.NumParamsChecked; // Otherwise a new param was iterated.
1506 }
1507
1508 return Ret;
1509}
1510
1511} // namespace model
1512
1513namespace {
1514/// Matches DeclRefExprs and their ignorable wrappers to ParmVarDecls.
1515AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<Stmt>, paramRefExpr) {
1516 return expr(ignoringParenImpCasts(ignoringElidableConstructorCall(
1517 declRefExpr(to(parmVarDecl().bind("param"))))));
1518}
1519} // namespace
1520
1521namespace filter {
1522
1523/// Returns whether the parameter's name or the parameter's type's name is
1524/// configured by the user to be ignored from analysis and diagnostic.
1525static bool isIgnoredParameter(const TheCheck &Check, const ParmVarDecl *Node) {
1526 LLVM_DEBUG(llvm::dbgs() << "Checking if '" << Node->getName()
1527 << "' is ignored.\n");
1528
1529 if (!Node->getIdentifier())
1530 return llvm::is_contained(Check.IgnoredParameterNames, "\"\"");
1531
1532 const StringRef NodeName = Node->getName();
1533 if (llvm::is_contained(Check.IgnoredParameterNames, NodeName)) {
1534 LLVM_DEBUG(llvm::dbgs() << "\tName ignored.\n");
1535 return true;
1536 }
1537
1538 const StringRef NodeTypeName = [Node] {
1539 const ASTContext &Ctx = Node->getASTContext();
1540 const SourceManager &SM = Ctx.getSourceManager();
1541 SourceLocation B = Node->getTypeSpecStartLoc();
1542 SourceLocation E = Node->getTypeSpecEndLoc();
1543 const LangOptions LO;
1544
1545 LLVM_DEBUG(llvm::dbgs() << "\tType name code is '"
1546 << Lexer::getSourceText(
1547 CharSourceRange::getTokenRange(B, E), SM, LO)
1548 << "'...\n");
1549 if (B.isMacroID()) {
1550 LLVM_DEBUG(llvm::dbgs() << "\t\tBeginning is macro.\n");
1551 B = SM.getTopMacroCallerLoc(B);
1552 }
1553 if (E.isMacroID()) {
1554 LLVM_DEBUG(llvm::dbgs() << "\t\tEnding is macro.\n");
1555 E = Lexer::getLocForEndOfToken(SM.getTopMacroCallerLoc(E), 0, SM, LO);
1556 }
1557 LLVM_DEBUG(llvm::dbgs() << "\tType name code is '"
1558 << Lexer::getSourceText(
1559 CharSourceRange::getTokenRange(B, E), SM, LO)
1560 << "'...\n");
1561
1562 return Lexer::getSourceText(CharSourceRange::getTokenRange(B, E), SM, LO);
1563 }();
1564
1565 LLVM_DEBUG(llvm::dbgs() << "\tType name is '" << NodeTypeName << "'\n");
1566 if (!NodeTypeName.empty() && llvm::any_of(Check.IgnoredParameterTypeSuffixes,
1567 [NodeTypeName](StringRef E) {
1568 return !E.empty() &&
1569 NodeTypeName.ends_with(E);
1570 })) {
1571 LLVM_DEBUG(llvm::dbgs() << "\tType suffix ignored.\n");
1572 return true;
1573 }
1574
1575 return false;
1576}
1577
1578/// This namespace contains the implementations for the suppression of
1579/// diagnostics from similarly-used ("related") parameters.
1581
1582static constexpr std::size_t SmallDataStructureSize = 4;
1583
1584template <typename T, std::size_t N = SmallDataStructureSize>
1586 llvm::DenseMap<const ParmVarDecl *, llvm::SmallSet<T, N>>;
1587
1588template <typename T, std::size_t N = SmallDataStructureSize>
1590 llvm::DenseMap<const ParmVarDecl *, llvm::SmallPtrSet<T, N>>;
1591
1592/// Returns whether the sets mapped to the two elements in the map have at
1593/// least one element in common.
1594template <typename MapTy, typename ElemTy>
1595static bool lazyMapOfSetsIntersectionExists(const MapTy &Map, const ElemTy &E1,
1596 const ElemTy &E2) {
1597 const auto E1Iterator = Map.find(E1);
1598 auto E2Iterator = Map.find(E2);
1599 if (E1Iterator == Map.end() || E2Iterator == Map.end())
1600 return false;
1601
1602 return llvm::any_of(E1Iterator->second, [&E2Iterator](const auto &E1SetElem) {
1603 return E2Iterator->second.contains(E1SetElem);
1604 });
1605}
1606
1607namespace {
1608
1609/// Implements the heuristic that marks two parameters related if there is
1610/// a usage for both in the same strict expression subtree. A strict
1611/// expression subtree is a tree which only includes Expr nodes, i.e. no
1612/// Stmts and no Decls.
1613class AppearsInSameExpr : public RecursiveASTVisitor<AppearsInSameExpr> {
1614 using Base = RecursiveASTVisitor<AppearsInSameExpr>;
1615
1616 const FunctionDecl *FD;
1617 const Expr *CurrentExprOnlyTreeRoot = nullptr;
1618 llvm::DenseMap<const ParmVarDecl *,
1619 llvm::SmallPtrSet<const Expr *, SmallDataStructureSize>>
1620 ParentExprsForParamRefs;
1621
1622public:
1623 void setup(const FunctionDecl *FD) {
1624 this->FD = FD;
1625 TraverseFunctionDecl(const_cast<FunctionDecl *>(FD));
1626 }
1627
1628 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1629 return lazyMapOfSetsIntersectionExists(ParentExprsForParamRefs, Param1,
1630 Param2);
1631 }
1632
1633 bool TraverseDecl(Decl *D) {
1634 CurrentExprOnlyTreeRoot = nullptr;
1635 return Base::TraverseDecl(D);
1636 }
1637
1638 bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue = nullptr) {
1639 if (const auto *E = dyn_cast_or_null<Expr>(S)) {
1640 bool RootSetInCurrentStackFrame = false;
1641 if (!CurrentExprOnlyTreeRoot) {
1642 CurrentExprOnlyTreeRoot = E;
1643 RootSetInCurrentStackFrame = true;
1644 }
1645
1646 const bool Ret = Base::TraverseStmt(S);
1647
1648 if (RootSetInCurrentStackFrame)
1649 CurrentExprOnlyTreeRoot = nullptr;
1650
1651 return Ret;
1652 }
1653
1654 // A Stmt breaks the strictly Expr subtree.
1655 CurrentExprOnlyTreeRoot = nullptr;
1656 return Base::TraverseStmt(S);
1657 }
1658
1659 bool VisitDeclRefExpr(DeclRefExpr *DRE) {
1660 if (!CurrentExprOnlyTreeRoot)
1661 return true;
1662
1663 if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl());
1664 PVD && llvm::find(FD->parameters(), PVD))
1665 ParentExprsForParamRefs[PVD].insert(CurrentExprOnlyTreeRoot);
1666
1667 return true;
1668 }
1669};
1670
1671/// Implements the heuristic that marks two parameters related if there are
1672/// two separate calls to the same function (overload) and the parameters are
1673/// passed to the same index in both calls, i.e f(a, b) and f(a, c) passes
1674/// b and c to the same index (2) of f(), marking them related.
1675class PassedToSameFunction {
1677
1678public:
1679 void setup(const FunctionDecl *FD) {
1680 const auto ParamsAsArgsInFnCalls =
1681 match(functionDecl(forEachDescendant(
1682 callExpr(forEachArgumentWithParam(
1683 paramRefExpr(), parmVarDecl().bind("passed-to")))
1684 .bind("call-expr"))),
1685 *FD, FD->getASTContext());
1686 for (const auto &Match : ParamsAsArgsInFnCalls) {
1687 const auto *PassedParamOfThisFn = Match.getNodeAs<ParmVarDecl>("param");
1688 const auto *CE = Match.getNodeAs<CallExpr>("call-expr");
1689 const auto *PassedToParam = Match.getNodeAs<ParmVarDecl>("passed-to");
1690 assert(PassedParamOfThisFn && CE && PassedToParam);
1691
1692 const FunctionDecl *CalledFn = CE->getDirectCallee();
1693 if (!CalledFn)
1694 continue;
1695
1696 std::optional<unsigned> TargetIdx;
1697 const unsigned NumFnParams = CalledFn->getNumParams();
1698 for (unsigned Idx = 0; Idx < NumFnParams; ++Idx)
1699 if (CalledFn->getParamDecl(Idx) == PassedToParam)
1700 TargetIdx.emplace(Idx);
1701
1702 assert(TargetIdx && "Matched, but didn't find index?");
1703 TargetParams[PassedParamOfThisFn].insert(
1704 {CalledFn->getCanonicalDecl(), *TargetIdx});
1705 }
1706 }
1707
1708 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1709 return lazyMapOfSetsIntersectionExists(TargetParams, Param1, Param2);
1710 }
1711};
1712
1713/// Implements the heuristic that marks two parameters related if the same
1714/// member is accessed (referred to) inside the current function's body.
1715class AccessedSameMemberOf {
1717
1718public:
1719 void setup(const FunctionDecl *FD) {
1720 const auto MembersCalledOnParams = match(
1721 functionDecl(forEachDescendant(
1722 memberExpr(hasObjectExpression(paramRefExpr())).bind("mem-expr"))),
1723 *FD, FD->getASTContext());
1724
1725 for (const auto &Match : MembersCalledOnParams) {
1726 const auto *AccessedParam = Match.getNodeAs<ParmVarDecl>("param");
1727 const auto *ME = Match.getNodeAs<MemberExpr>("mem-expr");
1728 assert(AccessedParam && ME);
1729 AccessedMembers[AccessedParam].insert(
1730 ME->getMemberDecl()->getCanonicalDecl());
1731 }
1732 }
1733
1734 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1735 return lazyMapOfSetsIntersectionExists(AccessedMembers, Param1, Param2);
1736 }
1737};
1738
1739/// Implements the heuristic that marks two parameters related if different
1740/// ReturnStmts return them from the function.
1741class Returned {
1742 SmallVector<const ParmVarDecl *, SmallDataStructureSize> ReturnedParams;
1743
1744public:
1745 void setup(const FunctionDecl *FD) {
1746 // TODO: Handle co_return.
1747 const auto ParamReturns = match(functionDecl(forEachDescendant(returnStmt(
1748 hasReturnValue(paramRefExpr())))),
1749 *FD, FD->getASTContext());
1750 for (const auto &Match : ParamReturns) {
1751 const auto *ReturnedParam = Match.getNodeAs<ParmVarDecl>("param");
1752 assert(ReturnedParam);
1753
1754 if (find(FD->parameters(), ReturnedParam) == FD->param_end())
1755 // Inside the subtree of a FunctionDecl there might be ReturnStmts of
1756 // a parameter that isn't the parameter of the function, e.g. in the
1757 // case of lambdas.
1758 continue;
1759
1760 ReturnedParams.emplace_back(ReturnedParam);
1761 }
1762 }
1763
1764 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1765 return llvm::is_contained(ReturnedParams, Param1) &&
1766 llvm::is_contained(ReturnedParams, Param2);
1767 }
1768};
1769
1770} // namespace
1771
1772} // namespace relatedness_heuristic
1773
1774/// Helper class that is used to detect if two parameters of the same function
1775/// are used in a similar fashion, to suppress the result.
1777 const bool Enabled;
1778 relatedness_heuristic::AppearsInSameExpr SameExpr;
1779 relatedness_heuristic::PassedToSameFunction PassToFun;
1780 relatedness_heuristic::AccessedSameMemberOf SameMember;
1781 relatedness_heuristic::Returned Returns;
1782
1783public:
1784 SimilarlyUsedParameterPairSuppressor(const FunctionDecl *FD, bool Enable)
1785 : Enabled(Enable) {
1786 if (!Enable)
1787 return;
1788
1789 SameExpr.setup(FD);
1790 PassToFun.setup(FD);
1791 SameMember.setup(FD);
1792 Returns.setup(FD);
1793 }
1794
1795 /// Returns whether the specified two parameters are deemed similarly used
1796 /// or related by the heuristics.
1797 bool operator()(const ParmVarDecl *Param1, const ParmVarDecl *Param2) const {
1798 if (!Enabled)
1799 return false;
1800
1801 LLVM_DEBUG(llvm::dbgs()
1802 << "::: Matching similar usage / relatedness heuristic...\n");
1803
1804 if (SameExpr(Param1, Param2)) {
1805 LLVM_DEBUG(llvm::dbgs() << "::: Used in the same expression.\n");
1806 return true;
1807 }
1808
1809 if (PassToFun(Param1, Param2)) {
1810 LLVM_DEBUG(llvm::dbgs()
1811 << "::: Passed to same function in different calls.\n");
1812 return true;
1813 }
1814
1815 if (SameMember(Param1, Param2)) {
1816 LLVM_DEBUG(llvm::dbgs()
1817 << "::: Same member field access or method called.\n");
1818 return true;
1819 }
1820
1821 if (Returns(Param1, Param2)) {
1822 LLVM_DEBUG(llvm::dbgs() << "::: Both parameter returned.\n");
1823 return true;
1824 }
1825
1826 LLVM_DEBUG(llvm::dbgs() << "::: None.\n");
1827 return false;
1828 }
1829};
1830
1831// (This function hoists the call to operator() of the wrapper, so we do not
1832// need to define the previous class at the top of the file.)
1833static inline bool
1835 const ParmVarDecl *Param1, const ParmVarDecl *Param2) {
1836 return Suppressor(Param1, Param2);
1837}
1838
1839static void padStringAtEnd(SmallVectorImpl<char> &Str, std::size_t ToLen) {
1840 while (Str.size() < ToLen)
1841 Str.emplace_back('\0');
1842}
1843
1844static void padStringAtBegin(SmallVectorImpl<char> &Str, std::size_t ToLen) {
1845 while (Str.size() < ToLen)
1846 Str.insert(Str.begin(), '\0');
1847}
1848
1849static bool isCommonPrefixWithoutSomeCharacters(std::size_t N, StringRef S1,
1850 StringRef S2) {
1851 assert(S1.size() >= N && S2.size() >= N);
1852 const StringRef S1Prefix = S1.take_front(S1.size() - N),
1853 S2Prefix = S2.take_front(S2.size() - N);
1854 return S1Prefix == S2Prefix && !S1Prefix.empty();
1855}
1856
1857static bool isCommonSuffixWithoutSomeCharacters(std::size_t N, StringRef S1,
1858 StringRef S2) {
1859 assert(S1.size() >= N && S2.size() >= N);
1860 const StringRef S1Suffix = S1.take_back(S1.size() - N),
1861 S2Suffix = S2.take_back(S2.size() - N);
1862 return S1Suffix == S2Suffix && !S1Suffix.empty();
1863}
1864
1865/// Returns whether the two strings are prefixes or suffixes of each other with
1866/// at most Threshold characters differing on the non-common end.
1867static bool prefixSuffixCoverUnderThreshold(std::size_t Threshold,
1868 StringRef Str1, StringRef Str2) {
1869 if (Threshold == 0)
1870 return false;
1871
1872 // Pad the two strings to the longer length.
1873 const std::size_t BiggerLength = std::max(Str1.size(), Str2.size());
1874
1875 if (BiggerLength <= Threshold)
1876 // If the length of the strings is still smaller than the threshold, they
1877 // would be covered by an empty prefix/suffix with the rest differing.
1878 // (E.g. "A" and "X" with Threshold = 1 would mean we think they are
1879 // similar and do not warn about them, which is a too eager assumption.)
1880 return false;
1881
1882 SmallString<32> S1PadE{Str1}, S2PadE{Str2};
1883 padStringAtEnd(S1PadE, BiggerLength);
1884 padStringAtEnd(S2PadE, BiggerLength);
1885
1887 Threshold, StringRef{S1PadE.begin(), BiggerLength},
1888 StringRef{S2PadE.begin(), BiggerLength}))
1889 return true;
1890
1891 SmallString<32> S1PadB{Str1}, S2PadB{Str2};
1892 padStringAtBegin(S1PadB, BiggerLength);
1893 padStringAtBegin(S2PadB, BiggerLength);
1894
1896 Threshold, StringRef{S1PadB.begin(), BiggerLength},
1897 StringRef{S2PadB.begin(), BiggerLength}))
1898 return true;
1899
1900 return false;
1901}
1902
1903} // namespace filter
1904
1905namespace {
1906
1907/// Matches functions that have at least the specified amount of parameters.
1908AST_MATCHER_P(FunctionDecl, parameterCountGE, unsigned, N) {
1909 return Node.getNumParams() >= N;
1910}
1911
1912/// Matches *any* overloaded unary and binary operators.
1913AST_MATCHER(FunctionDecl, isOverloadedUnaryOrBinaryOperator) {
1914 switch (Node.getOverloadedOperator()) {
1915 case OO_None:
1916 case OO_New:
1917 case OO_Delete:
1918 case OO_Array_New:
1919 case OO_Array_Delete:
1920 case OO_Conditional:
1921 case OO_Coawait:
1922 return false;
1923
1924 default:
1925 return Node.getNumParams() <= 2;
1926 }
1927}
1928
1929} // namespace
1930
1931/// Returns the DefaultMinimumLength if the Value of requested minimum length
1932/// is less than 2. Minimum lengths of 0 or 1 are not accepted.
1933static inline unsigned clampMinimumLength(const unsigned Value) {
1934 return Value < 2 ? DefaultMinimumLength : Value;
1935}
1936
1937// FIXME: Maybe unneeded, getNameForDiagnostic() is expected to change to return
1938// a crafted location when the node itself is unnamed. (See D84658, D85033.)
1939/// Returns the diagnostic-friendly name of the node, or empty string.
1940static SmallString<64> getName(const NamedDecl *ND) {
1941 SmallString<64> Name;
1942 llvm::raw_svector_ostream OS{Name};
1943 ND->getNameForDiagnostic(OS, ND->getASTContext().getPrintingPolicy(), false);
1944 return Name;
1945}
1946
1947/// Returns the diagnostic-friendly name of the node, or a constant value.
1948static SmallString<64> getNameOrUnnamed(const NamedDecl *ND) {
1949 auto Name = getName(ND);
1950 if (Name.empty())
1951 Name = "<unnamed>";
1952 return Name;
1953}
1954
1955/// Returns whether a particular Mix between two parameters should have the
1956/// types involved diagnosed to the user. This is only a flag check.
1957static inline bool needsToPrintTypeInDiagnostic(const model::Mix &M) {
1958 using namespace model;
1959 return static_cast<bool>(
1960 M.flags() &
1961 (MixFlags::TypeAlias | MixFlags::ReferenceBind | MixFlags::Qualifiers));
1962}
1963
1964/// Returns whether a particular Mix between the two parameters should have
1965/// implicit conversions elaborated.
1966static inline bool needsToElaborateImplicitConversion(const model::Mix &M) {
1967 return model::hasFlag(M.flags(), model::MixFlags::ImplicitConversion);
1968}
1969
1970namespace {
1971
1972/// This class formats a conversion sequence into a "Ty1 -> Ty2 -> Ty3" line
1973/// that can be used in diagnostics.
1974struct FormattedConversionSequence {
1975 std::string DiagnosticText;
1976
1977 /// The formatted sequence is trivial if it is "Ty1 -> Ty2", but Ty1 and
1978 /// Ty2 are the types that are shown in the code. A trivial diagnostic
1979 /// does not need to be printed.
1980 bool Trivial = true;
1981
1982 FormattedConversionSequence(const PrintingPolicy &PP,
1983 StringRef StartTypeAsDiagnosed,
1984 const model::ConversionSequence &Conv,
1985 StringRef DestinationTypeAsDiagnosed) {
1986 llvm::raw_string_ostream OS{DiagnosticText};
1987
1988 // Print the type name as it is printed in other places in the diagnostic.
1989 OS << '\'' << StartTypeAsDiagnosed << '\'';
1990 std::string LastAddedType = StartTypeAsDiagnosed.str();
1991 std::size_t NumElementsAdded = 1;
1992
1993 // However, the parameter's defined type might not be what the implicit
1994 // conversion started with, e.g. if a typedef is found to convert.
1995 const std::string SeqBeginTypeStr = Conv.Begin.getAsString(PP);
1996 std::string SeqEndTypeStr = Conv.End.getAsString(PP);
1997 if (StartTypeAsDiagnosed != SeqBeginTypeStr) {
1998 OS << " (as '" << SeqBeginTypeStr << "')";
1999 LastAddedType = SeqBeginTypeStr;
2000 Trivial = false;
2001 }
2002
2003 const auto AddType = [&](StringRef ToAdd) {
2004 if (LastAddedType != ToAdd && ToAdd != SeqEndTypeStr) {
2005 OS << " -> '" << ToAdd << "'";
2006 LastAddedType = ToAdd.str();
2007 ++NumElementsAdded;
2008 }
2009 };
2010 for (const QualType InvolvedType : Conv.getInvolvedTypesInSequence())
2011 // Print every type that's unique in the sequence into the diagnosis.
2012 AddType(InvolvedType.getAsString(PP));
2013
2014 if (LastAddedType != DestinationTypeAsDiagnosed) {
2015 OS << " -> '" << DestinationTypeAsDiagnosed << "'";
2016 LastAddedType = DestinationTypeAsDiagnosed.str();
2017 ++NumElementsAdded;
2018 }
2019
2020 // Same reasoning as with the Begin, e.g. if the converted-to type is a
2021 // typedef, it will not be the same inside the conversion sequence (where
2022 // the model already tore off typedefs) as in the code.
2023 if (DestinationTypeAsDiagnosed != SeqEndTypeStr) {
2024 OS << " (as '" << SeqEndTypeStr << "')";
2025 LastAddedType = SeqEndTypeStr;
2026 Trivial = false;
2027 }
2028
2029 if (Trivial && NumElementsAdded > 2)
2030 // If the thing is still marked trivial but we have more than the
2031 // from and to types added, it should not be trivial, and elaborated
2032 // when printing the diagnostic.
2033 Trivial = false;
2034 }
2035};
2036
2037/// Retains the elements called with and returns whether the call is done with
2038/// a new element.
2039template <typename E, std::size_t N> class InsertOnce {
2040 llvm::SmallSet<E, N> CalledWith;
2041
2042public:
2043 bool operator()(E El) { return CalledWith.insert(std::move(El)).second; }
2044
2045 bool calledWith(const E &El) const { return CalledWith.contains(El); }
2046};
2047
2048struct SwappedEqualQualTypePair {
2049 QualType LHSType, RHSType;
2050
2051 bool operator==(const SwappedEqualQualTypePair &Other) const {
2052 return (LHSType == Other.LHSType && RHSType == Other.RHSType) ||
2053 (LHSType == Other.RHSType && RHSType == Other.LHSType);
2054 }
2055
2056 bool operator<(const SwappedEqualQualTypePair &Other) const {
2057 return LHSType < Other.LHSType && RHSType < Other.RHSType;
2058 }
2059};
2060
2061struct TypeAliasDiagnosticTuple {
2062 QualType LHSType, RHSType, CommonType;
2063
2064 bool operator==(const TypeAliasDiagnosticTuple &Other) const {
2065 return CommonType == Other.CommonType &&
2066 ((LHSType == Other.LHSType && RHSType == Other.RHSType) ||
2067 (LHSType == Other.RHSType && RHSType == Other.LHSType));
2068 }
2069
2070 bool operator<(const TypeAliasDiagnosticTuple &Other) const {
2071 return CommonType < Other.CommonType && LHSType < Other.LHSType &&
2072 RHSType < Other.RHSType;
2073 }
2074};
2075
2076/// Helper class to only emit a diagnostic related to MixFlags::TypeAlias once.
2077class UniqueTypeAliasDiagnosticHelper
2078 : public InsertOnce<TypeAliasDiagnosticTuple, 8> {
2079 using Base = InsertOnce<TypeAliasDiagnosticTuple, 8>;
2080
2081public:
2082 /// Returns whether the diagnostic for LHSType and RHSType which are both
2083 /// referring to CommonType being the same has not been emitted already.
2084 bool operator()(QualType LHSType, QualType RHSType, QualType CommonType) {
2085 if (CommonType.isNull() || CommonType == LHSType || CommonType == RHSType)
2086 return Base::operator()({LHSType, RHSType, {}});
2087
2088 const TypeAliasDiagnosticTuple ThreeTuple{LHSType, RHSType, CommonType};
2089 if (!Base::operator()(ThreeTuple))
2090 return false;
2091
2092 const bool AlreadySaidLHSAndCommonIsSame =
2093 calledWith({LHSType, CommonType, {}});
2094 const bool AlreadySaidRHSAndCommonIsSame =
2095 calledWith({RHSType, CommonType, {}});
2096 if (AlreadySaidLHSAndCommonIsSame && AlreadySaidRHSAndCommonIsSame) {
2097 // "SomeInt == int" && "SomeOtherInt == int" => "Common(SomeInt,
2098 // SomeOtherInt) == int", no need to diagnose it. Save the 3-tuple only
2099 // for shortcut if it ever appears again.
2100 return false;
2101 }
2102
2103 return true;
2104 }
2105};
2106
2107} // namespace
2108
2110 StringRef Name, ClangTidyContext *Context)
2111 : ClangTidyCheck(Name, Context),
2113 Options.get("MinimumLength", DefaultMinimumLength))),
2114 IgnoredParameterNames(optutils::parseStringList(
2115 Options.get("IgnoredParameterNames", DefaultIgnoredParameterNames))),
2116 IgnoredParameterTypeSuffixes(optutils::parseStringList(
2117 Options.get("IgnoredParameterTypeSuffixes",
2119 QualifiersMix(Options.get("QualifiersMix", DefaultQualifiersMix)),
2120 ModelImplicitConversions(Options.get("ModelImplicitConversions",
2123 Options.get("SuppressParametersUsedTogether",
2126 Options.get("NamePrefixSuffixSilenceDissimilarityThreshold",
2128
2131 Options.store(Opts, "MinimumLength", MinimumLength);
2132 Options.store(Opts, "IgnoredParameterNames",
2134 Options.store(Opts, "IgnoredParameterTypeSuffixes",
2136 Options.store(Opts, "QualifiersMix", QualifiersMix);
2137 Options.store(Opts, "ModelImplicitConversions", ModelImplicitConversions);
2138 Options.store(Opts, "SuppressParametersUsedTogether",
2140 Options.store(Opts, "NamePrefixSuffixSilenceDissimilarityThreshold",
2142}
2143
2145 const auto BaseConstraints = functionDecl(
2146 // Only report for definition nodes, as fixing the issues reported
2147 // requires the user to be able to change code.
2148 isDefinition(), parameterCountGE(MinimumLength),
2149 unless(isOverloadedUnaryOrBinaryOperator()));
2150
2151 Finder->addMatcher(
2152 functionDecl(BaseConstraints,
2153 unless(ast_matchers::isTemplateInstantiation()))
2154 .bind("func"),
2155 this);
2156 Finder->addMatcher(
2157 functionDecl(BaseConstraints, isExplicitTemplateSpecialization())
2158 .bind("func"),
2159 this);
2160}
2161
2163 const MatchFinder::MatchResult &Result) {
2164 using namespace model;
2165 using namespace filter;
2166
2167 const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("func");
2168 assert(FD);
2169
2170 const PrintingPolicy &PP = FD->getASTContext().getPrintingPolicy();
2171 const std::size_t NumParams = FD->getNumParams();
2172 std::size_t MixableRangeStartIndex = 0;
2173
2174 // Spawn one suppressor and if the user requested, gather information from
2175 // the AST for the parameters' usages.
2176 const filter::SimilarlyUsedParameterPairSuppressor UsageBasedSuppressor{
2178
2179 LLVM_DEBUG(llvm::dbgs() << "Begin analysis of " << getName(FD) << " with "
2180 << NumParams << " parameters...\n");
2181 while (MixableRangeStartIndex < NumParams) {
2182 if (isIgnoredParameter(*this, FD->getParamDecl(MixableRangeStartIndex))) {
2183 LLVM_DEBUG(llvm::dbgs()
2184 << "Parameter #" << MixableRangeStartIndex << " ignored.\n");
2185 ++MixableRangeStartIndex;
2186 continue;
2187 }
2188
2189 MixableParameterRange R = modelMixingRange(
2190 *this, FD, MixableRangeStartIndex, UsageBasedSuppressor);
2191 assert(R.NumParamsChecked > 0 && "Ensure forward progress!");
2192 MixableRangeStartIndex += R.NumParamsChecked;
2193 if (R.NumParamsChecked < MinimumLength) {
2194 LLVM_DEBUG(llvm::dbgs() << "Ignoring range of " << R.NumParamsChecked
2195 << " lower than limit.\n");
2196 continue;
2197 }
2198
2199 const bool NeedsAnyTypeNote =
2200 llvm::any_of(R.Mixes, needsToPrintTypeInDiagnostic);
2201 const bool HasAnyImplicits =
2202 llvm::any_of(R.Mixes, needsToElaborateImplicitConversion);
2203 const ParmVarDecl *First = R.getFirstParam(), *Last = R.getLastParam();
2204 const std::string FirstParamTypeAsWritten =
2205 First->getType().getAsString(PP);
2206 {
2207 StringRef DiagText;
2208
2209 if (HasAnyImplicits)
2210 DiagText = "%0 adjacent parameters of %1 of convertible types are "
2211 "easily swapped by mistake";
2212 else if (NeedsAnyTypeNote)
2213 DiagText = "%0 adjacent parameters of %1 of similar type are easily "
2214 "swapped by mistake";
2215 else
2216 DiagText = "%0 adjacent parameters of %1 of similar type ('%2') are "
2217 "easily swapped by mistake";
2218
2219 const auto Diag = diag(First->getOuterLocStart(), DiagText)
2220 << static_cast<unsigned>(R.NumParamsChecked) << FD;
2221 if (!NeedsAnyTypeNote)
2222 Diag << FirstParamTypeAsWritten;
2223
2224 const CharSourceRange HighlightRange = CharSourceRange::getTokenRange(
2225 First->getBeginLoc(), Last->getEndLoc());
2226 Diag << HighlightRange;
2227 }
2228
2229 // There is a chance that the previous highlight did not succeed, e.g. when
2230 // the two parameters are on different lines. For clarity, show the user
2231 // the involved variable explicitly.
2232 diag(First->getLocation(), "the first parameter in the range is '%0'",
2233 DiagnosticIDs::Note)
2234 << getNameOrUnnamed(First)
2235 << CharSourceRange::getTokenRange(First->getLocation(),
2236 First->getLocation());
2237 diag(Last->getLocation(), "the last parameter in the range is '%0'",
2238 DiagnosticIDs::Note)
2239 << getNameOrUnnamed(Last)
2240 << CharSourceRange::getTokenRange(Last->getLocation(),
2241 Last->getLocation());
2242
2243 // Helper classes to silence elaborative diagnostic notes that would be
2244 // too verbose.
2245 UniqueTypeAliasDiagnosticHelper UniqueTypeAlias;
2246 InsertOnce<SwappedEqualQualTypePair, 8> UniqueBindPower;
2247 InsertOnce<SwappedEqualQualTypePair, 8> UniqueImplicitConversion;
2248
2249 for (const model::Mix &M : R.Mixes) {
2250 assert(M.mixable() && "Sentinel or false mix in result.");
2253 continue;
2254
2255 // Typedefs might result in the type of the variable needing to be
2256 // emitted to a note diagnostic, so prepare it.
2257 const ParmVarDecl *LVar = M.First;
2258 const ParmVarDecl *RVar = M.Second;
2259 const QualType LType = LVar->getType();
2260 const QualType RType = RVar->getType();
2261 const QualType CommonType = M.commonUnderlyingType();
2262 const std::string LTypeStr = LType.getAsString(PP);
2263 const std::string RTypeStr = RType.getAsString(PP);
2264 const std::string CommonTypeStr = CommonType.getAsString(PP);
2265
2266 if (hasFlag(M.flags(), MixFlags::TypeAlias) &&
2267 UniqueTypeAlias(LType, RType, CommonType)) {
2268 StringRef DiagText;
2269 bool ExplicitlyPrintCommonType = false;
2270 if (LTypeStr == CommonTypeStr || RTypeStr == CommonTypeStr) {
2271 if (hasFlag(M.flags(), MixFlags::Qualifiers))
2272 DiagText = "after resolving type aliases, '%0' and '%1' share a "
2273 "common type";
2274 else
2275 DiagText =
2276 "after resolving type aliases, '%0' and '%1' are the same";
2277 } else if (!CommonType.isNull()) {
2278 DiagText = "after resolving type aliases, the common type of '%0' "
2279 "and '%1' is '%2'";
2280 ExplicitlyPrintCommonType = true;
2281 }
2282
2283 const auto Diag =
2284 diag(LVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2285 << LTypeStr << RTypeStr;
2286 if (ExplicitlyPrintCommonType)
2287 Diag << CommonTypeStr;
2288 }
2289
2290 if ((hasFlag(M.flags(), MixFlags::ReferenceBind) ||
2291 hasFlag(M.flags(), MixFlags::Qualifiers)) &&
2292 UniqueBindPower({LType, RType})) {
2293 const StringRef DiagText =
2294 "'%0' and '%1' parameters accept and bind the "
2295 "same kind of values";
2296 diag(RVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2297 << LTypeStr << RTypeStr;
2298 }
2299
2301 UniqueImplicitConversion({LType, RType})) {
2302 const model::ConversionSequence &LTR =
2303 M.leftToRightConversionSequence();
2304 const model::ConversionSequence &RTL =
2305 M.rightToLeftConversionSequence();
2306 const FormattedConversionSequence LTRFmt{PP, LTypeStr, LTR, RTypeStr};
2307 const FormattedConversionSequence RTLFmt{PP, RTypeStr, RTL, LTypeStr};
2308
2309 StringRef DiagText = "'%0' and '%1' may be implicitly converted";
2310 if (!LTRFmt.Trivial || !RTLFmt.Trivial)
2311 DiagText = "'%0' and '%1' may be implicitly converted: %2, %3";
2312
2313 {
2314 const auto Diag =
2315 diag(RVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note)
2316 << LTypeStr << RTypeStr;
2317
2318 if (!LTRFmt.Trivial || !RTLFmt.Trivial)
2319 Diag << LTRFmt.DiagnosticText << RTLFmt.DiagnosticText;
2320 }
2321
2322 const StringRef ConversionFunctionDiagText =
2323 "the implicit conversion involves the "
2324 "%select{|converting constructor|conversion operator}0 "
2325 "declared here";
2326 if (const FunctionDecl *LFD = LTR.getUserDefinedConversionFunction())
2327 diag(LFD->getLocation(), ConversionFunctionDiagText,
2328 DiagnosticIDs::Note)
2329 << static_cast<unsigned>(LTR.UDConvKind)
2330 << LTR.getUserDefinedConversionHighlight();
2331 if (const FunctionDecl *RFD = RTL.getUserDefinedConversionFunction())
2332 diag(RFD->getLocation(), ConversionFunctionDiagText,
2333 DiagnosticIDs::Note)
2334 << static_cast<unsigned>(RTL.UDConvKind)
2335 << RTL.getUserDefinedConversionHighlight();
2336 }
2337 }
2338 }
2339}
2340
2341} // 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