38 const std::string &CastBindName = std::string()) {
42 auto IntTypeExpr = expr(hasType(hasCanonicalType(qualType(
43 isInteger(), IsSigned ? isSignedInteger() : isUnsignedInteger(),
44 unless(isActualChar()), unless(booleanType()), unless(enumType())))));
46 const auto ImplicitCastExpr =
47 CastBindName.empty() ? implicitCastExpr(hasSourceExpression(IntTypeExpr))
48 : implicitCastExpr(hasSourceExpression(IntTypeExpr))
51 const auto CStyleCastExpr = cStyleCastExpr(has(ImplicitCastExpr));
52 const auto StaticCastExpr = cxxStaticCastExpr(has(ImplicitCastExpr));
53 const auto FunctionalCastExpr = cxxFunctionalCastExpr(has(ImplicitCastExpr));
55 return expr(anyOf(ImplicitCastExpr, CStyleCastExpr, StaticCastExpr,
113 const MatchFinder::MatchResult &Result) {
114 const auto *SignedCastExpression =
115 Result.Nodes.getNodeAs<ImplicitCastExpr>(
"sIntCastExpression");
116 assert(SignedCastExpression);
119 Expr::EvalResult EVResult;
120 if (!SignedCastExpression->isValueDependent() &&
121 SignedCastExpression->getSubExpr()->EvaluateAsInt(EVResult,
123 const llvm::APSInt SValue = EVResult.Val.getInt();
124 if (SValue.isNonNegative())
128 const auto *BinaryOp =
129 Result.Nodes.getNodeAs<BinaryOperator>(
"intComparison");
130 if (BinaryOp ==
nullptr)
133 const BinaryOperator::Opcode OpCode = BinaryOp->getOpcode();
135 const Expr *LHS = BinaryOp->getLHS()->IgnoreImpCasts();
136 const Expr *RHS = BinaryOp->getRHS()->IgnoreImpCasts();
137 if (LHS ==
nullptr || RHS ==
nullptr)
139 const Expr *SubExprLHS =
nullptr;
140 const Expr *SubExprRHS =
nullptr;
141 SourceRange R1(LHS->getBeginLoc());
142 SourceRange R2(BinaryOp->getOperatorLoc());
143 SourceRange R3(Lexer::getLocForEndOfToken(
144 RHS->getEndLoc(), 0, *Result.SourceManager, getLangOpts()));
145 if (
const auto *LHSCast = llvm::dyn_cast<ExplicitCastExpr>(LHS)) {
146 SubExprLHS = LHSCast->getSubExpr();
147 R1 = SourceRange(LHS->getBeginLoc(),
148 SubExprLHS->getBeginLoc().getLocWithOffset(-1));
149 R2.setBegin(Lexer::getLocForEndOfToken(
150 SubExprLHS->getEndLoc(), 0, *Result.SourceManager, getLangOpts()));
152 if (
const auto *RHSCast = llvm::dyn_cast<ExplicitCastExpr>(RHS)) {
153 SubExprRHS = RHSCast->getSubExpr();
154 R2.setEnd(SubExprRHS->getBeginLoc().getLocWithOffset(-1));
156 DiagnosticBuilder Diag =
157 diag(BinaryOp->getBeginLoc(),
158 "comparison between 'signed' and 'unsigned' integers");
159 std::string CmpNamespace;
160 llvm::StringRef CmpHeader;
162 if (getLangOpts().CPlusPlus20) {
163 CmpHeader =
"<utility>";
164 CmpNamespace = llvm::Twine(
"std::" +
parseOpCode(OpCode)).str();
165 }
else if (getLangOpts().CPlusPlus17 && EnableQtSupport) {
166 CmpHeader =
"<QtCore/q20utility.h>";
167 CmpNamespace = llvm::Twine(
"q20::" +
parseOpCode(OpCode)).str();
171 Diag << FixItHint::CreateReplacement(
172 CharSourceRange(R1, SubExprLHS !=
nullptr),
173 llvm::Twine(CmpNamespace +
"(").str());
174 Diag << FixItHint::CreateReplacement(R2,
",");
175 Diag << FixItHint::CreateReplacement(CharSourceRange::getCharRange(R3),
")");
178 Diag << IncludeInserter.createIncludeInsertion(
179 Result.SourceManager->getFileID(BinaryOp->getBeginLoc()), CmpHeader);
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.