diff --git a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp @@ -382,7 +382,7 @@ /// A potentially calculated common underlying type after desugaring, that /// both sides of the mix can originate from. - QualType CommonType; + QualType CoreType; /// The steps an implicit conversion performs to get from one type to the /// other. @@ -393,16 +393,15 @@ bool CreatedFromOneWayConversion = false; MixData(MixFlags Flags) : Flags(Flags) {} - MixData(MixFlags Flags, QualType CommonType) - : Flags(Flags), CommonType(CommonType) {} + MixData(MixFlags Flags, QualType CoreType) + : Flags(Flags), CoreType(CoreType) {} MixData(MixFlags Flags, ConversionSequence Conv) : Flags(Flags), Conversion(Conv), CreatedFromOneWayConversion(true) {} MixData(MixFlags Flags, ConversionSequence LTR, ConversionSequence RTL) : Flags(Flags), Conversion(LTR), ConversionRTL(RTL) {} - MixData(MixFlags Flags, QualType CommonType, ConversionSequence LTR, + MixData(MixFlags Flags, QualType CoreType, ConversionSequence LTR, ConversionSequence RTL) - : Flags(Flags), CommonType(CommonType), Conversion(LTR), - ConversionRTL(RTL) {} + : Flags(Flags), CoreType(CoreType), Conversion(LTR), ConversionRTL(RTL) {} void sanitize() { assert(Flags != MixFlags::Invalid && "sanitize() called on invalid bitvec"); @@ -457,10 +456,10 @@ MixData operator|(MixFlags EnableFlags) const { if (CreatedFromOneWayConversion) { MixData M{Flags | EnableFlags, Conversion}; - M.CommonType = CommonType; + M.CoreType = CoreType; return M; } - return {Flags | EnableFlags, CommonType, Conversion, ConversionRTL}; + return {Flags | EnableFlags, CoreType, Conversion, ConversionRTL}; } /// Add the specified flag bits to the flags. @@ -469,18 +468,22 @@ return *this; } - /// Add the specified qualifiers to the common type in the Mix. + /// Add the specified qualifiers to the core type in the Mix. MixData qualify(Qualifiers Quals) const { - SplitQualType Split = CommonType.split(); - Split.Quals.addQualifiers(Quals); - QualType CommonType{Split.Ty, Split.Quals.getAsOpaqueValue()}; + if (CoreType.isNull()) + return *this; + + QualType NewCoreType = CoreType; + NewCoreType.addFastQualifiers(Quals.getFastQualifiers()); + NewCoreType.getQualifiers().addQualifiers(Quals); if (CreatedFromOneWayConversion) { MixData M{Flags, Conversion}; - M.CommonType = CommonType; + M.CoreType = NewCoreType; return M; } - return {Flags, CommonType, Conversion, ConversionRTL}; + + return {Flags, NewCoreType, Conversion, ConversionRTL}; } }; @@ -497,7 +500,7 @@ MixFlags flags() const { return Data.Flags; } bool flagsValid() const { return Data.isValid(); } bool mixable() const { return Data.indicatesMixability(); } - QualType commonUnderlyingType() const { return Data.CommonType; } + QualType coreUnderlyingType() const { return Data.CoreType; } const ConversionSequence &leftToRightConversionSequence() const { return Data.Conversion; } @@ -566,7 +569,41 @@ ImplicitConversionModellingMode ImplicitMode); static inline bool isUselessSugar(const Type *T) { - return isa(T); + return isa(T); +} + +/// Returns if the two types are qualified in a way that ever after equating or +/// removing local CVR qualification, even if the unqualified types would mix, +/// the qualified ones don't, because there are some other local qualifiers +/// that aren't equal. +static bool hasNonCVRMixabilityBreakingQualifiers(const ASTContext &Ctx, + QualType LType, + QualType RType) { + LLVM_DEBUG( + llvm::dbgs() << ">>> hasNonCVRMixabilityBreakingQualifiers for LType:\n"; + LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"; + RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';); + Qualifiers LQual = LType.getLocalQualifiers(), + RQual = RType.getLocalQualifiers(); + + // Strip potential CVR. That is handled by the check option QualifiersMix. + LQual.removeCVRQualifiers(); + RQual.removeCVRQualifiers(); + + Qualifiers CommonQuals = Qualifiers::removeCommonQualifiers(LQual, RQual); + (void)CommonQuals; + + LLVM_DEBUG(llvm::dbgs() << "--- hasNonCVRMixabilityBreakingQualifiers. " + "Removed common qualifiers: "; + CommonQuals.print(llvm::dbgs(), Ctx.getPrintingPolicy()); + llvm::dbgs() << "\n\tremaining on LType: "; + LQual.print(llvm::dbgs(), Ctx.getPrintingPolicy()); + llvm::dbgs() << "\n\tremaining on RType: "; + RQual.print(llvm::dbgs(), Ctx.getPrintingPolicy()); + llvm::dbgs() << '\n';); + + // If all other qualifiers are common between the two types, good to go. + return LQual.hasQualifiers() || RQual.hasQualifiers(); } /// Approximate the way how LType and RType might refer to "essentially the @@ -585,12 +622,6 @@ LLVM_DEBUG(llvm::dbgs() << ">>> calculateMixability for LType:\n"; LType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << "\nand RType:\n"; RType.dump(llvm::dbgs(), Ctx); llvm::dbgs() << '\n';); - - // Certain constructs match on the last catch-all getCanonicalType() equality, - // which is perhaps something not what we want. If this variable is true, - // the canonical type equality will be ignored. - bool RecursiveReturnDiscardingCanonicalType = false; - if (LType == RType) { LLVM_DEBUG(llvm::dbgs() << "<<< calculateMixability. Trivial equality.\n"); return {MixFlags::Trivial, LType}; @@ -628,7 +659,6 @@ MixFlags::ReferenceBind; } - // Dissolve typedefs after the qualifiers outside the typedef are dealt with. if (LType->getAs()) { LLVM_DEBUG(llvm::dbgs() << "--- calculateMixability. LHS is typedef.\n"); return calculateMixability(Check, LType.getSingleStepDesugaredType(Ctx), @@ -645,35 +675,72 @@ // A parameter of type 'cvr1 T' and another of potentially differently // qualified 'cvr2 T' may bind with the same power, if the user so requested. + // + // Whether to do this check for the inner unqualified types. + bool CompareUnqualifiedTypes = false; + // Should the result have a common inner type qualified for diagnosis? + bool RequalifyUnqualifiedMixabilityResult = false; if (LType.getLocalCVRQualifiers() != RType.getLocalCVRQualifiers()) { - LLVM_DEBUG(if (LType.getLocalCVRQualifiers()) llvm::dbgs() - << "--- calculateMixability. LHS is CVR.\n"); - LLVM_DEBUG(if (RType.getLocalCVRQualifiers()) llvm::dbgs() - << "--- calculateMixability. RHS is CVR.\n"); + LLVM_DEBUG(if (LType.getLocalCVRQualifiers()) { + llvm::dbgs() << "--- calculateMixability. LHS has CVR-Qualifiers: "; + Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) + .print(llvm::dbgs(), Ctx.getPrintingPolicy()); + llvm::dbgs() << '\n'; + }); + LLVM_DEBUG(if (RType.getLocalCVRQualifiers()) { + llvm::dbgs() << "--- calculateMixability. RHS has CVR-Qualifiers: "; + Qualifiers::fromCVRMask(RType.getLocalCVRQualifiers()) + .print(llvm::dbgs(), Ctx.getPrintingPolicy()); + llvm::dbgs() << '\n'; + }); if (!Check.QualifiersMix) { LLVM_DEBUG(llvm::dbgs() - << "<<< calculateMixability. QualifiersMix turned off.\n"); + << "<<< calculateMixability. QualifiersMix turned off - not " + "mixable.\n"); return {MixFlags::None}; } - return calculateMixability(Check, LType.getLocalUnqualifiedType(), - RType.getLocalUnqualifiedType(), Ctx, - ImplicitMode) | - MixFlags::Qualifiers; + CompareUnqualifiedTypes = true; } if (LType.getLocalCVRQualifiers() == RType.getLocalCVRQualifiers() && LType.getLocalCVRQualifiers() != 0) { - LLVM_DEBUG(llvm::dbgs() - << "--- calculateMixability. LHS and RHS same CVR.\n"); - // Apply the same qualifier back into the found common type if we found - // a common type between the unqualified versions. - return calculateMixability(Check, LType.getLocalUnqualifiedType(), - RType.getLocalUnqualifiedType(), Ctx, - ImplicitMode) - .qualify(LType.getLocalQualifiers()); + LLVM_DEBUG(if (LType.getLocalCVRQualifiers()) { + llvm::dbgs() + << "--- calculateMixability. LHS and RHS have same CVR-Qualifiers: "; + Qualifiers::fromCVRMask(LType.getLocalCVRQualifiers()) + .print(llvm::dbgs(), Ctx.getPrintingPolicy()); + llvm::dbgs() << '\n'; + }); + + CompareUnqualifiedTypes = true; + RequalifyUnqualifiedMixabilityResult = true; + } + + if (CompareUnqualifiedTypes) { + if (hasNonCVRMixabilityBreakingQualifiers(Ctx, LType, RType)) { + LLVM_DEBUG(llvm::dbgs() << "<<< calculateMixability. Additional " + "non-equal incompatible qualifiers.\n"); + return {MixFlags::None}; + } + + MixData UnqualifiedMixability = + calculateMixability(Check, LType.getLocalUnqualifiedType(), + RType.getLocalUnqualifiedType(), Ctx, ImplicitMode); + + if (!RequalifyUnqualifiedMixabilityResult) + return UnqualifiedMixability | MixFlags::Qualifiers; + + // Apply the same qualifier back into the found core type if we found + // a core type between the unqualified versions. + return UnqualifiedMixability.qualify(LType.getLocalQualifiers()); } + // Certain constructs match on the last catch-all getCanonicalType() equality, + // which is perhaps something not what we want. If this variable is true, + // the canonical type equality will be ignored. + bool RecursiveReturnDiscardingCanonicalType = false; + if (LType->isPointerType() && RType->isPointerType()) { // If both types are pointers, and pointed to the exact same type, // LType == RType took care of that. Try to see if the pointee type has @@ -1924,16 +1991,16 @@ }; struct TypeAliasDiagnosticTuple { - QualType LHSType, RHSType, CommonType; + QualType LHSType, RHSType, CoreType; bool operator==(const TypeAliasDiagnosticTuple &Other) const { - return CommonType == Other.CommonType && + return CoreType == Other.CoreType && ((LHSType == Other.LHSType && RHSType == Other.RHSType) || (LHSType == Other.RHSType && RHSType == Other.LHSType)); } bool operator<(const TypeAliasDiagnosticTuple &Other) const { - return CommonType < Other.CommonType && LHSType < Other.LHSType && + return CoreType < Other.CoreType && LHSType < Other.LHSType && RHSType < Other.RHSType; } }; @@ -1945,19 +2012,19 @@ public: /// Returns whether the diagnostic for LHSType and RHSType which are both - /// referring to CommonType being the same has not been emitted already. - bool operator()(QualType LHSType, QualType RHSType, QualType CommonType) { - if (CommonType.isNull() || CommonType == LHSType || CommonType == RHSType) + /// referring to CoreType being the same has not been emitted already. + bool operator()(QualType LHSType, QualType RHSType, QualType CoreType) { + if (CoreType.isNull() || CoreType == LHSType || CoreType == RHSType) return Base::operator()({LHSType, RHSType, {}}); - TypeAliasDiagnosticTuple ThreeTuple{LHSType, RHSType, CommonType}; + TypeAliasDiagnosticTuple ThreeTuple{LHSType, RHSType, CoreType}; if (!Base::operator()(ThreeTuple)) return false; - bool AlreadySaidLHSAndCommonIsSame = calledWith({LHSType, CommonType, {}}); - bool AlreadySaidRHSAndCommonIsSame = calledWith({RHSType, CommonType, {}}); - if (AlreadySaidLHSAndCommonIsSame && AlreadySaidRHSAndCommonIsSame) { - // "SomeInt == int" && "SomeOtherInt == int" => "Common(SomeInt, + bool AlreadySaidLHSAndCoreIsSame = calledWith({LHSType, CoreType, {}}); + bool AlreadySaidRHSAndCoreIsSame = calledWith({RHSType, CoreType, {}}); + if (AlreadySaidLHSAndCoreIsSame && AlreadySaidRHSAndCoreIsSame) { + // "SomeInt == int" && "SomeOtherInt == int" => "CoreType(SomeInt, // SomeOtherInt) == int", no need to diagnose it. Save the 3-tuple only // for shortcut if it ever appears again. return false; @@ -2119,33 +2186,33 @@ const ParmVarDecl *RVar = M.Second; QualType LType = LVar->getType(); QualType RType = RVar->getType(); - QualType CommonType = M.commonUnderlyingType(); + QualType CoreType = M.coreUnderlyingType(); std::string LTypeStr = LType.getAsString(PP); std::string RTypeStr = RType.getAsString(PP); - std::string CommonTypeStr = CommonType.getAsString(PP); + std::string CoreTypeStr = CoreType.getAsString(PP); if (hasFlag(M.flags(), MixFlags::TypeAlias) && - UniqueTypeAlias(LType, RType, CommonType)) { + UniqueTypeAlias(LType, RType, CoreType)) { StringRef DiagText; - bool ExplicitlyPrintCommonType = false; - if (LTypeStr == CommonTypeStr || RTypeStr == CommonTypeStr) + bool ExplicitlyPrintCoreType = false; + if (LTypeStr == CoreTypeStr || RTypeStr == CoreTypeStr) if (hasFlag(M.flags(), MixFlags::Qualifiers)) DiagText = "after resolving type aliases, '%0' and '%1' share a " - "common type"; + "core type"; else DiagText = "after resolving type aliases, '%0' and '%1' are the same"; - else if (!CommonType.isNull()) { - DiagText = "after resolving type aliases, the common type of '%0' " + else if (!CoreType.isNull()) { + DiagText = "after resolving type aliases, the core type of '%0' " "and '%1' is '%2'"; - ExplicitlyPrintCommonType = true; + ExplicitlyPrintCoreType = true; } auto Diag = diag(LVar->getOuterLocStart(), DiagText, DiagnosticIDs::Note) << LTypeStr << RTypeStr; - if (ExplicitlyPrintCommonType) - Diag << CommonTypeStr; + if (ExplicitlyPrintCoreType) + Diag << CoreTypeStr; } if ((hasFlag(M.flags(), MixFlags::ReferenceBind) || diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-easily-swappable-parameters-len2.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone-easily-swappable-parameters-len2.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone-easily-swappable-parameters-len2.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-easily-swappable-parameters-len2.cpp @@ -131,7 +131,7 @@ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: 3 adjacent parameters of 'typedefMultiple' of similar type are // CHECK-MESSAGES: :[[@LINE-2]]:29: note: the first parameter in the range is 'I1' // CHECK-MESSAGES: :[[@LINE-3]]:52: note: the last parameter in the range is 'I2y' -// CHECK-MESSAGES: :[[@LINE-4]]:22: note: after resolving type aliases, the common type of 'MyInt1' and 'MyInt2' is 'int' +// CHECK-MESSAGES: :[[@LINE-4]]:22: note: after resolving type aliases, the core type of 'MyInt1' and 'MyInt2' is 'int' void throughTypedef1(int I, MyInt1 J) {} // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: 2 adjacent parameters of 'throughTypedef1' of similar type are @@ -143,7 +143,7 @@ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: 2 adjacent parameters of 'betweenTypedef2' of similar type are // CHECK-MESSAGES: :[[@LINE-2]]:29: note: the first parameter in the range is 'I' // CHECK-MESSAGES: :[[@LINE-3]]:39: note: the last parameter in the range is 'J' -// CHECK-MESSAGES: :[[@LINE-4]]:22: note: after resolving type aliases, the common type of 'MyInt1' and 'MyInt2' is 'int' +// CHECK-MESSAGES: :[[@LINE-4]]:22: note: after resolving type aliases, the core type of 'MyInt1' and 'MyInt2' is 'int' void typedefChain(int I, MyInt1 MI1, MyInt2 MI2, MyInt2b MI2b) {} // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: 4 adjacent parameters of 'typedefChain' of similar type are @@ -179,7 +179,7 @@ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: 3 adjacent parameters of 'qualifiedThroughTypedef3' of similar type are // CHECK-MESSAGES: :[[@LINE-2]]:36: note: the first parameter in the range is 'CI1' // CHECK-MESSAGES: :[[@LINE-3]]:69: note: the last parameter in the range is 'CI3' -// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, the common type of 'CInt' and 'const MyInt1' is 'const int' +// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, the core type of 'CInt' and 'const MyInt1' is 'const int' // CHECK-MESSAGES: :[[@LINE-5]]:31: note: after resolving type aliases, 'CInt' and 'const int' are the same // CHECK-MESSAGES: :[[@LINE-6]]:41: note: after resolving type aliases, 'const MyInt1' and 'const int' are the same @@ -187,15 +187,15 @@ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: 3 adjacent parameters of 'qualifiedThroughTypedef4' of similar type are // CHECK-MESSAGES: :[[@LINE-2]]:36: note: the first parameter in the range is 'CI1' // CHECK-MESSAGES: :[[@LINE-3]]:72: note: the last parameter in the range is 'CI3' -// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, the common type of 'CInt' and 'const MyInt1' is 'const int' -// CHECK-MESSAGES: :[[@LINE-5]]:31: note: after resolving type aliases, the common type of 'CInt' and 'const MyInt2' is 'const int' -// CHECK-MESSAGES: :[[@LINE-6]]:41: note: after resolving type aliases, the common type of 'const MyInt1' and 'const MyInt2' is 'const int' +// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, the core type of 'CInt' and 'const MyInt1' is 'const int' +// CHECK-MESSAGES: :[[@LINE-5]]:31: note: after resolving type aliases, the core type of 'CInt' and 'const MyInt2' is 'const int' +// CHECK-MESSAGES: :[[@LINE-6]]:41: note: after resolving type aliases, the core type of 'const MyInt1' and 'const MyInt2' is 'const int' void qualifiedThroughTypedef5(CMyInt1 CMI1, CMyInt2 CMI2) {} // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: 2 adjacent parameters of 'qualifiedThroughTypedef5' of similar type are // CHECK-MESSAGES: :[[@LINE-2]]:39: note: the first parameter in the range is 'CMI1' // CHECK-MESSAGES: :[[@LINE-3]]:53: note: the last parameter in the range is 'CMI2' -// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, the common type of 'CMyInt1' and 'CMyInt2' is 'const int' +// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, the core type of 'CMyInt1' and 'CMyInt2' is 'const int' void qualifiedThroughTypedef6(CMyInt1 CMI1, int I) {} // NO-WARN: Different qualifiers. @@ -242,7 +242,7 @@ // CHECK-MESSAGES: :[[@LINE-4]]:37: note: 'int' and 'ICRTy' parameters accept and bind the same kind of values // CHECK-MESSAGES: :[[@LINE-5]]:30: note: after resolving type aliases, 'int' and 'MyIntCRTy' are the same // CHECK-MESSAGES: :[[@LINE-6]]:52: note: 'int' and 'MyIntCRTy' parameters accept and bind the same kind of values -// CHECK-MESSAGES: :[[@LINE-7]]:37: note: after resolving type aliases, the common type of 'ICRTy' and 'MyIntCRTy' is 'int' +// CHECK-MESSAGES: :[[@LINE-7]]:37: note: after resolving type aliases, the core type of 'ICRTy' and 'MyIntCRTy' is 'int' // CHECK-MESSAGES: :[[@LINE-8]]:52: note: 'ICRTy' and 'MyIntCRTy' parameters accept and bind the same kind of values short const typedef int unsigned Eldritch; @@ -252,13 +252,13 @@ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 2 adjacent parameters of 'collapse' of similar type are // CHECK-MESSAGES: :[[@LINE-2]]:24: note: the first parameter in the range is 'Cursed' // CHECK-MESSAGES: :[[@LINE-3]]:37: note: the last parameter in the range is 'Blessed' -// CHECK-MESSAGES: :[[@LINE-4]]:15: note: after resolving type aliases, the common type of 'Eldritch' and 'Holy' is 'const unsigned short' +// CHECK-MESSAGES: :[[@LINE-4]]:15: note: after resolving type aliases, the core type of 'Eldritch' and 'Holy' is 'const unsigned short' void collapseAndTypedef(Eldritch Cursed, const Holy &Blessed) {} // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 2 adjacent parameters of 'collapseAndTypedef' of similar type are // CHECK-MESSAGES: :[[@LINE-2]]:34: note: the first parameter in the range is 'Cursed' // CHECK-MESSAGES: :[[@LINE-3]]:54: note: the last parameter in the range is 'Blessed' -// CHECK-MESSAGES: :[[@LINE-4]]:25: note: after resolving type aliases, the common type of 'Eldritch' and 'const Holy &' is 'const unsigned short' +// CHECK-MESSAGES: :[[@LINE-4]]:25: note: after resolving type aliases, the core type of 'Eldritch' and 'const Holy &' is 'const unsigned short' // CHECK-MESSAGES: :[[@LINE-5]]:42: note: 'Eldritch' and 'const Holy &' parameters accept and bind the same kind of values template @@ -346,3 +346,31 @@ void functionPrototypeLosesNoexcept(void (*NonThrowing)() noexcept, void (*Throwing)()) {} // NO-WARN: This call cannot be swapped, even if "getCanonicalType()" believes otherwise. + +void attributedParam1(const __attribute__((address_space(256))) int *One, + const __attribute__((address_space(256))) int *Two) {} +// CHECK-MESSAGES: :[[@LINE-2]]:23: warning: 2 adjacent parameters of 'attributedParam1' of similar type ('const __attribute__((address_space(256))) int *') are +// CHECK-MESSAGES: :[[@LINE-3]]:70: note: the first parameter in the range is 'One' +// CHECK-MESSAGES: :[[@LINE-3]]:70: note: the last parameter in the range is 'Two' + +void attributedParam1Typedef(const __attribute__((address_space(256))) int *One, + const __attribute__((address_space(256))) MyInt1 *Two) {} +// CHECK-MESSAGES: :[[@LINE-2]]:30: warning: 2 adjacent parameters of 'attributedParam1Typedef' of similar type are +// CHECK-MESSAGES: :[[@LINE-3]]:77: note: the first parameter in the range is 'One' +// CHECK-MESSAGES: :[[@LINE-3]]:80: note: the last parameter in the range is 'Two' +// CHECK-MESSAGES: :[[@LINE-5]]:30: note: after resolving type aliases, the core type of 'const __attribute__((address_space(256))) int *' and 'const __attribute__((address_space(256))) MyInt1 *' is 'const __attribute__((address_space(256))) int' +// FIXME: The last diagnostic line is a bit bad: the core type should be a +// pointer type -- it is not clear right now, how it would be possible to +// properly wire a logic in that fixes it. + +void attributedParam2(__attribute__((address_space(256))) int *One, + const __attribute__((address_space(256))) MyInt1 *Two) {} +// NO-WARN: One is CVR-qualified, the other is not. + +void attributedParam3(const int *One, + const __attribute__((address_space(256))) MyInt1 *Two) {} +// NO-WARN: One is attributed, the other is not. + +void attributedParam4(const __attribute__((address_space(512))) int *One, + const __attribute__((address_space(256))) MyInt1 *Two) {} +// NO-WARN: Different value of the attribute. diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-easily-swappable-parameters-qualifiermixing.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone-easily-swappable-parameters-qualifiermixing.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone-easily-swappable-parameters-qualifiermixing.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-easily-swappable-parameters-qualifiermixing.cpp @@ -63,7 +63,7 @@ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: 2 adjacent parameters of 'qualifiedThroughTypedef1' of similar type are // CHECK-MESSAGES: :[[@LINE-2]]:35: note: the first parameter in the range is 'I' // CHECK-MESSAGES: :[[@LINE-3]]:43: note: the last parameter in the range is 'CI' -// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, 'int' and 'CInt' share a common type +// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, 'int' and 'CInt' share a core type // CHECK-MESSAGES: :[[@LINE-5]]:38: note: 'int' and 'CInt' parameters accept and bind the same kind of values void qualifiedThroughTypedef2(CInt CI1, const int CI2) {} @@ -76,7 +76,7 @@ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: 3 adjacent parameters of 'qualifiedThroughTypedef3' of similar type are // CHECK-MESSAGES: :[[@LINE-2]]:36: note: the first parameter in the range is 'CI1' // CHECK-MESSAGES: :[[@LINE-3]]:69: note: the last parameter in the range is 'CI3' -// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, the common type of 'CInt' and 'const MyInt1' is 'const int' +// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, the core type of 'CInt' and 'const MyInt1' is 'const int' // CHECK-MESSAGES: :[[@LINE-5]]:31: note: after resolving type aliases, 'CInt' and 'const int' are the same // CHECK-MESSAGES: :[[@LINE-6]]:41: note: after resolving type aliases, 'const MyInt1' and 'const int' are the same @@ -84,21 +84,21 @@ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: 3 adjacent parameters of 'qualifiedThroughTypedef4' of similar type are // CHECK-MESSAGES: :[[@LINE-2]]:36: note: the first parameter in the range is 'CI1' // CHECK-MESSAGES: :[[@LINE-3]]:72: note: the last parameter in the range is 'CI3' -// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, the common type of 'CInt' and 'const MyInt1' is 'const int' -// CHECK-MESSAGES: :[[@LINE-5]]:31: note: after resolving type aliases, the common type of 'CInt' and 'const MyInt2' is 'const int' -// CHECK-MESSAGES: :[[@LINE-6]]:41: note: after resolving type aliases, the common type of 'const MyInt1' and 'const MyInt2' is 'const int' +// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, the core type of 'CInt' and 'const MyInt1' is 'const int' +// CHECK-MESSAGES: :[[@LINE-5]]:31: note: after resolving type aliases, the core type of 'CInt' and 'const MyInt2' is 'const int' +// CHECK-MESSAGES: :[[@LINE-6]]:41: note: after resolving type aliases, the core type of 'const MyInt1' and 'const MyInt2' is 'const int' void qualifiedThroughTypedef5(CMyInt1 CMI1, CMyInt2 CMI2) {} // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: 2 adjacent parameters of 'qualifiedThroughTypedef5' of similar type are // CHECK-MESSAGES: :[[@LINE-2]]:39: note: the first parameter in the range is 'CMI1' // CHECK-MESSAGES: :[[@LINE-3]]:53: note: the last parameter in the range is 'CMI2' -// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, the common type of 'CMyInt1' and 'CMyInt2' is 'const int' +// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, the core type of 'CMyInt1' and 'CMyInt2' is 'const int' void qualifiedThroughTypedef6(CMyInt1 CMI1, int I) {} // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: 2 adjacent parameters of 'qualifiedThroughTypedef6' of similar type are // CHECK-MESSAGES: :[[@LINE-2]]:39: note: the first parameter in the range is 'CMI1' // CHECK-MESSAGES: :[[@LINE-3]]:49: note: the last parameter in the range is 'I' -// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, 'CMyInt1' and 'int' share a common type +// CHECK-MESSAGES: :[[@LINE-4]]:31: note: after resolving type aliases, 'CMyInt1' and 'int' share a core type // CHECK-MESSAGES: :[[@LINE-5]]:45: note: 'CMyInt1' and 'int' parameters accept and bind the same kind of values void referenceToTypedef1(CInt &CIR, int I) {} @@ -113,3 +113,11 @@ // CHECK-MESSAGES: :[[@LINE-2]]:20: note: the first parameter in the range is 'Dest' // CHECK-MESSAGES: :[[@LINE-3]]:29: note: the last parameter in the range is 'Source' // CHECK-MESSAGES: :[[@LINE-4]]:26: note: 'const T *' and 'T *' parameters accept and bind the same kind of values + +void attributedParam2(__attribute__((address_space(256))) int *One, + const __attribute__((address_space(256))) MyInt1 *Two) {} +// CHECK-MESSAGES: :[[@LINE-2]]:23: warning: 2 adjacent parameters of 'attributedParam2' of similar type are +// CHECK-MESSAGES: :[[@LINE-3]]:64: note: the first parameter in the range is 'One' +// CHECK-MESSAGES: :[[@LINE-3]]:73: note: the last parameter in the range is 'Two' +// CHECK-MESSAGES: :[[@LINE-5]]:23: note: after resolving type aliases, the core type of '__attribute__((address_space(256))) int *' and 'const __attribute__((address_space(256))) MyInt1 *' is 'int' +// CHECK-MESSAGES: :[[@LINE-5]]:23: note: '__attribute__((address_space(256))) int *' and 'const __attribute__((address_space(256))) MyInt1 *' parameters accept and bind the same kind of values