clang 20.0.0git
IdenticalExprChecker.cpp
Go to the documentation of this file.
1//== IdenticalExprChecker.cpp - Identical expression checker----------------==//
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/// \file
10/// This defines IdenticalExprChecker, a check that warns about
11/// unintended use of identical expressions.
12///
13/// It checks for use of identical expressions with comparison operators and
14/// inside conditional expressions.
15///
16//===----------------------------------------------------------------------===//
17
24
25using namespace clang;
26using namespace ento;
27
28static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
29 const Stmt *Stmt2, bool IgnoreSideEffects = false);
30//===----------------------------------------------------------------------===//
31// FindIdenticalExprVisitor - Identify nodes using identical expressions.
32//===----------------------------------------------------------------------===//
33
34namespace {
35class FindIdenticalExprVisitor
36 : public RecursiveASTVisitor<FindIdenticalExprVisitor> {
37 BugReporter &BR;
38 const CheckerBase *Checker;
40public:
41 explicit FindIdenticalExprVisitor(BugReporter &B,
42 const CheckerBase *Checker,
44 : BR(B), Checker(Checker), AC(A) {}
45 // FindIdenticalExprVisitor only visits nodes
46 // that are binary operators, if statements or
47 // conditional operators.
48 bool VisitBinaryOperator(const BinaryOperator *B);
49 bool VisitIfStmt(const IfStmt *I);
50 bool VisitConditionalOperator(const ConditionalOperator *C);
51
52private:
53 void reportIdenticalExpr(const BinaryOperator *B, bool CheckBitwise,
55 void checkBitwiseOrLogicalOp(const BinaryOperator *B, bool CheckBitwise);
56 void checkComparisonOp(const BinaryOperator *B);
57};
58} // end anonymous namespace
59
60void FindIdenticalExprVisitor::reportIdenticalExpr(const BinaryOperator *B,
61 bool CheckBitwise,
63 StringRef Message;
64 if (CheckBitwise)
65 Message = "identical expressions on both sides of bitwise operator";
66 else
67 Message = "identical expressions on both sides of logical operator";
68
70 PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
71 BR.EmitBasicReport(AC->getDecl(), Checker,
72 "Use of identical expressions",
74 Message, ELoc, Sr);
75}
76
77void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B,
78 bool CheckBitwise) {
79 SourceRange Sr[2];
80
81 const Expr *LHS = B->getLHS();
82 const Expr *RHS = B->getRHS();
83
84 // Split operators as long as we still have operators to split on. We will
85 // get called for every binary operator in an expression so there is no need
86 // to check every one against each other here, just the right most one with
87 // the others.
88 while (const BinaryOperator *B2 = dyn_cast<BinaryOperator>(LHS)) {
89 if (B->getOpcode() != B2->getOpcode())
90 break;
91 if (isIdenticalStmt(AC->getASTContext(), RHS, B2->getRHS())) {
92 Sr[0] = RHS->getSourceRange();
93 Sr[1] = B2->getRHS()->getSourceRange();
94 reportIdenticalExpr(B, CheckBitwise, Sr);
95 }
96 LHS = B2->getLHS();
97 }
98
99 if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) {
100 Sr[0] = RHS->getSourceRange();
101 Sr[1] = LHS->getSourceRange();
102 reportIdenticalExpr(B, CheckBitwise, Sr);
103 }
104}
105
106bool FindIdenticalExprVisitor::VisitIfStmt(const IfStmt *I) {
107 const Stmt *Stmt1 = I->getThen();
108 const Stmt *Stmt2 = I->getElse();
109
110 // Check for identical inner condition:
111 //
112 // if (x<10) {
113 // if (x<10) {
114 // ..
115 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(Stmt1)) {
116 if (!CS->body_empty()) {
117 const IfStmt *InnerIf = dyn_cast<IfStmt>(*CS->body_begin());
118 if (InnerIf && isIdenticalStmt(AC->getASTContext(), I->getCond(), InnerIf->getCond(), /*IgnoreSideEffects=*/ false)) {
119 PathDiagnosticLocation ELoc(InnerIf->getCond(), BR.getSourceManager(), AC);
120 BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions",
122 "conditions of the inner and outer statements are identical",
123 ELoc);
124 }
125 }
126 }
127
128 // Check for identical conditions:
129 //
130 // if (b) {
131 // foo1();
132 // } else if (b) {
133 // foo2();
134 // }
135 if (Stmt1 && Stmt2) {
136 const Expr *Cond1 = I->getCond();
137 const Stmt *Else = Stmt2;
138 while (const IfStmt *I2 = dyn_cast_or_null<IfStmt>(Else)) {
139 const Expr *Cond2 = I2->getCond();
140 if (isIdenticalStmt(AC->getASTContext(), Cond1, Cond2, false)) {
141 SourceRange Sr = Cond1->getSourceRange();
142 PathDiagnosticLocation ELoc(Cond2, BR.getSourceManager(), AC);
143 BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions",
145 "expression is identical to previous condition",
146 ELoc, Sr);
147 }
148 Else = I2->getElse();
149 }
150 }
151
152 if (!Stmt1 || !Stmt2)
153 return true;
154
155 // Special handling for code like:
156 //
157 // if (b) {
158 // i = 1;
159 // } else
160 // i = 1;
161 if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) {
162 if (CompStmt->size() == 1)
163 Stmt1 = CompStmt->body_back();
164 }
165 if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) {
166 if (CompStmt->size() == 1)
167 Stmt2 = CompStmt->body_back();
168 }
169
170 if (isIdenticalStmt(AC->getASTContext(), Stmt1, Stmt2, true)) {
172 PathDiagnosticLocation::createBegin(I, BR.getSourceManager(), AC);
173 BR.EmitBasicReport(AC->getDecl(), Checker,
174 "Identical branches",
176 "true and false branches are identical", ELoc);
177 }
178 return true;
179}
180
181bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
183
185 checkBitwiseOrLogicalOp(B, true);
186
188 checkBitwiseOrLogicalOp(B, false);
189
191 checkComparisonOp(B);
192
193 // We want to visit ALL nodes (subexpressions of binary comparison
194 // expressions too) that contains comparison operators.
195 // True is always returned to traverse ALL nodes.
196 return true;
197}
198
199void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) {
201
202 //
203 // Special case for floating-point representation.
204 //
205 // If expressions on both sides of comparison operator are of type float,
206 // then for some comparison operators no warning shall be
207 // reported even if the expressions are identical from a symbolic point of
208 // view. Comparison between expressions, declared variables and literals
209 // are treated differently.
210 //
211 // != and == between float literals that have the same value should NOT warn.
212 // < > between float literals that have the same value SHOULD warn.
213 //
214 // != and == between the same float declaration should NOT warn.
215 // < > between the same float declaration SHOULD warn.
216 //
217 // != and == between eq. expressions that evaluates into float
218 // should NOT warn.
219 // < > between eq. expressions that evaluates into float
220 // should NOT warn.
221 //
222 const Expr *LHS = B->getLHS()->IgnoreParenImpCasts();
223 const Expr *RHS = B->getRHS()->IgnoreParenImpCasts();
224
225 const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(LHS);
226 const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(RHS);
227 const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(LHS);
228 const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(RHS);
229 if ((DeclRef1) && (DeclRef2)) {
230 if ((DeclRef1->getType()->hasFloatingRepresentation()) &&
231 (DeclRef2->getType()->hasFloatingRepresentation())) {
232 if (DeclRef1->getDecl() == DeclRef2->getDecl()) {
233 if ((Op == BO_EQ) || (Op == BO_NE)) {
234 return;
235 }
236 }
237 }
238 } else if ((FloatLit1) && (FloatLit2)) {
239 if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) {
240 if ((Op == BO_EQ) || (Op == BO_NE)) {
241 return;
242 }
243 }
244 } else if (LHS->getType()->hasFloatingRepresentation()) {
245 // If any side of comparison operator still has floating-point
246 // representation, then it's an expression. Don't warn.
247 // Here only LHS is checked since RHS will be implicit casted to float.
248 return;
249 } else {
250 // No special case with floating-point representation, report as usual.
251 }
252
253 if (isIdenticalStmt(AC->getASTContext(), B->getLHS(), B->getRHS())) {
255 PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
256 StringRef Message;
257 if (Op == BO_Cmp)
258 Message = "comparison of identical expressions always evaluates to "
259 "'equal'";
260 else if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE)))
261 Message = "comparison of identical expressions always evaluates to true";
262 else
263 Message = "comparison of identical expressions always evaluates to false";
264 BR.EmitBasicReport(AC->getDecl(), Checker,
265 "Compare of identical expressions",
266 categories::LogicError, Message, ELoc);
267 }
268}
269
270bool FindIdenticalExprVisitor::VisitConditionalOperator(
271 const ConditionalOperator *C) {
272
273 // Check if expressions in conditional expression are identical
274 // from a symbolic point of view.
275
276 if (isIdenticalStmt(AC->getASTContext(), C->getTrueExpr(),
277 C->getFalseExpr(), true)) {
280 C, BR.getSourceManager());
281
282 SourceRange Sr[2];
283 Sr[0] = C->getTrueExpr()->getSourceRange();
284 Sr[1] = C->getFalseExpr()->getSourceRange();
285 BR.EmitBasicReport(
286 AC->getDecl(), Checker,
287 "Identical expressions in conditional expression",
289 "identical expressions on both sides of ':' in conditional expression",
290 ELoc, Sr);
291 }
292 // We want to visit ALL nodes (expressions in conditional
293 // expressions too) that contains conditional operators,
294 // thus always return true to traverse ALL nodes.
295 return true;
296}
297
298/// Determines whether two statement trees are identical regarding
299/// operators and symbols.
300///
301/// Exceptions: expressions containing macros or functions with possible side
302/// effects are never considered identical.
303/// Limitations: (t + u) and (u + t) are not considered identical.
304/// t*(u + t) and t*u + t*t are not considered identical.
305///
306static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
307 const Stmt *Stmt2, bool IgnoreSideEffects) {
308
309 if (!Stmt1 || !Stmt2) {
310 return !Stmt1 && !Stmt2;
311 }
312
313 // If Stmt1 & Stmt2 are of different class then they are not
314 // identical statements.
315 if (Stmt1->getStmtClass() != Stmt2->getStmtClass())
316 return false;
317
318 const Expr *Expr1 = dyn_cast<Expr>(Stmt1);
319 const Expr *Expr2 = dyn_cast<Expr>(Stmt2);
320
321 if (Expr1 && Expr2) {
322 // If Stmt1 has side effects then don't warn even if expressions
323 // are identical.
324 if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx))
325 return false;
326 // If either expression comes from a macro then don't warn even if
327 // the expressions are identical.
328 if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID()))
329 return false;
330
331 // If all children of two expressions are identical, return true.
334 while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) {
335 if (!*I1 || !*I2 || !isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
336 return false;
337 ++I1;
338 ++I2;
339 }
340 // If there are different number of children in the statements, return
341 // false.
342 if (I1 != Expr1->child_end())
343 return false;
344 if (I2 != Expr2->child_end())
345 return false;
346 }
347
348 switch (Stmt1->getStmtClass()) {
349 default:
350 return false;
351 case Stmt::CallExprClass:
352 case Stmt::ArraySubscriptExprClass:
353 case Stmt::ArraySectionExprClass:
354 case Stmt::OMPArrayShapingExprClass:
355 case Stmt::OMPIteratorExprClass:
356 case Stmt::ImplicitCastExprClass:
357 case Stmt::ParenExprClass:
358 case Stmt::BreakStmtClass:
359 case Stmt::ContinueStmtClass:
360 case Stmt::NullStmtClass:
361 return true;
362 case Stmt::CStyleCastExprClass: {
363 const CStyleCastExpr* CastExpr1 = cast<CStyleCastExpr>(Stmt1);
364 const CStyleCastExpr* CastExpr2 = cast<CStyleCastExpr>(Stmt2);
365
366 return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten();
367 }
368 case Stmt::ReturnStmtClass: {
369 const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
370 const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
371
372 return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(),
373 ReturnStmt2->getRetValue(), IgnoreSideEffects);
374 }
375 case Stmt::ForStmtClass: {
376 const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
377 const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
378
379 if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(),
380 IgnoreSideEffects))
381 return false;
382 if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(),
383 IgnoreSideEffects))
384 return false;
385 if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(),
386 IgnoreSideEffects))
387 return false;
388 if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(),
389 IgnoreSideEffects))
390 return false;
391 return true;
392 }
393 case Stmt::DoStmtClass: {
394 const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
395 const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
396
397 if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(),
398 IgnoreSideEffects))
399 return false;
400 if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(),
401 IgnoreSideEffects))
402 return false;
403 return true;
404 }
405 case Stmt::WhileStmtClass: {
406 const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
407 const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
408
409 if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(),
410 IgnoreSideEffects))
411 return false;
412 if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(),
413 IgnoreSideEffects))
414 return false;
415 return true;
416 }
417 case Stmt::IfStmtClass: {
418 const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
419 const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
420
421 if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(),
422 IgnoreSideEffects))
423 return false;
424 if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(),
425 IgnoreSideEffects))
426 return false;
427 if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(),
428 IgnoreSideEffects))
429 return false;
430 return true;
431 }
432 case Stmt::CompoundStmtClass: {
433 const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
434 const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
435
436 if (CompStmt1->size() != CompStmt2->size())
437 return false;
438
441 while (I1 != CompStmt1->body_end() && I2 != CompStmt2->body_end()) {
442 if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
443 return false;
444 ++I1;
445 ++I2;
446 }
447
448 return true;
449 }
450 case Stmt::CompoundAssignOperatorClass:
451 case Stmt::BinaryOperatorClass: {
452 const BinaryOperator *BinOp1 = cast<BinaryOperator>(Stmt1);
453 const BinaryOperator *BinOp2 = cast<BinaryOperator>(Stmt2);
454 return BinOp1->getOpcode() == BinOp2->getOpcode();
455 }
456 case Stmt::CharacterLiteralClass: {
457 const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Stmt1);
458 const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Stmt2);
459 return CharLit1->getValue() == CharLit2->getValue();
460 }
461 case Stmt::DeclRefExprClass: {
462 const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1);
463 const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2);
464 return DeclRef1->getDecl() == DeclRef2->getDecl();
465 }
466 case Stmt::IntegerLiteralClass: {
467 const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1);
468 const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2);
469
470 llvm::APInt I1 = IntLit1->getValue();
471 llvm::APInt I2 = IntLit2->getValue();
472 if (I1.getBitWidth() != I2.getBitWidth())
473 return false;
474 return I1 == I2;
475 }
476 case Stmt::FloatingLiteralClass: {
477 const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Stmt1);
478 const FloatingLiteral *FloatLit2 = cast<FloatingLiteral>(Stmt2);
479 return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue());
480 }
481 case Stmt::StringLiteralClass: {
482 const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
483 const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
484 return StringLit1->getBytes() == StringLit2->getBytes();
485 }
486 case Stmt::MemberExprClass: {
487 const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
488 const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2);
489 return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl();
490 }
491 case Stmt::UnaryOperatorClass: {
492 const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Stmt1);
493 const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Stmt2);
494 return UnaryOp1->getOpcode() == UnaryOp2->getOpcode();
495 }
496 }
497}
498
499//===----------------------------------------------------------------------===//
500// FindIdenticalExprChecker
501//===----------------------------------------------------------------------===//
502
503namespace {
504class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> {
505public:
506 void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
507 BugReporter &BR) const {
508 FindIdenticalExprVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D));
509 Visitor.TraverseDecl(const_cast<Decl *>(D));
510 }
511};
512} // end anonymous namespace
513
514void ento::registerIdenticalExprChecker(CheckerManager &Mgr) {
515 Mgr.registerChecker<FindIdenticalExprChecker>();
516}
517
518bool ento::shouldRegisterIdenticalExprChecker(const CheckerManager &mgr) {
519 return true;
520}
const Decl * D
static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, const Stmt *Stmt2, bool IgnoreSideEffects=false)
Determines whether two statement trees are identical regarding operators and symbols.
llvm::APInt getValue() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:187
AnalysisDeclContext contains the context data for the function, method or block under analysis.
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3860
Expr * getLHS() const
Definition: Expr.h:3910
bool isComparisonOp() const
Definition: Expr.h:3961
bool isLogicalOp() const
Definition: Expr.h:3994
Expr * getRHS() const
Definition: Expr.h:3912
bool isBitwiseOp() const
Definition: Expr.h:3952
Opcode getOpcode() const
Definition: Expr.h:3905
CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style cast in C++ (C++ [expr....
Definition: Expr.h:3791
unsigned getValue() const
Definition: Expr.h:1615
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition: Stmt.h:1611
unsigned size() const
Definition: Stmt.h:1656
Stmt *const * const_body_iterator
Definition: Stmt.h:1683
body_iterator body_end()
Definition: Stmt.h:1676
body_iterator body_begin()
Definition: Stmt.h:1675
ConditionalOperator - The ?: ternary operator.
Definition: Expr.h:4213
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1265
ValueDecl * getDecl()
Definition: Expr.h:1333
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
DoStmt - This represents a 'do/while' stmt.
Definition: Stmt.h:2735
Stmt * getBody()
Definition: Stmt.h:2760
Expr * getCond()
Definition: Stmt.h:2753
QualType getTypeAsWritten() const
getTypeAsWritten - Returns the type that this expression is casting to, as written in the source code...
Definition: Expr.h:3777
This represents one expression.
Definition: Expr.h:110
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition: Expr.cpp:3070
bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects=true) const
HasSideEffects - This routine returns true for all those expressions which have any effect other than...
Definition: Expr.cpp:3567
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:277
QualType getType() const
Definition: Expr.h:142
llvm::APFloat getValue() const
Definition: Expr.h:1652
ForStmt - This represents a 'for (init;cond;inc)' stmt.
Definition: Stmt.h:2791
Stmt * getInit()
Definition: Stmt.h:2806
Stmt * getBody()
Definition: Stmt.h:2835
Expr * getInc()
Definition: Stmt.h:2834
Expr * getCond()
Definition: Stmt.h:2833
IfStmt - This represents an if/then/else.
Definition: Stmt.h:2148
Stmt * getThen()
Definition: Stmt.h:2237
Expr * getCond()
Definition: Stmt.h:2225
Stmt * getElse()
Definition: Stmt.h:2246
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3187
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition: Expr.h:3270
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition: Stmt.h:3029
Expr * getRetValue()
Definition: Stmt.h:3060
A trivial tuple used to represent a source range.
Stmt - This represents one statement.
Definition: Stmt.h:84
child_iterator child_begin()
Definition: Stmt.h:1462
StmtClass getStmtClass() const
Definition: Stmt.h:1363
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:326
child_iterator child_end()
Definition: Stmt.h:1463
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1778
StringRef getBytes() const
Allow access to clients that need the byte representation, such as ASTWriterStmt::VisitStringLiteral(...
Definition: Expr.h:1863
bool hasFloatingRepresentation() const
Determine whether this type has a floating-point representation of some sort, e.g....
Definition: Type.cpp:2258
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition: Expr.h:2188
Opcode getOpcode() const
Definition: Expr.h:2228
WhileStmt - This represents a 'while' stmt.
Definition: Stmt.h:2594
Expr * getCond()
Definition: Stmt.h:2646
Stmt * getBody()
Definition: Stmt.h:2658
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
BugReporter is a utility class for generating PathDiagnostics for analysis.
Definition: BugReporter.h:585
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
Create the location for the operator of the binary expression.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
static PathDiagnosticLocation createConditionalColonLoc(const ConditionalOperator *CO, const SourceManager &SM)
The JSON file list parser is used to communicate input to InstallAPI.
BinaryOperatorKind