101 [](
const ast_matchers::internal::Matcher<Stmt> &InnerMatcher) {
102 return stmt(anyOf(forStmt(hasCondition(InnerMatcher)),
103 whileStmt(hasCondition(InnerMatcher)),
104 doStmt(hasCondition(InnerMatcher))));
107 const auto IntegerExpr = ignoringParenImpCasts(integerLiteral());
108 const auto ConstantExpr = ignoringParenImpCasts(
109 anyOf(integerLiteral(), unaryOperator(hasUnaryOperand(IntegerExpr)),
110 binaryOperator(hasLHS(IntegerExpr), hasRHS(IntegerExpr))));
111 const auto IntegerCallExpr = ignoringParenImpCasts(callExpr(
112 anyOf(hasType(isInteger()), hasType(hasCanonicalType(enumType()))),
113 unless(isInTemplateInstantiation())));
114 const auto SizeOfExpr = sizeOfExpr(hasArgumentOfType(
115 hasUnqualifiedDesugaredType(type().bind(
"sizeof-arg-type"))));
116 const auto SizeOfZero =
117 sizeOfExpr(has(ignoringParenImpCasts(integerLiteral(equals(0)))));
122 if (WarnOnSizeOfConstant) {
124 expr(sizeOfExpr(has(ignoringParenImpCasts(ConstantExpr))),
126 .bind(
"sizeof-constant"),
131 if (WarnOnSizeOfIntegerExpression) {
132 Finder->addMatcher(sizeOfExpr(ignoringParenImpCasts(has(IntegerCallExpr)))
133 .bind(
"sizeof-integer-call"),
138 if (WarnOnSizeOfThis) {
139 Finder->addMatcher(sizeOfExpr(has(ignoringParenImpCasts(cxxThisExpr())))
140 .bind(
"sizeof-this"),
144 if (WarnOnSizeOfInLoopTermination) {
145 auto CondExpr = binaryOperator(
146 allOf(has(SizeOfExpr.bind(
"sizeof-expr")), isComparisonOperator()));
147 Finder->addMatcher(LoopCondExpr(anyOf(CondExpr, hasDescendant(CondExpr)))
153 const auto CharPtrType = pointerType(pointee(isAnyCharacter()));
154 const auto ConstStrLiteralDecl =
155 varDecl(isDefinition(), hasType(hasCanonicalType(CharPtrType)),
156 hasInitializer(ignoringParenImpCasts(stringLiteral())));
157 const auto VarWithConstStrLiteralDecl = expr(
158 hasType(hasCanonicalType(CharPtrType)),
159 ignoringParenImpCasts(declRefExpr(hasDeclaration(ConstStrLiteralDecl))));
161 sizeOfExpr(has(ignoringParenImpCasts(VarWithConstStrLiteralDecl)))
162 .bind(
"sizeof-charp"),
180 if (WarnOnSizeOfPointerToAggregate || WarnOnSizeOfPointer) {
181 const auto ArrayExpr =
182 ignoringParenImpCasts(hasType(hasCanonicalType(arrayType())));
183 const auto ArrayCastExpr = expr(anyOf(
184 unaryOperator(hasUnaryOperand(ArrayExpr), unless(hasOperatorName(
"*"))),
185 binaryOperator(hasEitherOperand(ArrayExpr)),
186 castExpr(hasSourceExpression(ArrayExpr))));
187 const auto PointerToArrayExpr =
188 hasType(hasCanonicalType(pointerType(pointee(arrayType()))));
190 const auto PointerToStructType =
191 hasUnqualifiedDesugaredType(pointerType(pointee(recordType())));
192 const auto PointerToStructExpr =
193 expr(hasType(hasCanonicalType(PointerToStructType)));
195 const auto PointerToDetectedExpr =
197 ? expr(hasType(hasUnqualifiedDesugaredType(pointerType())))
198 : expr(anyOf(ArrayCastExpr, PointerToArrayExpr,
199 PointerToStructExpr));
201 const auto ZeroLiteral = ignoringParenImpCasts(integerLiteral(equals(0)));
202 const auto SubscriptExprWithZeroIndex =
203 arraySubscriptExpr(hasIndex(ZeroLiteral));
204 const auto DerefExpr =
205 ignoringParenImpCasts(unaryOperator(hasOperatorName(
"*")));
208 expr(sizeOfExpr(has(ignoringParenImpCasts(expr(
209 PointerToDetectedExpr, unless(DerefExpr),
210 unless(SubscriptExprWithZeroIndex),
211 unless(VarWithConstStrLiteralDecl), unless(cxxThisExpr()))))))
212 .bind(
"sizeof-pointer"),
217 if (WarnOnSizeOfCompareToConstant) {
219 binaryOperator(matchers::isRelationalOperator(),
220 hasOperands(ignoringParenImpCasts(SizeOfExpr),
221 ignoringParenImpCasts(integerLiteral(anyOf(
222 equals(0), isBiggerThan(0x80000))))))
223 .bind(
"sizeof-compare-constant"),
230 has(ignoringParenImpCasts(
231 binaryOperator(hasOperatorName(
",")).bind(
"sizeof-comma-binop"))))
232 .bind(
"sizeof-comma-expr"),
242 const auto ElemType =
243 arrayType(hasElementType(recordType().bind(
"elem-type")));
244 const auto ElemPtrType = pointerType(pointee(type().bind(
"elem-ptr-type")));
245 const auto SizeofDivideExpr = binaryOperator(
246 hasOperatorName(
"/"),
248 ignoringParenImpCasts(sizeOfExpr(hasArgumentOfType(hasCanonicalType(
249 type(anyOf(ElemType, ElemPtrType, type())).bind(
"num-type")))))),
250 hasRHS(ignoringParenImpCasts(sizeOfExpr(
251 hasArgumentOfType(hasCanonicalType(type().bind(
"denom-type")))))));
253 Finder->addMatcher(SizeofDivideExpr.bind(
"sizeof-divide-expr"),
this);
256 Finder->addMatcher(binaryOperator(hasOperatorName(
"*"),
257 hasLHS(ignoringParenImpCasts(SizeOfExpr)),
258 hasRHS(ignoringParenImpCasts(SizeOfExpr)))
259 .bind(
"sizeof-multiply-sizeof"),
263 binaryOperator(hasOperatorName(
"*"),
264 hasOperands(ignoringParenImpCasts(SizeOfExpr),
265 ignoringParenImpCasts(binaryOperator(
266 hasOperatorName(
"*"),
268 ignoringParenImpCasts(SizeOfExpr))))))
269 .bind(
"sizeof-multiply-sizeof"),
274 Finder->addMatcher(sizeOfExpr(has(ignoringParenImpCasts(hasSizeOfDescendant(
275 8, allOf(SizeOfExpr, unless(SizeOfZero))))))
276 .bind(
"sizeof-sizeof-expr"),
282 const auto PtrDiffExpr = binaryOperator(
283 hasOperatorName(
"-"),
284 hasLHS(hasType(hasUnqualifiedDesugaredType(pointerType(pointee(
285 hasUnqualifiedDesugaredType(type().bind(
"left-ptr-type"))))))),
286 hasRHS(hasType(hasUnqualifiedDesugaredType(pointerType(pointee(
287 hasUnqualifiedDesugaredType(type().bind(
"right-ptr-type"))))))));
291 hasAnyOperatorName(
"==",
"!=",
"<",
"<=",
">",
">=",
"+",
"-"),
292 hasOperands(anyOf(ignoringParenImpCasts(
293 SizeOfExpr.bind(
"sizeof-ptr-mul-expr")),
294 ignoringParenImpCasts(binaryOperator(
295 hasOperatorName(
"*"),
296 hasEitherOperand(ignoringParenImpCasts(
297 SizeOfExpr.bind(
"sizeof-ptr-mul-expr")))))),
298 ignoringParenImpCasts(PtrDiffExpr)))
299 .bind(
"sizeof-in-ptr-arithmetic-mul"),
304 hasOperatorName(
"/"), hasLHS(ignoringParenImpCasts(PtrDiffExpr)),
305 hasRHS(ignoringParenImpCasts(SizeOfExpr.bind(
"sizeof-ptr-div-expr"))))
306 .bind(
"sizeof-in-ptr-arithmetic-div"),
321 const auto InterestingPtrTyForPtrArithmetic =
322 pointerType(pointee(qualType().bind(
"pointee-type")));
323 const auto SizeofLikeScaleExpr =
324 expr(anyOf(unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf)),
325 unaryExprOrTypeTraitExpr(ofKind(UETT_AlignOf)),
327 .bind(
"sizeof-in-ptr-arithmetic-scale-expr");
328 const auto PtrArithmeticIntegerScaleExpr = binaryOperator(
329 WarnOnOffsetDividedBySizeOf ? binaryOperator(hasAnyOperatorName(
"*",
"/"))
330 : binaryOperator(hasOperatorName(
"*")),
333 hasOperands(expr(hasType(isInteger()), unless(SizeofLikeScaleExpr)),
334 SizeofLikeScaleExpr));
335 const auto PtrArithmeticScaledIntegerExpr =
336 expr(anyOf(SizeofLikeScaleExpr, PtrArithmeticIntegerScaleExpr),
337 unless(SizeofDivideExpr));
341 binaryOperator(hasAnyOperatorName(
"+",
"-"),
342 hasOperands(hasType(InterestingPtrTyForPtrArithmetic),
343 PtrArithmeticScaledIntegerExpr))
344 .bind(
"sizeof-in-ptr-arithmetic-plusminus"),
345 binaryOperator(hasAnyOperatorName(
"+=",
"-="),
346 hasLHS(hasType(InterestingPtrTyForPtrArithmetic)),
347 hasRHS(PtrArithmeticScaledIntegerExpr))
348 .bind(
"sizeof-in-ptr-arithmetic-plusminus"))),
353 const ASTContext &Ctx = *Result.Context;
355 if (
const auto *E = Result.Nodes.getNodeAs<Expr>(
"sizeof-constant")) {
356 diag(E->getBeginLoc(),
"suspicious usage of 'sizeof(K)'; did you mean 'K'?")
357 << E->getSourceRange();
358 }
else if (
const auto *E =
359 Result.Nodes.getNodeAs<Expr>(
"sizeof-integer-call")) {
360 diag(E->getBeginLoc(),
"suspicious usage of 'sizeof()' on an expression "
362 << E->getSourceRange();
363 }
else if (
const auto *E = Result.Nodes.getNodeAs<Expr>(
"sizeof-this")) {
364 diag(E->getBeginLoc(),
365 "suspicious usage of 'sizeof(this)'; did you mean 'sizeof(*this)'")
366 << E->getSourceRange();
367 }
else if (
const auto *E = Result.Nodes.getNodeAs<Expr>(
"sizeof-charp")) {
368 diag(E->getBeginLoc(),
369 "suspicious usage of 'sizeof(char*)'; do you mean 'strlen'?")
370 << E->getSourceRange();
371 }
else if (Result.Nodes.getNodeAs<Stmt>(
"loop-expr")) {
372 auto *SizeofArgTy = Result.Nodes.getNodeAs<Type>(
"sizeof-arg-type");
373 if (
const auto *Member = dyn_cast<MemberPointerType>(SizeofArgTy))
374 SizeofArgTy = Member->getPointeeType().getTypePtr();
376 const auto *SzOfExpr = Result.Nodes.getNodeAs<Expr>(
"sizeof-expr");
378 if (
const auto *Type = dyn_cast<ArrayType>(SizeofArgTy)) {
381 if (!getSizeOfType(Ctx, Type->getElementType().getTypePtr()).isOne()) {
382 diag(SzOfExpr->getBeginLoc(),
383 "suspicious usage of 'sizeof' in the loop")
384 << SzOfExpr->getSourceRange();
387 }
else if (
const auto *E = Result.Nodes.getNodeAs<Expr>(
"sizeof-pointer")) {
388 diag(E->getBeginLoc(),
"suspicious usage of 'sizeof()' on an expression "
390 << E->getSourceRange();
391 }
else if (
const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(
392 "sizeof-compare-constant")) {
393 diag(E->getOperatorLoc(),
394 "suspicious comparison of 'sizeof(expr)' to a constant")
395 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
396 }
else if (
const auto *E =
397 Result.Nodes.getNodeAs<Expr>(
"sizeof-comma-expr")) {
399 Result.Nodes.getNodeAs<BinaryOperator>(
"sizeof-comma-binop");
401 diag(BO->getOperatorLoc(),
"suspicious usage of 'sizeof(..., ...)'")
402 << E->getSourceRange();
403 }
else if (
const auto *E =
404 Result.Nodes.getNodeAs<BinaryOperator>(
"sizeof-divide-expr")) {
405 const auto *NumTy = Result.Nodes.getNodeAs<Type>(
"num-type");
406 const auto *DenomTy = Result.Nodes.getNodeAs<Type>(
"denom-type");
407 const auto *ElementTy = Result.Nodes.getNodeAs<Type>(
"elem-type");
408 const auto *PointedTy = Result.Nodes.getNodeAs<Type>(
"elem-ptr-type");
410 CharUnits NumeratorSize = getSizeOfType(Ctx, NumTy);
411 CharUnits DenominatorSize = getSizeOfType(Ctx, DenomTy);
412 CharUnits ElementSize = getSizeOfType(Ctx, ElementTy);
414 if (DenominatorSize > CharUnits::Zero() &&
415 !NumeratorSize.isMultipleOf(DenominatorSize)) {
416 diag(E->getOperatorLoc(),
"suspicious usage of 'sizeof(...)/sizeof(...)';"
417 " numerator is not a multiple of denominator")
418 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
419 }
else if (ElementSize > CharUnits::Zero() &&
420 DenominatorSize > CharUnits::Zero() &&
421 ElementSize != DenominatorSize) {
423 diag(E->getOperatorLoc(),
424 "suspicious usage of 'sizeof(array)/sizeof(...)';"
425 " denominator differs from the size of array elements")
426 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
427 }
else if (NumTy && DenomTy && Ctx.hasSameType(NumTy, DenomTy) &&
428 !NumTy->isDependentType()) {
430 diag(E->getOperatorLoc(),
431 "suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions "
432 "have the same type")
433 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
434 }
else if (!WarnOnSizeOfPointer) {
436 if (PointedTy && DenomTy && Ctx.hasSameType(PointedTy, DenomTy)) {
437 diag(E->getOperatorLoc(),
438 "suspicious usage of 'sizeof(...)/sizeof(...)'; size of pointer "
439 "is divided by size of pointed type")
440 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
441 }
else if (NumTy && DenomTy && NumTy->isPointerType() &&
442 DenomTy->isPointerType()) {
443 diag(E->getOperatorLoc(),
444 "suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions "
445 "have pointer types")
446 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
449 }
else if (
const auto *E =
450 Result.Nodes.getNodeAs<Expr>(
"sizeof-sizeof-expr")) {
451 diag(E->getBeginLoc(),
"suspicious usage of 'sizeof(sizeof(...))'")
452 << E->getSourceRange();
453 }
else if (
const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(
454 "sizeof-multiply-sizeof")) {
455 diag(E->getOperatorLoc(),
"suspicious 'sizeof' by 'sizeof' multiplication")
456 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
457 }
else if (
const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(
458 "sizeof-in-ptr-arithmetic-mul")) {
459 const auto *LPtrTy = Result.Nodes.getNodeAs<Type>(
"left-ptr-type");
460 const auto *RPtrTy = Result.Nodes.getNodeAs<Type>(
"right-ptr-type");
461 const auto *SizeofArgTy = Result.Nodes.getNodeAs<Type>(
"sizeof-arg-type");
462 const auto *SizeOfExpr =
463 Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>(
"sizeof-ptr-mul-expr");
465 if (Ctx.hasSameType(LPtrTy, RPtrTy) &&
466 Ctx.hasSameType(LPtrTy, SizeofArgTy)) {
467 diag(SizeOfExpr->getBeginLoc(),
"suspicious usage of 'sizeof(...)' in "
468 "pointer arithmetic")
469 << SizeOfExpr->getSourceRange() << E->getOperatorLoc()
470 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
472 }
else if (
const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(
473 "sizeof-in-ptr-arithmetic-div")) {
474 const auto *LPtrTy = Result.Nodes.getNodeAs<Type>(
"left-ptr-type");
475 const auto *RPtrTy = Result.Nodes.getNodeAs<Type>(
"right-ptr-type");
476 const auto *SizeofArgTy = Result.Nodes.getNodeAs<Type>(
"sizeof-arg-type");
477 const auto *SizeOfExpr =
478 Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>(
"sizeof-ptr-div-expr");
480 if (Ctx.hasSameType(LPtrTy, RPtrTy) &&
481 Ctx.hasSameType(LPtrTy, SizeofArgTy)) {
482 diag(SizeOfExpr->getBeginLoc(),
"suspicious usage of 'sizeof(...)' in "
483 "pointer arithmetic")
484 << SizeOfExpr->getSourceRange() << E->getOperatorLoc()
485 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
487 }
else if (
const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(
488 "sizeof-in-ptr-arithmetic-plusminus")) {
489 const auto *PointeeTy = Result.Nodes.getNodeAs<QualType>(
"pointee-type");
490 const auto *ScaleExpr =
491 Result.Nodes.getNodeAs<Expr>(
"sizeof-in-ptr-arithmetic-scale-expr");
492 const CharUnits PointeeSize = getSizeOfType(Ctx, PointeeTy->getTypePtr());
493 const int ScaleKind = [ScaleExpr]() {
494 if (
const auto *UTTE = dyn_cast<UnaryExprOrTypeTraitExpr>(ScaleExpr))
495 switch (UTTE->getKind()) {
504 if (isa<OffsetOfExpr>(ScaleExpr))
510 if (ScaleKind != -1 && PointeeSize > CharUnits::One()) {
511 diag(E->getExprLoc(),
512 "suspicious usage of '%select{sizeof|alignof|offsetof}0(...)' in "
513 "pointer arithmetic; this scaled value will be scaled again by the "
515 << ScaleKind << E->getOpcodeStr() << ScaleExpr->getSourceRange();
516 diag(E->getExprLoc(),
517 "'%0' in pointer arithmetic internally scales with 'sizeof(%1)' == "
521 << PointeeTy->getAsString(Ctx.getPrintingPolicy())
522 << PointeeSize.getQuantity();