1//===--- SizeofExpressionCheck.cpp - clang-tidy----------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "SizeofExpressionCheck.h"
10#include "../utils/Matchers.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13
14using namespace clang::ast_matchers;
15
16namespace clang::tidy::bugprone {
17
18namespace {
19
20AST_MATCHER_P(IntegerLiteral, isBiggerThan, unsigned, N) {
21 return Node.getValue().ugt(N);
22}
23
24AST_MATCHER_P2(Expr, hasSizeOfDescendant, int, Depth,
25 ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
26 if (Depth < 0)
27 return false;
28
29 const Expr *E = Node.IgnoreParenImpCasts();
30 if (InnerMatcher.matches(Node: *E, Finder, Builder))
31 return true;
32
33 if (const auto *CE = dyn_cast<CastExpr>(Val: E)) {
34 const auto M = hasSizeOfDescendant(Depth: Depth - 1, InnerMatcher);
35 return M.matches(Node: *CE->getSubExpr(), Finder, Builder);
36 }
37 if (const auto *UE = dyn_cast<UnaryOperator>(Val: E)) {
38 const auto M = hasSizeOfDescendant(Depth: Depth - 1, InnerMatcher);
39 return M.matches(Node: *UE->getSubExpr(), Finder, Builder);
40 }
41 if (const auto *BE = dyn_cast<BinaryOperator>(Val: E)) {
42 const auto LHS = hasSizeOfDescendant(Depth: Depth - 1, InnerMatcher);
43 const auto RHS = hasSizeOfDescendant(Depth: Depth - 1, InnerMatcher);
44 return LHS.matches(Node: *BE->getLHS(), Finder, Builder) ||
45 RHS.matches(Node: *BE->getRHS(), Finder, Builder);
46 }
47
48 return false;
49}
50
51CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {
52 if (!Ty || Ty->isIncompleteType() || Ty->isDependentType() ||
53 isa<DependentSizedArrayType>(Val: Ty) || !Ty->isConstantSizeType())
54 return CharUnits::Zero();
55 return Ctx.getTypeSizeInChars(T: Ty);
56}
57
58} // namespace
59
60SizeofExpressionCheck::SizeofExpressionCheck(StringRef Name,
61 ClangTidyContext *Context)
62 : ClangTidyCheck(Name, Context),
63 WarnOnSizeOfConstant(Options.get(LocalName: "WarnOnSizeOfConstant", Default: true)),
64 WarnOnSizeOfIntegerExpression(
65 Options.get(LocalName: "WarnOnSizeOfIntegerExpression", Default: false)),
66 WarnOnSizeOfThis(Options.get(LocalName: "WarnOnSizeOfThis", Default: true)),
67 WarnOnSizeOfCompareToConstant(
68 Options.get(LocalName: "WarnOnSizeOfCompareToConstant", Default: true)),
69 WarnOnSizeOfPointerToAggregate(
70 Options.get(LocalName: "WarnOnSizeOfPointerToAggregate", Default: true)) {}
71
72void SizeofExpressionCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
73 Options.store(Options&: Opts, LocalName: "WarnOnSizeOfConstant", Value: WarnOnSizeOfConstant);
74 Options.store(Options&: Opts, LocalName: "WarnOnSizeOfIntegerExpression",
75 Value: WarnOnSizeOfIntegerExpression);
76 Options.store(Options&: Opts, LocalName: "WarnOnSizeOfThis", Value: WarnOnSizeOfThis);
77 Options.store(Options&: Opts, LocalName: "WarnOnSizeOfCompareToConstant",
78 Value: WarnOnSizeOfCompareToConstant);
79 Options.store(Options&: Opts, LocalName: "WarnOnSizeOfPointerToAggregate",
80 Value: WarnOnSizeOfPointerToAggregate);
81}
82
83void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
84 // FIXME:
85 // Some of the checks should not match in template code to avoid false
86 // positives if sizeof is applied on template argument.
87
88 const auto IntegerExpr = ignoringParenImpCasts(InnerMatcher: integerLiteral());
89 const auto ConstantExpr = ignoringParenImpCasts(
90 InnerMatcher: anyOf(integerLiteral(), unaryOperator(hasUnaryOperand(InnerMatcher: IntegerExpr)),
91 binaryOperator(hasLHS(InnerMatcher: IntegerExpr), hasRHS(InnerMatcher: IntegerExpr))));
92 const auto IntegerCallExpr = ignoringParenImpCasts(InnerMatcher: callExpr(
93 anyOf(hasType(InnerMatcher: isInteger()), hasType(InnerMatcher: hasCanonicalType(InnerMatcher: enumType()))),
94 unless(isInTemplateInstantiation())));
95 const auto SizeOfExpr = sizeOfExpr(InnerMatcher: hasArgumentOfType(
96 InnerMatcher: hasUnqualifiedDesugaredType(InnerMatcher: type().bind(ID: "sizeof-arg-type"))));
97 const auto SizeOfZero =
98 sizeOfExpr(InnerMatcher: has(ignoringParenImpCasts(InnerMatcher: integerLiteral(equals(Value: 0)))));
99
100 // Detect expression like: sizeof(ARRAYLEN);
101 // Note: The expression 'sizeof(sizeof(0))' is a portable trick used to know
102 // the sizeof size_t.
103 if (WarnOnSizeOfConstant) {
104 Finder->addMatcher(
105 NodeMatch: expr(sizeOfExpr(InnerMatcher: has(ignoringParenImpCasts(InnerMatcher: ConstantExpr))),
106 unless(SizeOfZero))
107 .bind(ID: "sizeof-constant"),
108 Action: this);
109 }
110
111 // Detect sizeof(f())
112 if (WarnOnSizeOfIntegerExpression) {
113 Finder->addMatcher(NodeMatch: sizeOfExpr(InnerMatcher: ignoringParenImpCasts(InnerMatcher: has(IntegerCallExpr)))
114 .bind(ID: "sizeof-integer-call"),
115 Action: this);
116 }
117
118 // Detect expression like: sizeof(this);
119 if (WarnOnSizeOfThis) {
120 Finder->addMatcher(NodeMatch: sizeOfExpr(InnerMatcher: has(ignoringParenImpCasts(InnerMatcher: cxxThisExpr())))
121 .bind(ID: "sizeof-this"),
122 Action: this);
123 }
124
125 // Detect sizeof(kPtr) where kPtr is 'const char* kPtr = "abc"';
126 const auto CharPtrType = pointerType(pointee(isAnyCharacter()));
127 const auto ConstStrLiteralDecl =
128 varDecl(isDefinition(), hasType(InnerMatcher: hasCanonicalType(InnerMatcher: CharPtrType)),
129 hasInitializer(InnerMatcher: ignoringParenImpCasts(InnerMatcher: stringLiteral())));
130 Finder->addMatcher(
131 NodeMatch: sizeOfExpr(InnerMatcher: has(ignoringParenImpCasts(
132 InnerMatcher: expr(hasType(InnerMatcher: hasCanonicalType(InnerMatcher: CharPtrType)),
133 ignoringParenImpCasts(InnerMatcher: declRefExpr(
134 hasDeclaration(InnerMatcher: ConstStrLiteralDecl)))))))
135 .bind(ID: "sizeof-charp"),
136 Action: this);
137
138 // Detect sizeof(ptr) where ptr points to an aggregate (i.e. sizeof(&S)).
139 // Do not find it if RHS of a 'sizeof(arr) / sizeof(arr[0])' expression.
140 if (WarnOnSizeOfPointerToAggregate) {
141 const auto ArrayExpr =
142 ignoringParenImpCasts(InnerMatcher: hasType(InnerMatcher: hasCanonicalType(InnerMatcher: arrayType())));
143 const auto ArrayCastExpr = expr(anyOf(
144 unaryOperator(hasUnaryOperand(InnerMatcher: ArrayExpr), unless(hasOperatorName(Name: "*"))),
145 binaryOperator(hasEitherOperand(InnerMatcher: ArrayExpr)),
146 castExpr(hasSourceExpression(InnerMatcher: ArrayExpr))));
147 const auto PointerToArrayExpr = ignoringParenImpCasts(
148 InnerMatcher: hasType(InnerMatcher: hasCanonicalType(InnerMatcher: pointerType(pointee(arrayType())))));
149
150 const auto StructAddrOfExpr = unaryOperator(
151 hasOperatorName(Name: "&"), hasUnaryOperand(InnerMatcher: ignoringParenImpCasts(
152 InnerMatcher: hasType(InnerMatcher: hasCanonicalType(InnerMatcher: recordType())))));
153 const auto PointerToStructType =
154 hasUnqualifiedDesugaredType(InnerMatcher: pointerType(pointee(recordType())));
155 const auto PointerToStructExpr = ignoringParenImpCasts(InnerMatcher: expr(
156 hasType(InnerMatcher: hasCanonicalType(InnerMatcher: PointerToStructType)), unless(cxxThisExpr())));
157
158 const auto ArrayOfPointersExpr = ignoringParenImpCasts(
159 InnerMatcher: hasType(InnerMatcher: hasCanonicalType(InnerMatcher: arrayType(hasElementType(pointerType()))
160 .bind(ID: "type-of-array-of-pointers"))));
161 const auto ArrayOfSamePointersExpr =
162 ignoringParenImpCasts(InnerMatcher: hasType(InnerMatcher: hasCanonicalType(
163 InnerMatcher: arrayType(equalsBoundNode(ID: "type-of-array-of-pointers")))));
164 const auto ZeroLiteral = ignoringParenImpCasts(InnerMatcher: integerLiteral(equals(Value: 0)));
165 const auto ArrayOfSamePointersZeroSubscriptExpr =
166 ignoringParenImpCasts(InnerMatcher: arraySubscriptExpr(
167 hasBase(InnerMatcher: ArrayOfSamePointersExpr), hasIndex(InnerMatcher: ZeroLiteral)));
168 const auto ArrayLengthExprDenom =
169 expr(hasParent(expr(ignoringParenImpCasts(InnerMatcher: binaryOperator(
170 hasOperatorName(Name: "/"), hasLHS(InnerMatcher: ignoringParenImpCasts(InnerMatcher: sizeOfExpr(
171 InnerMatcher: has(ArrayOfPointersExpr)))))))),
172 sizeOfExpr(InnerMatcher: has(ArrayOfSamePointersZeroSubscriptExpr)));
173
174 Finder->addMatcher(NodeMatch: expr(anyOf(sizeOfExpr(InnerMatcher: has(ignoringParenImpCasts(InnerMatcher: anyOf(
175 ArrayCastExpr, PointerToArrayExpr,
176 StructAddrOfExpr, PointerToStructExpr)))),
177 sizeOfExpr(InnerMatcher: has(PointerToStructType))),
178 unless(ArrayLengthExprDenom))
179 .bind(ID: "sizeof-pointer-to-aggregate"),
180 Action: this);
181 }
182
183 // Detect expression like: sizeof(expr) <= k for a suspicious constant 'k'.
184 if (WarnOnSizeOfCompareToConstant) {
185 Finder->addMatcher(
186 NodeMatch: binaryOperator(matchers::isRelationalOperator(),
187 hasOperands(Matcher1: ignoringParenImpCasts(InnerMatcher: SizeOfExpr),
188 Matcher2: ignoringParenImpCasts(InnerMatcher: integerLiteral(anyOf(
189 equals(Value: 0), isBiggerThan(N: 0x80000))))))
190 .bind(ID: "sizeof-compare-constant"),
191 Action: this);
192 }
193
194 // Detect expression like: sizeof(expr, expr); most likely an error.
195 Finder->addMatcher(
196 NodeMatch: sizeOfExpr(
197 InnerMatcher: has(ignoringParenImpCasts(
198 InnerMatcher: binaryOperator(hasOperatorName(Name: ",")).bind(ID: "sizeof-comma-binop"))))
199 .bind(ID: "sizeof-comma-expr"),
200 Action: this);
201
202 // Detect sizeof(...) /sizeof(...));
203 // FIXME:
204 // Re-evaluate what cases to handle by the checker.
205 // Probably any sizeof(A)/sizeof(B) should be error if
206 // 'A' is not an array (type) and 'B' the (type of the) first element of it.
207 // Except if 'A' and 'B' are non-pointers, then use the existing size division
208 // rule.
209 const auto ElemType =
210 arrayType(hasElementType(recordType().bind(ID: "elem-type")));
211 const auto ElemPtrType = pointerType(pointee(type().bind(ID: "elem-ptr-type")));
212
213 Finder->addMatcher(
214 NodeMatch: binaryOperator(
215 hasOperatorName(Name: "/"),
216 hasLHS(InnerMatcher: ignoringParenImpCasts(InnerMatcher: sizeOfExpr(InnerMatcher: hasArgumentOfType(
217 InnerMatcher: hasCanonicalType(InnerMatcher: type(anyOf(ElemType, ElemPtrType, type()))
218 .bind(ID: "num-type")))))),
219 hasRHS(InnerMatcher: ignoringParenImpCasts(InnerMatcher: sizeOfExpr(
220 InnerMatcher: hasArgumentOfType(InnerMatcher: hasCanonicalType(InnerMatcher: type().bind(ID: "denom-type")))))))
221 .bind(ID: "sizeof-divide-expr"),
222 Action: this);
223
224 // Detect expression like: sizeof(...) * sizeof(...)); most likely an error.
225 Finder->addMatcher(NodeMatch: binaryOperator(hasOperatorName(Name: "*"),
226 hasLHS(InnerMatcher: ignoringParenImpCasts(InnerMatcher: SizeOfExpr)),
227 hasRHS(InnerMatcher: ignoringParenImpCasts(InnerMatcher: SizeOfExpr)))
228 .bind(ID: "sizeof-multiply-sizeof"),
229 Action: this);
230
231 Finder->addMatcher(
232 NodeMatch: binaryOperator(hasOperatorName(Name: "*"),
233 hasOperands(Matcher1: ignoringParenImpCasts(InnerMatcher: SizeOfExpr),
234 Matcher2: ignoringParenImpCasts(InnerMatcher: binaryOperator(
235 hasOperatorName(Name: "*"),
236 hasEitherOperand(
237 InnerMatcher: ignoringParenImpCasts(InnerMatcher: SizeOfExpr))))))
238 .bind(ID: "sizeof-multiply-sizeof"),
239 Action: this);
240
241 // Detect strange double-sizeof expression like: sizeof(sizeof(...));
242 // Note: The expression 'sizeof(sizeof(0))' is accepted.
243 Finder->addMatcher(NodeMatch: sizeOfExpr(InnerMatcher: has(ignoringParenImpCasts(InnerMatcher: hasSizeOfDescendant(
244 Depth: 8, InnerMatcher: allOf(SizeOfExpr, unless(SizeOfZero))))))
245 .bind(ID: "sizeof-sizeof-expr"),
246 Action: this);
247
248 // Detect sizeof in pointer arithmetic like: N * sizeof(S) == P1 - P2 or
249 // (P1 - P2) / sizeof(S) where P1 and P2 are pointers to type S.
250 const auto PtrDiffExpr = binaryOperator(
251 hasOperatorName(Name: "-"),
252 hasLHS(InnerMatcher: hasType(InnerMatcher: hasUnqualifiedDesugaredType(InnerMatcher: pointerType(pointee(
253 hasUnqualifiedDesugaredType(InnerMatcher: type().bind(ID: "left-ptr-type"))))))),
254 hasRHS(InnerMatcher: hasType(InnerMatcher: hasUnqualifiedDesugaredType(InnerMatcher: pointerType(pointee(
255 hasUnqualifiedDesugaredType(InnerMatcher: type().bind(ID: "right-ptr-type"))))))));
256
257 Finder->addMatcher(
258 NodeMatch: binaryOperator(
259 hasAnyOperatorName("==", "!=", "<", "<=", ">", ">=", "+", "-"),
260 hasOperands(Matcher1: anyOf(ignoringParenImpCasts(
261 InnerMatcher: SizeOfExpr.bind(ID: "sizeof-ptr-mul-expr")),
262 ignoringParenImpCasts(InnerMatcher: binaryOperator(
263 hasOperatorName(Name: "*"),
264 hasEitherOperand(InnerMatcher: ignoringParenImpCasts(
265 InnerMatcher: SizeOfExpr.bind(ID: "sizeof-ptr-mul-expr")))))),
266 Matcher2: ignoringParenImpCasts(InnerMatcher: PtrDiffExpr)))
267 .bind(ID: "sizeof-in-ptr-arithmetic-mul"),
268 Action: this);
269
270 Finder->addMatcher(
271 NodeMatch: binaryOperator(
272 hasOperatorName(Name: "/"), hasLHS(InnerMatcher: ignoringParenImpCasts(InnerMatcher: PtrDiffExpr)),
273 hasRHS(InnerMatcher: ignoringParenImpCasts(InnerMatcher: SizeOfExpr.bind(ID: "sizeof-ptr-div-expr"))))
274 .bind(ID: "sizeof-in-ptr-arithmetic-div"),
275 Action: this);
276}
277
278void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {
279 const ASTContext &Ctx = *Result.Context;
280
281 if (const auto *E = Result.Nodes.getNodeAs<Expr>(ID: "sizeof-constant")) {
282 diag(E->getBeginLoc(), "suspicious usage of 'sizeof(K)'; did you mean 'K'?")
283 << E->getSourceRange();
284 } else if (const auto *E =
285 Result.Nodes.getNodeAs<Expr>(ID: "sizeof-integer-call")) {
286 diag(E->getBeginLoc(), "suspicious usage of 'sizeof()' on an expression "
287 "that results in an integer")
288 << E->getSourceRange();
289 } else if (const auto *E = Result.Nodes.getNodeAs<Expr>(ID: "sizeof-this")) {
290 diag(E->getBeginLoc(),
291 "suspicious usage of 'sizeof(this)'; did you mean 'sizeof(*this)'")
292 << E->getSourceRange();
293 } else if (const auto *E = Result.Nodes.getNodeAs<Expr>(ID: "sizeof-charp")) {
294 diag(E->getBeginLoc(),
295 "suspicious usage of 'sizeof(char*)'; do you mean 'strlen'?")
296 << E->getSourceRange();
297 } else if (const auto *E =
298 Result.Nodes.getNodeAs<Expr>(ID: "sizeof-pointer-to-aggregate")) {
299 diag(E->getBeginLoc(),
300 "suspicious usage of 'sizeof(A*)'; pointer to aggregate")
301 << E->getSourceRange();
302 } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(
303 ID: "sizeof-compare-constant")) {
304 diag(Loc: E->getOperatorLoc(),
305 Description: "suspicious comparison of 'sizeof(expr)' to a constant")
306 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
307 } else if (const auto *E =
308 Result.Nodes.getNodeAs<Expr>(ID: "sizeof-comma-expr")) {
309 const auto *BO =
310 Result.Nodes.getNodeAs<BinaryOperator>(ID: "sizeof-comma-binop");
311 assert(BO);
312 diag(Loc: BO->getOperatorLoc(), Description: "suspicious usage of 'sizeof(..., ...)'")
313 << E->getSourceRange();
314 } else if (const auto *E =
315 Result.Nodes.getNodeAs<BinaryOperator>(ID: "sizeof-divide-expr")) {
316 const auto *NumTy = Result.Nodes.getNodeAs<Type>(ID: "num-type");
317 const auto *DenomTy = Result.Nodes.getNodeAs<Type>(ID: "denom-type");
318 const auto *ElementTy = Result.Nodes.getNodeAs<Type>(ID: "elem-type");
319 const auto *PointedTy = Result.Nodes.getNodeAs<Type>(ID: "elem-ptr-type");
320
321 CharUnits NumeratorSize = getSizeOfType(Ctx, Ty: NumTy);
322 CharUnits DenominatorSize = getSizeOfType(Ctx, Ty: DenomTy);
323 CharUnits ElementSize = getSizeOfType(Ctx, Ty: ElementTy);
324
325 if (DenominatorSize > CharUnits::Zero() &&
326 !NumeratorSize.isMultipleOf(N: DenominatorSize)) {
327 diag(Loc: E->getOperatorLoc(), Description: "suspicious usage of 'sizeof(...)/sizeof(...)';"
328 " numerator is not a multiple of denominator")
329 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
330 } else if (ElementSize > CharUnits::Zero() &&
331 DenominatorSize > CharUnits::Zero() &&
332 ElementSize != DenominatorSize) {
333 diag(Loc: E->getOperatorLoc(), Description: "suspicious usage of 'sizeof(...)/sizeof(...)';"
334 " numerator is not a multiple of denominator")
335 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
336 } else if (NumTy && DenomTy && NumTy == DenomTy) {
337 diag(Loc: E->getOperatorLoc(),
338 Description: "suspicious usage of sizeof pointer 'sizeof(T)/sizeof(T)'")
339 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
340 } else if (PointedTy && DenomTy && PointedTy == DenomTy) {
341 diag(Loc: E->getOperatorLoc(),
342 Description: "suspicious usage of sizeof pointer 'sizeof(T*)/sizeof(T)'")
343 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
344 } else if (NumTy && DenomTy && NumTy->isPointerType() &&
345 DenomTy->isPointerType()) {
346 diag(Loc: E->getOperatorLoc(),
347 Description: "suspicious usage of sizeof pointer 'sizeof(P*)/sizeof(Q*)'")
348 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
349 }
350 } else if (const auto *E =
351 Result.Nodes.getNodeAs<Expr>(ID: "sizeof-sizeof-expr")) {
352 diag(E->getBeginLoc(), "suspicious usage of 'sizeof(sizeof(...))'")
353 << E->getSourceRange();
354 } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(
355 ID: "sizeof-multiply-sizeof")) {
356 diag(Loc: E->getOperatorLoc(), Description: "suspicious 'sizeof' by 'sizeof' multiplication")
357 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
358 } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(
359 ID: "sizeof-in-ptr-arithmetic-mul")) {
360 const auto *LPtrTy = Result.Nodes.getNodeAs<Type>(ID: "left-ptr-type");
361 const auto *RPtrTy = Result.Nodes.getNodeAs<Type>(ID: "right-ptr-type");
362 const auto *SizeofArgTy = Result.Nodes.getNodeAs<Type>(ID: "sizeof-arg-type");
363 const auto *SizeOfExpr =
364 Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>(ID: "sizeof-ptr-mul-expr");
365
366 if ((LPtrTy == RPtrTy) && (LPtrTy == SizeofArgTy)) {
367 diag(Loc: SizeOfExpr->getBeginLoc(), Description: "suspicious usage of 'sizeof(...)' in "
368 "pointer arithmetic")
369 << SizeOfExpr->getSourceRange() << E->getOperatorLoc()
370 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
371 }
372 } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(
373 ID: "sizeof-in-ptr-arithmetic-div")) {
374 const auto *LPtrTy = Result.Nodes.getNodeAs<Type>(ID: "left-ptr-type");
375 const auto *RPtrTy = Result.Nodes.getNodeAs<Type>(ID: "right-ptr-type");
376 const auto *SizeofArgTy = Result.Nodes.getNodeAs<Type>(ID: "sizeof-arg-type");
377 const auto *SizeOfExpr =
378 Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>(ID: "sizeof-ptr-div-expr");
379
380 if ((LPtrTy == RPtrTy) && (LPtrTy == SizeofArgTy)) {
381 diag(Loc: SizeOfExpr->getBeginLoc(), Description: "suspicious usage of 'sizeof(...)' in "
382 "pointer arithmetic")
383 << SizeOfExpr->getSourceRange() << E->getOperatorLoc()
384 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
385 }
386 }
387}
388
389} // namespace clang::tidy::bugprone
390

source code of clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp