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 | |
14 | using namespace clang::ast_matchers; |
15 | |
16 | namespace clang::tidy::bugprone { |
17 | |
18 | namespace { |
19 | |
20 | AST_MATCHER_P(IntegerLiteral, isBiggerThan, unsigned, N) { |
21 | return Node.getValue().ugt(N); |
22 | } |
23 | |
24 | AST_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 | |
51 | CharUnits 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 | |
60 | SizeofExpressionCheck::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 | |
72 | void 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 | |
83 | void 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 | |
278 | void 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 | |