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