diff options
author | Anna Zaks <ganna@apple.com> | 2011-09-14 17:48:01 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2011-09-14 17:48:01 +0000 |
commit | 4d353eb8af7324c0ee3736c736668f6c9b162ee0 (patch) | |
tree | 6dfc7fb26baac31742c93cb4d27f8f4b73ad7f29 | |
parent | ab9b154c93475fa55e6115774f64661737d113f9 (diff) |
[analyzer] After CFG has been linearized, we can have a situation where an ExpoledNode has an invalid SourceLocation (which has no correspondence in the source code). This commit is the first step to solve this problem.
- It adds LocationContext to the PathDiagnosticLocation object and uses it to lookup the enclosing statement with a valid location.
- So far, the LocationContext is only available when the object is constructed from the ExplodedNode.
- Already found some subtle bugs(in plist-output-alternate.m) where the intermediate diagnostic steps were not previously shown.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139703 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h | 19 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/PathDiagnostic.cpp | 34 | ||||
-rw-r--r-- | test/Analysis/plist-output-alternate.m | 187 |
3 files changed, 226 insertions, 14 deletions
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 59e26293a1..022922a74a 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -89,32 +89,35 @@ private: const Stmt *S; const Decl *D; const SourceManager *SM; + const LocationContext *LC; public: PathDiagnosticLocation() - : K(SingleLocK), S(0), D(0), SM(0) {} + : K(SingleLocK), S(0), D(0), SM(0), LC(0) {} PathDiagnosticLocation(FullSourceLoc L) - : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {} + : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()), LC(0) {} - PathDiagnosticLocation(const Stmt *s, const SourceManager &sm) - : K(StmtK), S(s), D(0), SM(&sm) {} + PathDiagnosticLocation(const Stmt *s, + const SourceManager &sm, + const LocationContext *lc = 0) + : K(StmtK), S(s), D(0), SM(&sm), LC(lc) {} /// Create a location corresponding to the next valid ExplodedNode. static PathDiagnosticLocation create(const ExplodedNode* N, const SourceManager &SM); PathDiagnosticLocation(SourceRange r, const SourceManager &sm) - : K(RangeK), R(r), S(0), D(0), SM(&sm) {} + : K(RangeK), R(r), S(0), D(0), SM(&sm), LC(0) {} PathDiagnosticLocation(const Decl *d, const SourceManager &sm) - : K(DeclK), S(0), D(d), SM(&sm) {} + : K(DeclK), S(0), D(d), SM(&sm), LC(0) {} bool operator==(const PathDiagnosticLocation &X) const { - return K == X.K && R == X.R && S == X.S && D == X.D; + return K == X.K && R == X.R && S == X.S && D == X.D && LC == X.LC; } bool operator!=(const PathDiagnosticLocation &X) const { - return K != X.K || R != X.R || S != X.S || D != X.D;; + return !(*this == X); } PathDiagnosticLocation& operator=(const PathDiagnosticLocation &X) { diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 28a6d403f5..ac9b15e743 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/ParentMap.h" #include "clang/AST/StmtCXX.h" #include "llvm/ADT/SmallString.h" @@ -137,14 +138,14 @@ PathDiagnosticLocation PathDiagnosticLocation::create(const ExplodedNode* N, while (NI) { ProgramPoint P = NI->getLocation(); - + const LocationContext *LC = P.getLocationContext(); if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P)) { - return PathDiagnosticLocation(PS->getStmt(), SM); + return PathDiagnosticLocation(PS->getStmt(), SM, LC); } else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { const Stmt *Term = BE->getSrc()->getTerminator(); assert(Term); - return PathDiagnosticLocation(Term, SM); + return PathDiagnosticLocation(Term, SM, LC); } NI = NI->succ_empty() ? 0 : *(NI->succ_begin()); } @@ -153,6 +154,28 @@ PathDiagnosticLocation PathDiagnosticLocation::create(const ExplodedNode* N, return PathDiagnosticLocation(D.getBodyRBrace(), SM); } +static SourceLocation getValidSourceLocation(const Stmt* S, + const LocationContext *LC) { + SourceLocation L = S->getLocStart(); + + // S might be a temporary statement that does not have a location in the + // source code, so find an enclosing statement and use it's location. + if (!L.isValid() && LC) { + assert(LC); + ParentMap & PM = LC->getParentMap(); + + const Stmt *PS = S; + while (!L.isValid()) { + PS = PM.getParent(PS); + L = PS->getLocStart(); + } + } + + // TODO: either change the name or uncomment the assert. + //assert(L.isValid()); + return L; +} + FullSourceLoc PathDiagnosticLocation::asLocation() const { assert(isValid()); // Note that we want a 'switch' here so that the compiler can warn us in @@ -162,7 +185,8 @@ FullSourceLoc PathDiagnosticLocation::asLocation() const { case RangeK: break; case StmtK: - return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM)); + return FullSourceLoc(getValidSourceLocation(S, LC), + const_cast<SourceManager&>(*SM)); case DeclK: return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); } @@ -205,7 +229,7 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const { case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: case Stmt::ObjCForCollectionStmtClass: { - SourceLocation L = S->getLocStart(); + SourceLocation L = getValidSourceLocation(S, LC); return SourceRange(L, L); } } diff --git a/test/Analysis/plist-output-alternate.m b/test/Analysis/plist-output-alternate.m index 67135fac36..b00a161202 100644 --- a/test/Analysis/plist-output-alternate.m +++ b/test/Analysis/plist-output-alternate.m @@ -317,6 +317,68 @@ void rdar8331641(int x) { // CHECK: <key>end</key> // CHECK: <array> // CHECK: <dict> +// CHECK: <key>line</key><integer>22</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>22</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>22</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>22</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>22</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>extended_message</key> +// CHECK: <string>Assuming 'p' is null</string> +// CHECK: <key>message</key> +// CHECK: <string>Assuming 'p' is null</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>22</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>22</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> // CHECK: <key>line</key><integer>23</integer> // CHECK: <key>col</key><integer>5</integer> // CHECK: <key>file</key><integer>0</integer> @@ -393,6 +455,68 @@ void rdar8331641(int x) { // CHECK: <key>end</key> // CHECK: <array> // CHECK: <dict> +// CHECK: <key>line</key><integer>28</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>28</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>28</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>28</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>28</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>extended_message</key> +// CHECK: <string>Assuming 'q' is null</string> +// CHECK: <key>message</key> +// CHECK: <string>Assuming 'q' is null</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>28</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>28</integer> +// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> // CHECK: <key>line</key><integer>29</integer> // CHECK: <key>col</key><integer>5</integer> // CHECK: <key>file</key><integer>0</integer> @@ -743,6 +867,68 @@ void rdar8331641(int x) { // CHECK: <key>end</key> // CHECK: <array> // CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>event</string> +// CHECK: <key>location</key> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <key>ranges</key> +// CHECK: <array> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: </array> +// CHECK: <key>extended_message</key> +// CHECK: <string>Assuming 'x' is 0</string> +// CHECK: <key>message</key> +// CHECK: <string>Assuming 'x' is 0</string> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>kind</key><string>control</string> +// CHECK: <key>edges</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>start</key> +// CHECK: <array> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: <dict> +// CHECK: <key>line</key><integer>54</integer> +// CHECK: <key>col</key><integer>7</integer> +// CHECK: <key>file</key><integer>0</integer> +// CHECK: </dict> +// CHECK: </array> +// CHECK: <key>end</key> +// CHECK: <array> +// CHECK: <dict> // CHECK: <key>line</key><integer>56</integer> // CHECK: <key>col</key><integer>10</integer> // CHECK: <key>file</key><integer>0</integer> @@ -832,4 +1018,3 @@ void rdar8331641(int x) { // CHECK: </array> // CHECK: </dict> // CHECK: </plist> - |