|
11 | 11 | //
|
12 | 12 | //===----------------------------------------------------------------------===//
|
13 | 13 |
|
14 |
| -#include "clang/Lex/Lexer.h" |
15 |
| -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
16 | 14 | #include "clang/AST/ASTContext.h"
|
17 | 15 | #include "clang/AST/Attr.h"
|
18 | 16 | #include "clang/AST/ParentMap.h"
|
19 | 17 | #include "clang/AST/RecursiveASTVisitor.h"
|
20 | 18 | #include "clang/Analysis/Analyses/LiveVariables.h"
|
| 19 | +#include "clang/Lex/Lexer.h" |
| 20 | +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
21 | 21 | #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
|
22 | 22 | #include "clang/StaticAnalyzer/Core/Checker.h"
|
23 | 23 | #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
|
24 | 24 | #include "llvm/ADT/BitVector.h"
|
| 25 | +#include "llvm/ADT/STLExtras.h" |
25 | 26 | #include "llvm/ADT/SmallString.h"
|
26 | 27 | #include "llvm/Support/SaveAndRestore.h"
|
27 | 28 |
|
@@ -408,15 +409,17 @@ class DeadStoreObs : public LiveVariables::Observer {
|
408 | 409 | // Special case: check for initializations with constants.
|
409 | 410 | //
|
410 | 411 | // e.g. : int x = 0;
|
| 412 | + // struct A = {0, 1}; |
| 413 | + // struct B = {{0}, {1, 2}}; |
411 | 414 | //
|
412 | 415 | // If x is EVER assigned a new value later, don't issue
|
413 | 416 | // a warning. This is because such initialization can be
|
414 | 417 | // due to defensive programming.
|
415 |
| - if (E->isEvaluatable(Ctx)) |
| 418 | + if (isConstant(E)) |
416 | 419 | return;
|
417 | 420 |
|
418 | 421 | if (const DeclRefExpr *DRE =
|
419 |
| - dyn_cast<DeclRefExpr>(E->IgnoreParenCasts())) |
| 422 | + dyn_cast<DeclRefExpr>(E->IgnoreParenCasts())) |
420 | 423 | if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
|
421 | 424 | // Special case: check for initialization from constant
|
422 | 425 | // variables.
|
@@ -444,6 +447,29 @@ class DeadStoreObs : public LiveVariables::Observer {
|
444 | 447 | }
|
445 | 448 | }
|
446 | 449 | }
|
| 450 | + |
| 451 | +private: |
| 452 | + /// Return true if the given init list can be interpreted as constant |
| 453 | + bool isConstant(const InitListExpr *Candidate) const { |
| 454 | + // We consider init list to be constant if each member of the list can be |
| 455 | + // interpreted as constant. |
| 456 | + return llvm::all_of(Candidate->inits(), |
| 457 | + [this](const Expr *Init) { return isConstant(Init); }); |
| 458 | + } |
| 459 | + |
| 460 | + /// Return true if the given expression can be interpreted as constant |
| 461 | + bool isConstant(const Expr *E) const { |
| 462 | + // It looks like E itself is a constant |
| 463 | + if (E->isEvaluatable(Ctx)) |
| 464 | + return true; |
| 465 | + |
| 466 | + // We should also allow defensive initialization of structs, i.e. { 0 } |
| 467 | + if (const auto *ILE = dyn_cast<InitListExpr>(E->IgnoreParenCasts())) { |
| 468 | + return isConstant(ILE); |
| 469 | + } |
| 470 | + |
| 471 | + return false; |
| 472 | + } |
447 | 473 | };
|
448 | 474 |
|
449 | 475 | } // end anonymous namespace
|
|
0 commit comments