NoQ created this revision.
NoQ added a reviewer: Charusso.
Herald added subscribers: cfe-commits, dkrupp, donat.nagy, Szelethus, 
mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a project: clang.

- Correctly display macro expansion and spelling locations.
- Use the same procedure to display location context call site locations.
- Display statement IDs for program points.

F9535526: Screen Shot 2019-07-11 at 5.07.05 PM.png 
<https://reviews.llvm.org/F9535526>


Repository:
  rC Clang

https://reviews.llvm.org/D64611

Files:
  clang/include/clang/Basic/JsonSupport.h
  clang/lib/Analysis/AnalysisDeclContext.cpp
  clang/lib/Analysis/ProgramPoint.cpp
  clang/test/Analysis/dump_egraph.cpp
  clang/test/Analysis/exploded-graph-rewriter/environment.dot
  clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot
  clang/test/Analysis/exploded-graph-rewriter/macros.c
  clang/test/Analysis/exploded-graph-rewriter/program_points.dot
  clang/test/Analysis/expr-inspection.c
  clang/utils/analyzer/exploded-graph-rewriter.py

Index: clang/utils/analyzer/exploded-graph-rewriter.py
===================================================================
--- clang/utils/analyzer/exploded-graph-rewriter.py
+++ clang/utils/analyzer/exploded-graph-rewriter.py
@@ -49,10 +49,16 @@
 class SourceLocation(object):
     def __init__(self, json_loc):
         super(SourceLocation, self).__init__()
+        logging.debug('json: %s' % json_loc)
         self.line = json_loc['line']
         self.col = json_loc['column']
         self.filename = os.path.basename(json_loc['file']) \
             if 'file' in json_loc else '(main file)'
+        self.spelling = SourceLocation(json_loc['spelling']) \
+            if 'spelling' in json_loc else None
+
+    def is_macro(self):
+        return self.spelling is not None
 
 
 # A deserialized program point.
@@ -65,8 +71,10 @@
             self.src_id = json_pp['src_id']
             self.dst_id = json_pp['dst_id']
         elif self.kind == 'Statement':
+            logging.debug(json_pp)
             self.stmt_kind = json_pp['stmt_kind']
             self.stmt_point_kind = json_pp['stmt_point_kind']
+            self.stmt_id = json_pp['stmt_id']
             self.pointer = json_pp['pointer']
             self.pretty = json_pp['pretty']
             self.loc = SourceLocation(json_pp['location']) \
@@ -102,7 +110,8 @@
         self.lctx_id = json_frame['lctx_id']
         self.caption = json_frame['location_context']
         self.decl = json_frame['calling']
-        self.line = json_frame['call_line']
+        self.loc = SourceLocation(json_frame['location']) \
+            if json_frame['location'] is not None else None
 
     def _key(self):
         return self.lctx_id
@@ -432,6 +441,22 @@
             return s
         return candidate
 
+    @staticmethod
+    def _make_sloc(loc):
+        if loc is None:
+            return '<i>Invalid Source Location</i>'
+
+        def make_plain_loc(loc):
+            return '%s:<b>%s</b>:<b>%s</b>' \
+                % (loc.filename, loc.line, loc.col)
+
+        if loc.is_macro():
+            return '%s <font color="royalblue1">' \
+                   '(<i>spelling at </i> %s)</font>' \
+                % (make_plain_loc(loc), make_plain_loc(loc.spelling))
+
+        return make_plain_loc(loc)
+
     def visit_begin_graph(self, graph):
         self._graph = graph
         self._dump_raw('digraph "ExplodedGraph" {\n')
@@ -457,29 +482,16 @@
             # Such statements show up only at [Pre|Post]StmtPurgeDeadSymbols
             skip_pretty = 'PurgeDeadSymbols' in p.stmt_point_kind
             stmt_color = 'cyan3'
