1 //===--- SizeofExpressionCheck.cpp - clang-tidy----------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "SizeofExpressionCheck.h"
10 #include "../utils/Matchers.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 using namespace clang::ast_matchers
;
16 namespace clang::tidy::bugprone
{
20 AST_MATCHER_P(IntegerLiteral
, isBiggerThan
, unsigned, N
) {
21 return Node
.getValue().ugt(N
);
24 AST_MATCHER_P2(Expr
, hasSizeOfDescendant
, int, Depth
,
25 ast_matchers::internal::Matcher
<Expr
>, InnerMatcher
) {
29 const Expr
*E
= Node
.IgnoreParenImpCasts();
30 if (InnerMatcher
.matches(*E
, Finder
, Builder
))
33 if (const auto *CE
= dyn_cast
<CastExpr
>(E
)) {
34 const auto M
= hasSizeOfDescendant(Depth
- 1, InnerMatcher
);
35 return M
.matches(*CE
->getSubExpr(), Finder
, Builder
);
37 if (const auto *UE
= dyn_cast
<UnaryOperator
>(E
)) {
38 const auto M
= hasSizeOfDescendant(Depth
- 1, InnerMatcher
);
39 return M
.matches(*UE
->getSubExpr(), Finder
, Builder
);
41 if (const auto *BE
= dyn_cast
<BinaryOperator
>(E
)) {
42 const auto LHS
= hasSizeOfDescendant(Depth
- 1, InnerMatcher
);
43 const auto RHS
= hasSizeOfDescendant(Depth
- 1, InnerMatcher
);
44 return LHS
.matches(*BE
->getLHS(), Finder
, Builder
) ||
45 RHS
.matches(*BE
->getRHS(), Finder
, Builder
);
51 AST_MATCHER(Expr
, offsetOfExpr
) { return isa
<OffsetOfExpr
>(Node
); }
53 CharUnits
getSizeOfType(const ASTContext
&Ctx
, const Type
*Ty
) {
54 if (!Ty
|| Ty
->isIncompleteType() || Ty
->isDependentType() ||
55 isa
<DependentSizedArrayType
>(Ty
) || !Ty
->isConstantSizeType())
56 return CharUnits::Zero();
57 return Ctx
.getTypeSizeInChars(Ty
);
62 SizeofExpressionCheck::SizeofExpressionCheck(StringRef Name
,
63 ClangTidyContext
*Context
)
64 : ClangTidyCheck(Name
, Context
),
65 WarnOnSizeOfConstant(Options
.get("WarnOnSizeOfConstant", true)),
66 WarnOnSizeOfIntegerExpression(
67 Options
.get("WarnOnSizeOfIntegerExpression", false)),
68 WarnOnSizeOfThis(Options
.get("WarnOnSizeOfThis", true)),
69 WarnOnSizeOfCompareToConstant(
70 Options
.get("WarnOnSizeOfCompareToConstant", true)),
71 WarnOnSizeOfPointerToAggregate(
72 Options
.get("WarnOnSizeOfPointerToAggregate", true)),
73 WarnOnSizeOfPointer(Options
.get("WarnOnSizeOfPointer", false)),
74 WarnOnOffsetDividedBySizeOf(
75 Options
.get("WarnOnOffsetDividedBySizeOf", true)) {}
77 void SizeofExpressionCheck::storeOptions(ClangTidyOptions::OptionMap
&Opts
) {
78 Options
.store(Opts
, "WarnOnSizeOfConstant", WarnOnSizeOfConstant
);
79 Options
.store(Opts
, "WarnOnSizeOfIntegerExpression",
80 WarnOnSizeOfIntegerExpression
);
81 Options
.store(Opts
, "WarnOnSizeOfThis", WarnOnSizeOfThis
);
82 Options
.store(Opts
, "WarnOnSizeOfCompareToConstant",
83 WarnOnSizeOfCompareToConstant
);
84 Options
.store(Opts
, "WarnOnSizeOfPointerToAggregate",
85 WarnOnSizeOfPointerToAggregate
);
86 Options
.store(Opts
, "WarnOnSizeOfPointer", WarnOnSizeOfPointer
);
87 Options
.store(Opts
, "WarnOnOffsetDividedBySizeOf",
88 WarnOnOffsetDividedBySizeOf
);
91 void SizeofExpressionCheck::registerMatchers(MatchFinder
*Finder
) {
93 // Some of the checks should not match in template code to avoid false
94 // positives if sizeof is applied on template argument.
96 const auto IntegerExpr
= ignoringParenImpCasts(integerLiteral());
97 const auto ConstantExpr
= ignoringParenImpCasts(
98 anyOf(integerLiteral(), unaryOperator(hasUnaryOperand(IntegerExpr
)),
99 binaryOperator(hasLHS(IntegerExpr
), hasRHS(IntegerExpr
))));
100 const auto IntegerCallExpr
= ignoringParenImpCasts(callExpr(
101 anyOf(hasType(isInteger()), hasType(hasCanonicalType(enumType()))),
102 unless(isInTemplateInstantiation())));
103 const auto SizeOfExpr
= sizeOfExpr(hasArgumentOfType(
104 hasUnqualifiedDesugaredType(type().bind("sizeof-arg-type"))));
105 const auto SizeOfZero
=
106 sizeOfExpr(has(ignoringParenImpCasts(integerLiteral(equals(0)))));
108 // Detect expression like: sizeof(ARRAYLEN);
109 // Note: The expression 'sizeof(sizeof(0))' is a portable trick used to know
110 // the sizeof size_t.
111 if (WarnOnSizeOfConstant
) {
113 expr(sizeOfExpr(has(ignoringParenImpCasts(ConstantExpr
))),
115 .bind("sizeof-constant"),
119 // Detect sizeof(f())
120 if (WarnOnSizeOfIntegerExpression
) {
121 Finder
->addMatcher(sizeOfExpr(ignoringParenImpCasts(has(IntegerCallExpr
)))
122 .bind("sizeof-integer-call"),
126 // Detect expression like: sizeof(this);
127 if (WarnOnSizeOfThis
) {
128 Finder
->addMatcher(sizeOfExpr(has(ignoringParenImpCasts(cxxThisExpr())))
129 .bind("sizeof-this"),
133 // Detect sizeof(kPtr) where kPtr is 'const char* kPtr = "abc"';
134 const auto CharPtrType
= pointerType(pointee(isAnyCharacter()));
135 const auto ConstStrLiteralDecl
=
136 varDecl(isDefinition(), hasType(hasCanonicalType(CharPtrType
)),
137 hasInitializer(ignoringParenImpCasts(stringLiteral())));
138 const auto VarWithConstStrLiteralDecl
= expr(
139 hasType(hasCanonicalType(CharPtrType
)),
140 ignoringParenImpCasts(declRefExpr(hasDeclaration(ConstStrLiteralDecl
))));
142 sizeOfExpr(has(ignoringParenImpCasts(VarWithConstStrLiteralDecl
)))
143 .bind("sizeof-charp"),
146 // Detect sizeof(ptr) where ptr is a pointer (CWE-467).
148 // In WarnOnSizeOfPointerToAggregate mode only report cases when ptr points
149 // to an aggregate type or ptr is an expression that (implicitly or
150 // explicitly) casts an array to a pointer type. (These are more suspicious
151 // than other sizeof(ptr) expressions because they can appear as distorted
152 // forms of the common sizeof(aggregate) expressions.)
154 // To avoid false positives, the check doesn't report expressions like
155 // 'sizeof(pp[0])' and 'sizeof(*pp)' where `pp` is a pointer-to-pointer or
156 // array of pointers. (This filters out both `sizeof(arr) / sizeof(arr[0])`
157 // expressions and other cases like `p = realloc(p, newsize * sizeof(*p));`.)
159 // Moreover this generic message is suppressed in cases that are also matched
160 // by the more concrete matchers 'sizeof-this' and 'sizeof-charp'.
161 if (WarnOnSizeOfPointerToAggregate
|| WarnOnSizeOfPointer
) {
162 const auto ArrayExpr
=
163 ignoringParenImpCasts(hasType(hasCanonicalType(arrayType())));
164 const auto ArrayCastExpr
= expr(anyOf(
165 unaryOperator(hasUnaryOperand(ArrayExpr
), unless(hasOperatorName("*"))),
166 binaryOperator(hasEitherOperand(ArrayExpr
)),
167 castExpr(hasSourceExpression(ArrayExpr
))));
168 const auto PointerToArrayExpr
=
169 hasType(hasCanonicalType(pointerType(pointee(arrayType()))));
171 const auto PointerToStructType
=
172 hasUnqualifiedDesugaredType(pointerType(pointee(recordType())));
173 const auto PointerToStructTypeWithBinding
=
174 type(PointerToStructType
).bind("struct-type");
175 const auto PointerToStructExpr
=
176 expr(hasType(hasCanonicalType(PointerToStructType
)));
178 const auto PointerToDetectedExpr
=
180 ? expr(hasType(hasUnqualifiedDesugaredType(pointerType())))
181 : expr(anyOf(ArrayCastExpr
, PointerToArrayExpr
,
182 PointerToStructExpr
));
184 const auto ZeroLiteral
= ignoringParenImpCasts(integerLiteral(equals(0)));
185 const auto SubscriptExprWithZeroIndex
=
186 arraySubscriptExpr(hasIndex(ZeroLiteral
));
187 const auto DerefExpr
=
188 ignoringParenImpCasts(unaryOperator(hasOperatorName("*")));
191 expr(sizeOfExpr(anyOf(has(ignoringParenImpCasts(
192 expr(PointerToDetectedExpr
, unless(DerefExpr
),
193 unless(SubscriptExprWithZeroIndex
),
194 unless(VarWithConstStrLiteralDecl
),
195 unless(cxxThisExpr())))),
196 has(PointerToStructTypeWithBinding
))))
197 .bind("sizeof-pointer"),
201 // Detect expression like: sizeof(expr) <= k for a suspicious constant 'k'.
202 if (WarnOnSizeOfCompareToConstant
) {
204 binaryOperator(matchers::isRelationalOperator(),
205 hasOperands(ignoringParenImpCasts(SizeOfExpr
),
206 ignoringParenImpCasts(integerLiteral(anyOf(
207 equals(0), isBiggerThan(0x80000))))))
208 .bind("sizeof-compare-constant"),
212 // Detect expression like: sizeof(expr, expr); most likely an error.
215 has(ignoringParenImpCasts(
216 binaryOperator(hasOperatorName(",")).bind("sizeof-comma-binop"))))
217 .bind("sizeof-comma-expr"),
220 // Detect sizeof(...) /sizeof(...));
222 // Re-evaluate what cases to handle by the checker.
223 // Probably any sizeof(A)/sizeof(B) should be error if
224 // 'A' is not an array (type) and 'B' the (type of the) first element of it.
225 // Except if 'A' and 'B' are non-pointers, then use the existing size division
227 const auto ElemType
=
228 arrayType(hasElementType(recordType().bind("elem-type")));
229 const auto ElemPtrType
= pointerType(pointee(type().bind("elem-ptr-type")));
230 const auto SizeofDivideExpr
= binaryOperator(
231 hasOperatorName("/"),
233 ignoringParenImpCasts(sizeOfExpr(hasArgumentOfType(hasCanonicalType(
234 type(anyOf(ElemType
, ElemPtrType
, type())).bind("num-type")))))),
235 hasRHS(ignoringParenImpCasts(sizeOfExpr(
236 hasArgumentOfType(hasCanonicalType(type().bind("denom-type")))))));
238 Finder
->addMatcher(SizeofDivideExpr
.bind("sizeof-divide-expr"), this);
240 // Detect expression like: sizeof(...) * sizeof(...)); most likely an error.
241 Finder
->addMatcher(binaryOperator(hasOperatorName("*"),
242 hasLHS(ignoringParenImpCasts(SizeOfExpr
)),
243 hasRHS(ignoringParenImpCasts(SizeOfExpr
)))
244 .bind("sizeof-multiply-sizeof"),
248 binaryOperator(hasOperatorName("*"),
249 hasOperands(ignoringParenImpCasts(SizeOfExpr
),
250 ignoringParenImpCasts(binaryOperator(
251 hasOperatorName("*"),
253 ignoringParenImpCasts(SizeOfExpr
))))))
254 .bind("sizeof-multiply-sizeof"),
257 // Detect strange double-sizeof expression like: sizeof(sizeof(...));
258 // Note: The expression 'sizeof(sizeof(0))' is accepted.
259 Finder
->addMatcher(sizeOfExpr(has(ignoringParenImpCasts(hasSizeOfDescendant(
260 8, allOf(SizeOfExpr
, unless(SizeOfZero
))))))
261 .bind("sizeof-sizeof-expr"),
264 // Detect sizeof usage in comparisons involving pointer arithmetics, such as
265 // N * sizeof(T) == P1 - P2 or (P1 - P2) / sizeof(T), where P1 and P2 are
266 // pointers to a type T.
267 const auto PtrDiffExpr
= binaryOperator(
268 hasOperatorName("-"),
269 hasLHS(hasType(hasUnqualifiedDesugaredType(pointerType(pointee(
270 hasUnqualifiedDesugaredType(type().bind("left-ptr-type"))))))),
271 hasRHS(hasType(hasUnqualifiedDesugaredType(pointerType(pointee(
272 hasUnqualifiedDesugaredType(type().bind("right-ptr-type"))))))));
276 hasAnyOperatorName("==", "!=", "<", "<=", ">", ">=", "+", "-"),
277 hasOperands(anyOf(ignoringParenImpCasts(
278 SizeOfExpr
.bind("sizeof-ptr-mul-expr")),
279 ignoringParenImpCasts(binaryOperator(
280 hasOperatorName("*"),
281 hasEitherOperand(ignoringParenImpCasts(
282 SizeOfExpr
.bind("sizeof-ptr-mul-expr")))))),
283 ignoringParenImpCasts(PtrDiffExpr
)))
284 .bind("sizeof-in-ptr-arithmetic-mul"),
289 hasOperatorName("/"), hasLHS(ignoringParenImpCasts(PtrDiffExpr
)),
290 hasRHS(ignoringParenImpCasts(SizeOfExpr
.bind("sizeof-ptr-div-expr"))))
291 .bind("sizeof-in-ptr-arithmetic-div"),
294 // SEI CERT ARR39-C. Do not add or subtract a scaled integer to a pointer.
295 // Detect sizeof, alignof and offsetof usage in pointer arithmetics where
296 // they are used to scale the numeric distance, which is scaled again by
297 // the pointer arithmetic operator. This can result in forming invalid
300 // Examples, where P is a pointer, N is some integer (both compile-time and
301 // run-time): P + sizeof(T), P + sizeof(*P), P + N * sizeof(*P).
303 // This check does not warn on cases where the pointee type is "1 byte",
304 // as those cases can often come from generics and also do not constitute a
305 // problem because the size does not affect the scale used.
306 const auto InterestingPtrTyForPtrArithmetic
=
307 pointerType(pointee(qualType().bind("pointee-type")));
308 const auto SizeofLikeScaleExpr
=
309 expr(anyOf(unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf
)),
310 unaryExprOrTypeTraitExpr(ofKind(UETT_AlignOf
)),
312 .bind("sizeof-in-ptr-arithmetic-scale-expr");
313 const auto PtrArithmeticIntegerScaleExpr
= binaryOperator(
314 WarnOnOffsetDividedBySizeOf
? binaryOperator(hasAnyOperatorName("*", "/"))
315 : binaryOperator(hasOperatorName("*")),
316 // sizeof(...) * sizeof(...) and sizeof(...) / sizeof(...) is handled
317 // by this check on another path.
318 hasOperands(expr(hasType(isInteger()), unless(SizeofLikeScaleExpr
)),
319 SizeofLikeScaleExpr
));
320 const auto PtrArithmeticScaledIntegerExpr
=
321 expr(anyOf(SizeofLikeScaleExpr
, PtrArithmeticIntegerScaleExpr
),
322 unless(SizeofDivideExpr
));
326 binaryOperator(hasAnyOperatorName("+", "-"),
327 hasOperands(hasType(InterestingPtrTyForPtrArithmetic
),
328 PtrArithmeticScaledIntegerExpr
))
329 .bind("sizeof-in-ptr-arithmetic-plusminus"),
330 binaryOperator(hasAnyOperatorName("+=", "-="),
331 hasLHS(hasType(InterestingPtrTyForPtrArithmetic
)),
332 hasRHS(PtrArithmeticScaledIntegerExpr
))
333 .bind("sizeof-in-ptr-arithmetic-plusminus"))),
337 void SizeofExpressionCheck::check(const MatchFinder::MatchResult
&Result
) {
338 const ASTContext
&Ctx
= *Result
.Context
;
340 if (const auto *E
= Result
.Nodes
.getNodeAs
<Expr
>("sizeof-constant")) {
341 diag(E
->getBeginLoc(), "suspicious usage of 'sizeof(K)'; did you mean 'K'?")
342 << E
->getSourceRange();
343 } else if (const auto *E
=
344 Result
.Nodes
.getNodeAs
<Expr
>("sizeof-integer-call")) {
345 diag(E
->getBeginLoc(), "suspicious usage of 'sizeof()' on an expression "
347 << E
->getSourceRange();
348 } else if (const auto *E
= Result
.Nodes
.getNodeAs
<Expr
>("sizeof-this")) {
349 diag(E
->getBeginLoc(),
350 "suspicious usage of 'sizeof(this)'; did you mean 'sizeof(*this)'")
351 << E
->getSourceRange();
352 } else if (const auto *E
= Result
.Nodes
.getNodeAs
<Expr
>("sizeof-charp")) {
353 diag(E
->getBeginLoc(),
354 "suspicious usage of 'sizeof(char*)'; do you mean 'strlen'?")
355 << E
->getSourceRange();
356 } else if (const auto *E
= Result
.Nodes
.getNodeAs
<Expr
>("sizeof-pointer")) {
357 if (Result
.Nodes
.getNodeAs
<Type
>("struct-type")) {
358 diag(E
->getBeginLoc(),
359 "suspicious usage of 'sizeof(A*)' on pointer-to-aggregate type; did "
360 "you mean 'sizeof(A)'?")
361 << E
->getSourceRange();
363 diag(E
->getBeginLoc(), "suspicious usage of 'sizeof()' on an expression "
365 << E
->getSourceRange();
367 } else if (const auto *E
= Result
.Nodes
.getNodeAs
<BinaryOperator
>(
368 "sizeof-compare-constant")) {
369 diag(E
->getOperatorLoc(),
370 "suspicious comparison of 'sizeof(expr)' to a constant")
371 << E
->getLHS()->getSourceRange() << E
->getRHS()->getSourceRange();
372 } else if (const auto *E
=
373 Result
.Nodes
.getNodeAs
<Expr
>("sizeof-comma-expr")) {
375 Result
.Nodes
.getNodeAs
<BinaryOperator
>("sizeof-comma-binop");
377 diag(BO
->getOperatorLoc(), "suspicious usage of 'sizeof(..., ...)'")
378 << E
->getSourceRange();
379 } else if (const auto *E
=
380 Result
.Nodes
.getNodeAs
<BinaryOperator
>("sizeof-divide-expr")) {
381 const auto *NumTy
= Result
.Nodes
.getNodeAs
<Type
>("num-type");
382 const auto *DenomTy
= Result
.Nodes
.getNodeAs
<Type
>("denom-type");
383 const auto *ElementTy
= Result
.Nodes
.getNodeAs
<Type
>("elem-type");
384 const auto *PointedTy
= Result
.Nodes
.getNodeAs
<Type
>("elem-ptr-type");
386 CharUnits NumeratorSize
= getSizeOfType(Ctx
, NumTy
);
387 CharUnits DenominatorSize
= getSizeOfType(Ctx
, DenomTy
);
388 CharUnits ElementSize
= getSizeOfType(Ctx
, ElementTy
);
390 if (DenominatorSize
> CharUnits::Zero() &&
391 !NumeratorSize
.isMultipleOf(DenominatorSize
)) {
392 diag(E
->getOperatorLoc(), "suspicious usage of 'sizeof(...)/sizeof(...)';"
393 " numerator is not a multiple of denominator")
394 << E
->getLHS()->getSourceRange() << E
->getRHS()->getSourceRange();
395 } else if (ElementSize
> CharUnits::Zero() &&
396 DenominatorSize
> CharUnits::Zero() &&
397 ElementSize
!= DenominatorSize
) {
398 // FIXME: Apparently there are no testcases that cover this branch!
399 diag(E
->getOperatorLoc(),
400 "suspicious usage of 'sizeof(array)/sizeof(...)';"
401 " denominator differs from the size of array elements")
402 << E
->getLHS()->getSourceRange() << E
->getRHS()->getSourceRange();
403 } else if (NumTy
&& DenomTy
&& NumTy
== DenomTy
&&
404 !NumTy
->isDependentType()) {
405 // Dependent type should not be compared.
406 diag(E
->getOperatorLoc(),
407 "suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions "
408 "have the same type")
409 << E
->getLHS()->getSourceRange() << E
->getRHS()->getSourceRange();
410 } else if (!WarnOnSizeOfPointer
) {
411 // When 'WarnOnSizeOfPointer' is enabled, these messages become redundant:
412 if (PointedTy
&& DenomTy
&& PointedTy
== DenomTy
) {
413 diag(E
->getOperatorLoc(),
414 "suspicious usage of 'sizeof(...)/sizeof(...)'; size of pointer "
415 "is divided by size of pointed type")
416 << E
->getLHS()->getSourceRange() << E
->getRHS()->getSourceRange();
417 } else if (NumTy
&& DenomTy
&& NumTy
->isPointerType() &&
418 DenomTy
->isPointerType()) {
419 diag(E
->getOperatorLoc(),
420 "suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions "
421 "have pointer types")
422 << E
->getLHS()->getSourceRange() << E
->getRHS()->getSourceRange();
425 } else if (const auto *E
=
426 Result
.Nodes
.getNodeAs
<Expr
>("sizeof-sizeof-expr")) {
427 diag(E
->getBeginLoc(), "suspicious usage of 'sizeof(sizeof(...))'")
428 << E
->getSourceRange();
429 } else if (const auto *E
= Result
.Nodes
.getNodeAs
<BinaryOperator
>(
430 "sizeof-multiply-sizeof")) {
431 diag(E
->getOperatorLoc(), "suspicious 'sizeof' by 'sizeof' multiplication")
432 << E
->getLHS()->getSourceRange() << E
->getRHS()->getSourceRange();
433 } else if (const auto *E
= Result
.Nodes
.getNodeAs
<BinaryOperator
>(
434 "sizeof-in-ptr-arithmetic-mul")) {
435 const auto *LPtrTy
= Result
.Nodes
.getNodeAs
<Type
>("left-ptr-type");
436 const auto *RPtrTy
= Result
.Nodes
.getNodeAs
<Type
>("right-ptr-type");
437 const auto *SizeofArgTy
= Result
.Nodes
.getNodeAs
<Type
>("sizeof-arg-type");
438 const auto *SizeOfExpr
=
439 Result
.Nodes
.getNodeAs
<UnaryExprOrTypeTraitExpr
>("sizeof-ptr-mul-expr");
441 if ((LPtrTy
== RPtrTy
) && (LPtrTy
== SizeofArgTy
)) {
442 diag(SizeOfExpr
->getBeginLoc(), "suspicious usage of 'sizeof(...)' in "
443 "pointer arithmetic")
444 << SizeOfExpr
->getSourceRange() << E
->getOperatorLoc()
445 << E
->getLHS()->getSourceRange() << E
->getRHS()->getSourceRange();
447 } else if (const auto *E
= Result
.Nodes
.getNodeAs
<BinaryOperator
>(
448 "sizeof-in-ptr-arithmetic-div")) {
449 const auto *LPtrTy
= Result
.Nodes
.getNodeAs
<Type
>("left-ptr-type");
450 const auto *RPtrTy
= Result
.Nodes
.getNodeAs
<Type
>("right-ptr-type");
451 const auto *SizeofArgTy
= Result
.Nodes
.getNodeAs
<Type
>("sizeof-arg-type");
452 const auto *SizeOfExpr
=
453 Result
.Nodes
.getNodeAs
<UnaryExprOrTypeTraitExpr
>("sizeof-ptr-div-expr");
455 if ((LPtrTy
== RPtrTy
) && (LPtrTy
== SizeofArgTy
)) {
456 diag(SizeOfExpr
->getBeginLoc(), "suspicious usage of 'sizeof(...)' in "
457 "pointer arithmetic")
458 << SizeOfExpr
->getSourceRange() << E
->getOperatorLoc()
459 << E
->getLHS()->getSourceRange() << E
->getRHS()->getSourceRange();
461 } else if (const auto *E
= Result
.Nodes
.getNodeAs
<BinaryOperator
>(
462 "sizeof-in-ptr-arithmetic-plusminus")) {
463 const auto *PointeeTy
= Result
.Nodes
.getNodeAs
<QualType
>("pointee-type");
464 const auto *ScaleExpr
=
465 Result
.Nodes
.getNodeAs
<Expr
>("sizeof-in-ptr-arithmetic-scale-expr");
466 const CharUnits PointeeSize
= getSizeOfType(Ctx
, PointeeTy
->getTypePtr());
467 const int ScaleKind
= [ScaleExpr
]() {
468 if (const auto *UTTE
= dyn_cast
<UnaryExprOrTypeTraitExpr
>(ScaleExpr
))
469 switch (UTTE
->getKind()) {
478 if (isa
<OffsetOfExpr
>(ScaleExpr
))
484 if (ScaleKind
!= -1 && PointeeSize
> CharUnits::One()) {
485 diag(E
->getExprLoc(),
486 "suspicious usage of '%select{sizeof|alignof|offsetof}0(...)' in "
487 "pointer arithmetic; this scaled value will be scaled again by the "
489 << ScaleKind
<< E
->getOpcodeStr() << ScaleExpr
->getSourceRange();
490 diag(E
->getExprLoc(),
491 "'%0' in pointer arithmetic internally scales with 'sizeof(%1)' == "
495 << PointeeTy
->getAsString(Ctx
.getPrintingPolicy())
496 << PointeeSize
.getQuantity();
501 } // namespace clang::tidy::bugprone