ExecutedLines->operator[](FID.getHashValue()).insert(Line);
}
+static void populateExecutedLinesWithStmt(
+ const Stmt *S, SourceManager &SM,
+ std::unique_ptr<FilesToLineNumsMap> &ExecutedLines) {
+ SourceLocation Loc = S->getSourceRange().getBegin();
+ SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
+ FileID FID = SM.getFileID(ExpansionLoc);
+ unsigned LineNo = SM.getExpansionLineNumber(ExpansionLoc);
+ ExecutedLines->operator[](FID.getHashValue()).insert(LineNo);
+}
+
/// \return all executed lines including function signatures on the path
/// starting from \p N.
static std::unique_ptr<FilesToLineNumsMap>
populateExecutedLinesWithFunctionSignature(D, SM, ExecutedLines);
} else if (const Stmt *S = PathDiagnosticLocation::getStmt(N)) {
+ populateExecutedLinesWithStmt(S, SM, ExecutedLines);
+
+ // Show extra context for some parent kinds.
+ const Stmt *P = N->getParentMap().getParent(S);
+
+ // The path exploration can die before the node with the associated
+ // return statement is generated, but we do want to show the whole
+ // return.
+ if (auto *RS = dyn_cast_or_null<ReturnStmt>(P)) {
+ populateExecutedLinesWithStmt(RS, SM, ExecutedLines);
+ P = N->getParentMap().getParent(RS);
+ }
- // Otherwise: show lines associated with the processed statement.
- SourceLocation Loc = S->getSourceRange().getBegin();
- SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
- FileID FID = SM.getFileID(ExpansionLoc);
- unsigned LineNo = SM.getExpansionLineNumber(ExpansionLoc);
- ExecutedLines->operator[](FID.getHashValue()).insert(LineNo);
+ if (P && (isa<SwitchCase>(P) || isa<LabelStmt>(P)))
+ populateExecutedLinesWithStmt(P, SM, ExecutedLines);
}
N = N->getFirstPred();
--- /dev/null
+int goto_test(int input) {
+ int *p = 0;
+ if (input)
+ goto mylabel;
+ return 0;
+mylabel:
+ return *p;
+}
+
+// RUN: rm -rf %t.output
+// RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core -analyzer-output html -o %t.output %s
+// RUN: cat %t.output/* | FileCheck %s --match-full-lines
+// CHECK: var relevant_lines = {"1": {"1": 1, "2": 1, "3": 1, "4": 1, "6": 1, "7": 1}};
--- /dev/null
+enum E {
+ A, B, C
+};
+
+int f(enum E input) {
+ int *x = 0;
+ switch (input) {
+ case A:
+ return 1;
+ case B:
+ return 0;
+ case C:
+ return *x;
+ }
+}
+
+// RUN: rm -rf %t.output
+// RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core -analyzer-output html -o %t.output %s
+// RUN: cat %t.output/* | FileCheck %s --match-full-lines
+// CHECK: var relevant_lines = {"1": {"5": 1, "6": 1, "7": 1, "12": 1, "13": 1}};
--- /dev/null
+enum E {
+ A, B, C
+};
+
+int f(enum E input) {
+ int *x = 0;
+ switch (input) {
+ case A:
+ return 1;
+ case B:
+ return 0;
+ default:
+ return *x;
+ }
+}
+
+// RUN: rm -rf %t.output
+// RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core -analyzer-output html -o %t.output %s
+// RUN: cat %t.output/* | FileCheck %s --match-full-lines
+// CHECK: var relevant_lines = {"1": {"5": 1, "6": 1, "7": 1, "12": 1, "13": 1}};