-            if p.loc is not None:
-                self._dump('<tr><td align="left" width="0">'
-                           '%s:<b>%s</b>:<b>%s</b>:</td>'
-                           '<td align="left" width="0"><font color="%s">'
-                           '%s</font></td>'
-                           '<td align="left"><font color="%s">%s</font></td>'
-                           '<td>%s</td></tr>'
-                           % (p.loc.filename, p.loc.line,
-                              p.loc.col, color, p.stmt_kind,
-                              stmt_color, p.stmt_point_kind,
-                              self._short_pretty(p.pretty)
-                              if not skip_pretty else ''))
-            else:
-                self._dump('<tr><td align="left" width="0">'
-                           '<i>Invalid Source Location</i>:</td>'
-                           '<td align="left" width="0">'
-                           '<font color="%s">%s</font></td>'
-                           '<td align="left"><font color="%s">%s</font></td>'
-                           '<td>%s</td></tr>'
-                           % (color, p.stmt_kind,
-                              stmt_color, p.stmt_point_kind,
-                              self._short_pretty(p.pretty)
-                              if not skip_pretty else ''))
+            self._dump('<tr><td align="left" width="0">%s:</td>'
+                       '<td align="left" width="0"><font color="%s">'
+                       '%s</font> </td>'
+                       '<td align="left"><i>S%s</i></td>'
+                       '<td align="left"><font color="%s">%s</font></td>'
+                       '<td align="left">%s</td></tr>'
+                       % (self._make_sloc(p.loc), color, p.stmt_kind,
+                          p.stmt_id, stmt_color, p.stmt_point_kind,
+                          self._short_pretty(p.pretty)
+                          if not skip_pretty else ''))
         elif p.kind == 'Edge':
             self._dump('<tr><td width="0"></td>'
                        '<td align="left" width="0">'
@@ -516,8 +528,8 @@
                        '%s</td></tr>'
                        % (self._diff_plus_minus(is_added),
                           lc.caption, lc.decl,
-                          ('(line %s)' % lc.line) if lc.line is not None
-                          else ''))
+                          ('(%s)' % self._make_sloc(lc.loc))
+                          if lc.loc is not None else ''))
 
         def dump_binding(f, b, is_added=None):
             self._dump('<tr><td>%s</td>'
Index: clang/test/Analysis/expr-inspection.c
===================================================================
--- clang/test/Analysis/expr-inspection.c
+++ clang/test/Analysis/expr-inspection.c
@@ -30,7 +30,7 @@
 // CHECK-NEXT:     ]}
 // CHECK-NEXT:   ]},
 // CHECK-NEXT:   "environment": { "pointer": "{{0x[0-9a-f]+}}", "items": [
-// CHECK-NEXT:     { "lctx_id": 1, "location_context": "#0 Call", "calling": "foo", "call_line": null, "items": [
+// CHECK-NEXT:     { "lctx_id": 1, "location_context": "#0 Call", "calling": "foo", "location": null, "items": [
 // CHECK-NEXT:       { "stmt_id": {{[0-9]+}}, "pretty": "clang_analyzer_printState", "value": "&code{clang_analyzer_printState}" }
 // CHECK-NEXT:     ]}
 // CHECK-NEXT:   ]},
Index: clang/test/Analysis/exploded-graph-rewriter/program_points.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/program_points.dot
+++ clang/test/Analysis/exploded-graph-rewriter/program_points.dot
@@ -57,10 +57,11 @@
 // CHECK-SAME:     <td align="left" width="0">
 // CHECK-SAME:       <font color="cyan4">DeclRefExpr</font>
 // CHECK-SAME:     </td>
+// CHECK-SAME:     <td align="left"><i>S3</i></td>
 // CHECK-SAME:     <td align="left">
 // CHECK-SAME:       <font color="cyan3">PreStmt</font>
 // CHECK-SAME:     </td>
-// CHECK-SAME:     <td>x</td>
+// CHECK-SAME:     <td align="left">x</td>
 // CHECK-SAME:   </tr>
 // CHECK-SAME:   <tr>
 // CHECK-SAME:     <td width="0">
@@ -79,7 +80,7 @@
         "kind": "Statement",
         "stmt_kind": "DeclRefExpr",
         "stmt_point_kind": "PreStmt",
-        "stmd_id": 3,
+        "stmt_id": 3,
         "pointer": "0x3",
         "pretty": "x",
         "location": {
@@ -95,7 +96,7 @@
 // Test collapsing large pretty prints with braces.
 
 // CHECK-NEXT: <b>Program point:</b>
-// CHECK-SAME: <td>\{ ... \}</td>
+// CHECK-SAME: <td align="left">\{ ... \}</td>
 Node0x3 [shape=record,label=
  "{
     { "node_id": 3, "pointer": "0x3", "has_report": false, "is_sink": false,
@@ -104,7 +105,7 @@
         "kind": "Statement",
         "stmt_kind": "CompoundStmt",
         "stmt_point_kind": "PostStmt",
-        "stmd_id": 6,
+        "stmt_id": 6,
         "pointer": "0x6",
         "pretty": "{ very very very very very very long pretty print }",
         "location": {
Index: clang/test/Analysis/exploded-graph-rewriter/macros.c
===================================================================
--- /dev/null
+++ clang/test/Analysis/exploded-graph-rewriter/macros.c
@@ -0,0 +1,18 @@
+// FIXME: Figure out how to use %clang_analyze_cc1 with our lit.local.cfg.
+// RUN: %clang_cc1 -analyze -triple x86_64-unknown-linux-gnu \
+// RUN:                     -analyzer-checker=core \
+// RUN:                     -analyzer-dump-egraph=%t.dot %s
+// RUN: %exploded_graph_rewriter %t.dot | FileCheck %s
+// REQUIRES: asserts
+
+// FIXME: Substitution doesn't seem to work on Windows.
+// UNSUPPORTED: system-windows
+
+// CHECK: macros.c:<b>17</b>:<b>10</b>
+// CHECK-SAME: <font color="royalblue1">
+// CHECK-SAME:   (<i>spelling at </i> macros.c:<b>15</b>:<b>14</b>)
+// CHECK-SAME: </font>
+#define NULL 0
+void *foo() {
+  return NULL;
+}
Index: clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot
+++ clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot
@@ -25,7 +25,7 @@
               "location_context": "#0 Call",
               "lctx_id": 3,
               "calling": "foo",
-              "call_line": 4,
+              "location": null,
               "items": [
                 {
                   "stmt_id": 5,
@@ -76,7 +76,7 @@
               "location_context": "#0 Call",
               "lctx_id": 3,
               "calling": "foo",
-              "call_line": 4,
+              "location": null,
               "items": [
                 {
                   "stmt_id": 9,
@@ -121,7 +121,7 @@
               "location_context": "#0 Call",
               "lctx_id": 3,
               "calling": "foo",
-              "call_line": 4,
+              "location": null,
               "items": [
                 {
                   "stmt_id": 9,
Index: clang/test/Analysis/exploded-graph-rewriter/environment.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/environment.dot
+++ clang/test/Analysis/exploded-graph-rewriter/environment.dot
@@ -10,7 +10,11 @@
 // CHECK-SAME:       <b>#0 Call</b>
 // CHECK-SAME:     </td>
 // CHECK-SAME:     <td align="left" colspan="2">
-// CHECK-SAME:       <font color="gray60">foo </font>(line 4)
+// CHECK-SAME:       <font color="gray60">foo </font>
+// CHECK-SAME:       (environment.cpp:<b>4</b>:<b>6</b> 
+// CHECK-SAME:       <font color="royalblue1">
+// CHECK-SAME:         (<i>spelling at </i> environment.h:<b>7</b>:<b>8</b>)
+// CHECK-SAME:       </font>)
 // CHECK-SAME:     </td>
 // CHECK-SAME:   </tr>
 // CHECK-SAME:   <tr>
@@ -46,7 +50,16 @@
               "location_context": "#0 Call",
               "lctx_id": 3,
               "calling": "foo",
-              "call_line": 4,
+              "location": {
+                "file": "environment.cpp",
+                "line": 4,
+                "column": 6,
+                "spelling": {
+                  "file": "environment.h",
+                  "line": 7,
+                  "column": 8
+                }
+              },
               "items": [
                 {
                   "stmt_id": 5,
Index: clang/test/Analysis/dump_egraph.cpp
===================================================================
--- clang/test/Analysis/dump_egraph.cpp
+++ clang/test/Analysis/dump_egraph.cpp
@@ -18,9 +18,9 @@
   new S;
 }
 
-// CHECK: \"location_context\": \"#0 Call\", \"calling\": \"foo\", \"call_line\": null, \"items\": [\l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\{ \"stmt_id\": {{[0-9]+}}, \"kind\": \"construct into local variable\", \"argument_index\": null, \"pretty\": \"T t;\", \"value\": \"&t\"
+// CHECK: \"location_context\": \"#0 Call\", \"calling\": \"foo\", \"location\": null, \"items\": [\l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\{ \"stmt_id\": {{[0-9]+}}, \"kind\": \"construct into local variable\", \"argument_index\": null, \"pretty\": \"T t;\", \"value\": \"&t\"
 
-// CHECK: \"location_context\": \"#0 Call\", \"calling\": \"T::T\", \"call_line\": \"16\", \"items\": [\l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\{ \"init_id\": {{[0-9]+}}, \"kind\": \"construct into member variable\", \"argument_index\": null, \"pretty\": \"s\", \"value\": \"&t-\>s\"
+// CHECK: \"location_context\": \"#0 Call\", \"calling\": \"T::T\", \"location\": \{ \"line\": 16, \"column\": 5, \"file\": \"{{.*}}dump_egraph.cpp\" \}, \"items\": [\l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\{ \"init_id\": {{[0-9]+}}, \"kind\": \"construct into member variable\", \"argument_index\": null, \"pretty\": \"s\", \"value\": \"&t-\>s\"
 
 // CHECK: \"cluster\": \"t\", \"pointer\": \"{{0x[0-9a-f]+}}\", \"items\": [\l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\{ \"kind\": \"Default\", \"offset\": 0, \"value\": \"conj_$2\{int, LC5, no stmt, #1\}\"
 
Index: clang/lib/Analysis/ProgramPoint.cpp
===================================================================
--- clang/lib/Analysis/ProgramPoint.cpp
+++ clang/lib/Analysis/ProgramPoint.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Analysis/ProgramPoint.h"
+#include "clang/Basic/JsonSupport.h"
 
 using namespace clang;
 
@@ -46,19 +47,6 @@
   return printJson(llvm::errs());
 }
 
-static void printLocJson(raw_ostream &Out, SourceLocation Loc,
-                         const SourceManager &SM) {
-  Out << "\"location\": ";
-  if (!Loc.isFileID()) {
-    Out << "null";
-    return;
-  }
-
-  Out << "{ \"line\": " << SM.getExpansionLineNumber(Loc)
-      << ", \"column\": " << SM.getExpansionColumnNumber(Loc)
-      << ", \"file\": \"" << SM.getFilename(Loc) << "\" }";
-}
-
 void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
   const ASTContext &Context =
       getLocationContext()->getAnalysisDeclContext()->getASTContext();
@@ -112,16 +100,18 @@
   case ProgramPoint::PreImplicitCallKind: {
     ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
     Out << "PreCall\", \"decl\": \""
-        << PC.getDecl()->getAsFunction()->getQualifiedNameAsString() << "\", ";
-    printLocJson(Out, PC.getLocation(), SM);
+        << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()
+        << "\", \"location\": ";
+    printSourceLocationAsJson(Out, PC.getLocation(), SM);
     break;
   }
 
   case ProgramPoint::PostImplicitCallKind: {
     ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
     Out << "PostCall\", \"decl\": \""
-        << PC.getDecl()->getAsFunction()->getQualifiedNameAsString() << "\", ";
-    printLocJson(Out, PC.getLocation(), SM);
+        << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()
+        << "\", \"location\": ";
+    printSourceLocationAsJson(Out, PC.getLocation(), SM);
     break;
   }
 
@@ -153,8 +143,8 @@
 
     E.getSrc()->printTerminatorJson(Out, Context.getLangOpts(),
                                     /*AddQuotes=*/true);
-    Out << ", ";
-    printLocJson(Out, T->getBeginLoc(), SM);
+    Out << ", \"location\": ";
+    printSourceLocationAsJson(Out, T->getBeginLoc(), SM);
 
     Out << ", \"term_kind\": \"";
     if (isa<SwitchStmt>(T)) {
@@ -202,8 +192,8 @@
 
     S->printJson(Out, nullptr, PP, AddQuotes);
 
-    Out << ", ";
-    printLocJson(Out, S->getBeginLoc(), SM);
+    Out << ", \"location\": ";
+    printSourceLocationAsJson(Out, S->getBeginLoc(), SM);
 
     Out << ", \"stmt_point_kind\": \"";
     if (getAs<PreLoad>())
Index: clang/lib/Analysis/AnalysisDeclContext.cpp
===================================================================
--- clang/lib/Analysis/AnalysisDeclContext.cpp
+++ clang/lib/Analysis/AnalysisDeclContext.cpp
@@ -538,11 +538,9 @@
       else
         Out << "anonymous code";
 
-      Out << "\", \"call_line\": ";
+      Out << "\", \"location\": ";
       if (const Stmt *S = cast<StackFrameContext>(LCtx)->getCallSite()) {
-        Out << '\"';
-        printLocation(Out, SM, S->getBeginLoc());
-        Out << '\"';
+        printSourceLocationAsJson(Out, S->getBeginLoc(), SM);
       } else {
         Out << "null";
       }
@@ -555,8 +553,8 @@
     case Block:
       Out << "Invoking block\" ";
       if (const Decl *D = cast<BlockInvocationContext>(LCtx)->getDecl()) {
-        Out << ", \"decl_line\": ";
-        printLocation(Out, SM, D->getBeginLoc());
+        Out << ", \"location\": ";
+        printSourceLocationAsJson(Out, D->getBeginLoc(), SM);
         Out << ' ';
       }
       break;
Index: clang/include/clang/Basic/JsonSupport.h
===================================================================
--- clang/include/clang/Basic/JsonSupport.h
+++ clang/include/clang/Basic/JsonSupport.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_BASIC_JSONSUPPORT_H
 
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -77,6 +78,42 @@
   return '\"' + Str + '\"';
 }
 
+inline void printSourceLocationAsJson(raw_ostream &Out, SourceLocation Loc,
+                                      const SourceManager &SM,
+                                      bool AddBraces = true) {
+  // Mostly copy-pasted from SourceLocation::print.
+  if (!Loc.isValid()) {
+    Out << "null";
+    return;
+  }
+
+  if (Loc.isFileID()) {
+    PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+
+    if (PLoc.isInvalid()) {
+      Out << "null";
+      return;
+    }
+    // The macro expansion and spelling pos is identical for file locs.
+    if (AddBraces)
+      Out << "{ ";
+    Out << "\"line\": " << PLoc.getLine()
+        << ", \"column\": " << PLoc.getColumn()
+        << ", \"file\": \"" << PLoc.getFilename() << "\"";
+    if (AddBraces)
+      Out << " }";
+    return;
+  }
+
+  // We want 'location: { ..., spelling: { ... }}' but not
+  // 'location: { ... }, spelling: { ... }', hence the dance
+  // with braces.
+  Out << "{ ";
+  printSourceLocationAsJson(Out, SM.getExpansionLoc(Loc), SM, false);
+  Out << ", \"spelling\": ";
+  printSourceLocationAsJson(Out, SM.getSpellingLoc(Loc), SM, true);
+  Out << " }";
+}
 } // namespace clang
 
 #endif // LLVM_CLANG_BASIC_JSONSUPPORT_H
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to