70 StatementMatcher LoopVarMatcher =
71 expr(ignoringParenImpCasts(
72 anyOf(declRefExpr(to(varDecl(hasType(isInteger())))),
73 memberExpr(member(fieldDecl(hasType(isInteger())))))))
77 StatementMatcher LoopVarConversionMatcher = traverse(
78 TK_AsIs, implicitCastExpr(hasImplicitDestinationType(isInteger()),
79 has(ignoringParenImpCasts(LoopVarMatcher)))
84 StatementMatcher LoopBoundMatcher =
85 expr(ignoringParenImpCasts(allOf(
86 hasType(isInteger()), unless(integerLiteral()),
88 hasType(isConstQualified()),
89 declRefExpr(to(varDecl(anyOf(
90 hasInitializer(ignoringParenImpCasts(integerLiteral())),
91 isConstexpr(), isConstinit())))))),
92 unless(hasType(enumType())))))
97 StatementMatcher IncrementMatcher =
103 binaryOperator(hasOperatorName(
"<"),
104 hasLHS(LoopVarConversionMatcher),
105 hasRHS(LoopBoundMatcher)),
106 binaryOperator(hasOperatorName(
"<="),
107 hasLHS(LoopVarConversionMatcher),
108 hasRHS(LoopBoundMatcher)),
109 binaryOperator(hasOperatorName(
">"), hasLHS(LoopBoundMatcher),
110 hasRHS(LoopVarConversionMatcher)),
111 binaryOperator(hasOperatorName(
">="), hasLHS(LoopBoundMatcher),
112 hasRHS(LoopVarConversionMatcher)))),
113 hasIncrement(IncrementMatcher))
120 const QualType &IntExprType,
121 const Expr *IntExpr) {
122 assert(IntExprType->isIntegerType());
124 unsigned SignedBits = IntExprType->isUnsignedIntegerType() ? 0U : 1U;
126 if (
const auto *BitField = IntExpr->getSourceBitField()) {
127 unsigned BitFieldWidth = BitField->getBitWidthValue();
128 return {BitFieldWidth - SignedBits, BitFieldWidth};
131 unsigned IntWidth = Context.getIntWidth(IntExprType);
132 return {IntWidth - SignedBits, 0U};
139 const QualType &UpperBoundType) {
142 if (
const auto *BinOperator = dyn_cast<BinaryOperator>(UpperBound)) {
143 const Expr *RHSE = BinOperator->getRHS()->IgnoreParenImpCasts();
144 const Expr *LHSE = BinOperator->getLHS()->IgnoreParenImpCasts();
146 QualType RHSEType = RHSE->getType();
147 QualType LHSEType = LHSE->getType();
149 if (!RHSEType->isIntegerType() || !LHSEType->isIntegerType())
152 bool RHSEIsConstantValue = RHSEType->isEnumeralType() ||
153 RHSEType.isConstQualified() ||
154 isa<IntegerLiteral>(RHSE);
155 bool LHSEIsConstantValue = LHSEType->isEnumeralType() ||
156 LHSEType.isConstQualified() ||
157 isa<IntegerLiteral>(LHSE);
160 if (RHSEIsConstantValue && LHSEIsConstantValue)
162 if (RHSEIsConstantValue)
164 if (LHSEIsConstantValue)
186 const auto *LoopVar = Result.Nodes.getNodeAs<Expr>(
LoopVarName);
187 const auto *UpperBound =
189 const auto *LoopIncrement =
193 if (LoopVar->getType() != LoopIncrement->getType())
196 ASTContext &Context = *Result.Context;
198 const QualType LoopVarType = LoopVar->getType();
199 const MagnitudeBits LoopVarMagnitudeBits =
202 const MagnitudeBits LoopIncrementMagnitudeBits =
205 if (LoopIncrementMagnitudeBits != LoopVarMagnitudeBits)
208 const QualType UpperBoundType = UpperBound->getType();
209 const MagnitudeBits UpperBoundMagnitudeBits =
212 if ((0U == UpperBoundMagnitudeBits.WidthWithoutSignBit) ||
213 (LoopVarMagnitudeBits.WidthWithoutSignBit > MagnitudeBitsUpperLimit) ||
214 (LoopVarMagnitudeBits.WidthWithoutSignBit >=
215 UpperBoundMagnitudeBits.WidthWithoutSignBit))
218 diag(LoopVar->getBeginLoc(),
219 "loop variable has narrower type '%0' than iteration's upper bound '%1'")
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
static MagnitudeBits calcUpperBoundMagnitudeBits(const ASTContext &Context, const Expr *UpperBound, const QualType &UpperBoundType)
Calculate the upper bound expression's magnitude bits, but ignore constant like values to reduce fals...