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