65 const StatementMatcher LoopVarMatcher =
66 expr(ignoringParenImpCasts(
67 anyOf(declRefExpr(to(varDecl(hasType(isInteger())))),
68 memberExpr(member(fieldDecl(hasType(isInteger())))))))
72 const StatementMatcher LoopVarConversionMatcher = traverse(
73 TK_AsIs, implicitCastExpr(hasImplicitDestinationType(isInteger()),
74 has(ignoringParenImpCasts(LoopVarMatcher)))
79 const StatementMatcher LoopBoundMatcher =
80 expr(ignoringParenImpCasts(allOf(
81 hasType(isInteger()), unless(integerLiteral()),
83 hasType(isConstQualified()),
84 declRefExpr(to(varDecl(anyOf(
85 hasInitializer(ignoringParenImpCasts(integerLiteral())),
86 isConstexpr(), isConstinit())))))),
87 unless(hasType(enumType())))))
92 const StatementMatcher IncrementMatcher =
98 binaryOperator(hasOperatorName(
"<"),
99 hasLHS(LoopVarConversionMatcher),
100 hasRHS(LoopBoundMatcher)),
101 binaryOperator(hasOperatorName(
"<="),
102 hasLHS(LoopVarConversionMatcher),
103 hasRHS(LoopBoundMatcher)),
104 binaryOperator(hasOperatorName(
">"), hasLHS(LoopBoundMatcher),
105 hasRHS(LoopVarConversionMatcher)),
106 binaryOperator(hasOperatorName(
">="), hasLHS(LoopBoundMatcher),
107 hasRHS(LoopVarConversionMatcher)))),
108 hasIncrement(IncrementMatcher))
115 const QualType &IntExprType,
116 const Expr *IntExpr) {
117 assert(IntExprType->isIntegerType());
119 const unsigned SignedBits = IntExprType->isUnsignedIntegerType() ? 0U : 1U;
121 if (
const auto *BitField = IntExpr->getSourceBitField()) {
122 const unsigned BitFieldWidth = BitField->getBitWidthValue();
123 return {BitFieldWidth - SignedBits, BitFieldWidth};
126 const unsigned IntWidth = Context.getIntWidth(IntExprType);
127 return {IntWidth - SignedBits, 0U};
134 const QualType &UpperBoundType) {
137 if (
const auto *BinOperator = dyn_cast<BinaryOperator>(UpperBound)) {
138 const Expr *RHSE = BinOperator->getRHS()->IgnoreParenImpCasts();
139 const Expr *LHSE = BinOperator->getLHS()->IgnoreParenImpCasts();
141 const QualType RHSEType = RHSE->getType();
142 const QualType LHSEType = LHSE->getType();
144 if (!RHSEType->isIntegerType() || !LHSEType->isIntegerType())
147 const bool RHSEIsConstantValue = RHSEType->isEnumeralType() ||
148 RHSEType.isConstQualified() ||
149 isa<IntegerLiteral>(RHSE);
150 const bool LHSEIsConstantValue = LHSEType->isEnumeralType() ||
151 LHSEType.isConstQualified() ||
152 isa<IntegerLiteral>(LHSE);
155 if (RHSEIsConstantValue && LHSEIsConstantValue)
157 if (RHSEIsConstantValue)
159 if (LHSEIsConstantValue)
181 const auto *LoopVar = Result.Nodes.getNodeAs<Expr>(
LoopVarName);
182 const auto *UpperBound =
184 const auto *LoopIncrement =
188 if (LoopVar->getType() != LoopIncrement->getType())
191 const ASTContext &Context = *Result.Context;
193 const QualType LoopVarType = LoopVar->getType();
194 const MagnitudeBits LoopVarMagnitudeBits =
197 const MagnitudeBits LoopIncrementMagnitudeBits =
200 if (LoopIncrementMagnitudeBits != LoopVarMagnitudeBits)
203 const QualType UpperBoundType = UpperBound->getType();
204 const MagnitudeBits UpperBoundMagnitudeBits =
207 if ((0U == UpperBoundMagnitudeBits.WidthWithoutSignBit) ||
208 (LoopVarMagnitudeBits.WidthWithoutSignBit > MagnitudeBitsUpperLimit) ||
209 (LoopVarMagnitudeBits.WidthWithoutSignBit >=
210 UpperBoundMagnitudeBits.WidthWithoutSignBit))
213 diag(LoopVar->getBeginLoc(),
214 "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...