Index: test/tools/llvm-cov/Inputs/binary-formats.canonical.json =================================================================== --- /dev/null +++ test/tools/llvm-cov/Inputs/binary-formats.canonical.json @@ -0,0 +1,38 @@ +// Metadata section +// CHECK: {"version":"1.0.0","type":"llvm.coverage.json.export","data":[ + +// Open Export +// CHECK-SAME: {"object":"{{[^\"]+}}","files":[ + +// File Object +// CHECK-SAME: {"filename":"/tmp/binary-formats.c", +// CHECK-SAME: "segments":[ +// CHECK-SAME: [4,40,100,1,1],[4,42,0,0,0]], +// CHECK-SAME: "expansions":[], + +// Verify the Summary Section for the first file +// CHECK-SAME: "summary":{ +// CHECK-SAME: "lines":{"count":1,"covered":1,"percent":100,"noncode":0}, +// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100}, +// CHECK-SAME: "regions":{"count":1,"covered":1,"notcovered":0,"percent":100}}} + +// Close Files Array +// CHECK-SAME: ], + +// Functions List +// CHECK-SAME: "functions":[ +// CHECK-SAME: {"name":"main","count":100,"regions":[ +// CHECK-SAME: [4,40,4,42,100,0,0,0] +// CHECK-SAME: ], +// CHECK-SAME: "filenames":["/tmp/binary-formats.c"] +// CHECK-SAME: }], + + +// Full Export Summary +// CHECK-SAME: "totals":{ +// CHECK-SAME: "lines":{"count":1,"covered":1,"percent":100,"noncode":0}, +// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100}, +// CHECK-SAME: "regions":{"count":1,"covered":1,"notcovered":0,"percent":100}} + +// Close the export object, data array, and root object +// CHECK-SAME: }]} Index: test/tools/llvm-cov/Inputs/highlightedRanges.json =================================================================== --- /dev/null +++ test/tools/llvm-cov/Inputs/highlightedRanges.json @@ -0,0 +1,67 @@ +// Metadata section +// CHECK: {"version":"1.0.0","type":"llvm.coverage.json.export","data":[ + +// Open Export +// CHECK-SAME: {"object":"{{[^\"]+}}","files":[ + +// File Object +// CHECK-SAME: {"filename":"/Users/bogner/code/llvm/test/tools/llvm-cov/showHighlightedRanges.cpp", +// CHECK-SAME: "segments":[ +// CHECK-SAME: [3,13,1,1,1],[5,3,0,1,1],[6,2,1,1,0],[6,2,0,0,0], +// CHECK-SAME: [8,19,1,1,1],[9,13,1,1,1],[10,11,1,1,1],[10,17,1,1,0], +// CHECK-SAME: [10,19,1,1,1],[12,7,0,1,1],[13,6,1,1,0],[14,5,0,1,1], +// CHECK-SAME: [15,4,1,1,0],[16,2,0,0,0],[18,13,1,1,1],[21,10,0,1,1], +// CHECK-SAME: [23,4,1,1,0],[23,10,1,1,1],[25,4,1,1,0],[28,19,1,1,1], +// CHECK-SAME: [28,24,1,1,0],[28,26,0,1,1],[28,29,1,1,0],[28,31,0,1,1], +// CHECK-SAME: [30,4,1,1,0],[32,16,1,1,1],[33,17,1,1,0],[34,16,0,1,1], +// CHECK-SAME: [34,21,1,1,0],[35,16,0,1,1],[36,17,1,1,0],[37,16,1,1,1], +// CHECK-SAME: [37,21,1,1,0],[38,2,0,0,0],[40,12,1,1,1],[45,2,0,0,0]] +// CHECK-SAME: "expansions":[], + +// Verify the Summary Section for the first file +// CHECK-SAME: "summary":{ +// CHECK-SAME: "lines":{"count":40,"covered":26,"percent":65,"noncode":0}, +// CHECK-SAME: "functions":{"count":4,"covered":4,"percent":100}, +// CHECK-SAME: "regions":{"count":19,"covered":11,"notcovered":8,"percent":57}}} + +// Close Files Array +// CHECK-SAME: ], + +// Functions List +// CHECK-SAME: "functions":[ +// CHECK-SAME: {"name":"_Z4funcv","count":1,"regions":[ +// CHECK-SAME: [3,13,6,2,1,0,0,0],[5,3,6,2,0,0,0,0] +// CHECK-SAME: ], +// CHECK-SAME: "filenames":["/Users/bogner/code/llvm/test/tools/llvm-cov/showHighlightedRanges.cpp"] +// CHECK-SAME: } +// CHECK-SAME: {"name":"_Z5func2i","count":1,"regions":[ +// CHECK-SAME: [8,19,16,2,1,0,0,0],[9,13,15,4,1,0,0,0], +// CHECK-SAME: [10,11,10,17,1,0,0,0],[10,19,13,6,1,0,0,0], +// CHECK-SAME: [12,7,13,6,0,0,0,0],[14,5,15,4,0,0,0,0] +// CHECK-SAME: ], +// CHECK-SAME: "filenames":["/Users/bogner/code/llvm/test/tools/llvm-cov/showHighlightedRanges.cpp"] +// CHECK-SAME: } +// CHECK-SAME: {"name":"_Z4testv","count":1,"regions":[ +// CHECK-SAME: [18,13,38,2,1,0,0,0],[21,10,23,4,0,0,0,0], +// CHECK-SAME: [23,10,25,4,1,0,0,0],[28,19,28,24,1,0,0,0], +// CHECK-SAME: [28,26,28,29,0,0,0,0],[28,31,30,4,0,0,0,0], +// CHECK-SAME: [32,16,33,17,1,0,0,0],[34,16,34,21,0,0,0,0], +// CHECK-SAME: [35,16,36,17,0,0,0,0],[37,16,37,21,1,0,0,0] +// CHECK-SAME: ], +// CHECK-SAME: "filenames":["/Users/bogner/code/llvm/test/tools/llvm-cov/showHighlightedRanges.cpp"] +// CHECK-SAME: } +// CHECK-SAME: {"name":"main","count":1,"regions":[ +// CHECK-SAME: [40,12,45,2,1,0,0,0] +// CHECK-SAME: ], +// CHECK-SAME: "filenames":["/Users/bogner/code/llvm/test/tools/llvm-cov/showHighlightedRanges.cpp"] +// CHECK-SAME: }], + + +// Full Export Summary +// CHECK-SAME: "totals":{ +// CHECK-SAME: "lines":{"count":40,"covered":26,"percent":65,"noncode":0}, +// CHECK-SAME: "functions":{"count":4,"covered":4,"percent":100}, +// CHECK-SAME: "regions":{"count":19,"covered":11,"notcovered":8,"percent":57}} + +// Close the export object, data array, and root object +// CHECK-SAME: }]} Index: test/tools/llvm-cov/Inputs/lineExecutionCounts.json =================================================================== --- /dev/null +++ test/tools/llvm-cov/Inputs/lineExecutionCounts.json @@ -0,0 +1,47 @@ +// Metadata section +// CHECK: {"version":"1.0.0","type":"llvm.coverage.json.export","data":[ + +// Open Export +// CHECK-SAME: {"object":"{{[^\"]+}}","files":[ + +// File Object +// CHECK-SAME: {"filename":"/tmp/showLineExecutionCounts.cpp", +// CHECK-SAME: "segments":[ +// CHECK-SAME: [6,24,161,1,1],[9,20,0,1,1],[11,4,161,1,0],[11,20,161,1,1], +// CHECK-SAME: [13,4,161,1,0],[15,38,16261,1,1],[15,26,161,1,0], +// CHECK-SAMEL [15,56,16100,1,1],[15,31,161,1,0],[15,66,16100,1,1], +// CHECK-SAME: [17,4,161,1,0],[19,32,161,1,1],[19,21,161,1,0],[19,48,0,1,1], +// CHECK-SAME: [19,29,161,1,0],[21,18,0,1,1],[21,14,161,1,0],[22,18,161,1,1], +// CHECK-SAME: [22,14,161,1,0],[25,2,0,0,0]], +// CHECK-SAME: "expansions":[], + +// Verify the Summary Section for the first file +// CHECK-SAME: "summary":{ +// CHECK-SAME: "lines":{"count":20,"covered":16,"percent":80,"noncode":0}, +// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100}, +// CHECK-SAME: "regions":{"count":10,"covered":7,"notcovered":3,"percent":70}}} + +// Close Files Array +// CHECK-SAME: ], + +// Functions List +// CHECK-SAME: "functions":[ +// CHECK-SAME: {"name":"main","count":161,"regions":[ +// CHECK-SAME: [6,24,25,2,161,0,0,0],[9,20,11,4,0,0,0,0], +// CHECK-SAME: [11,20,13,4,161,0,0,0],[15,38,15,26,16261,0,0,0], +// CHECK-SAME: [15,56,15,31,16100,0,0,0],[15,66,17,4,16100,0,0,0], +// CHECK-SAME: [19,32,19,21,161,0,0,0],[19,48,19,29,0,0,0,0], +// CHECK-SAME: [21,18,21,14,0,0,0,0],[22,18,22,14,161,0,0,0] +// CHECK-SAME: ], +// CHECK-SAME: "filenames":["/tmp/showLineExecutionCounts.cpp"] +// CHECK-SAME: }], + + +// Full Export Summary +// CHECK-SAME: "totals":{ +// CHECK-SAME: "lines":{"count":20,"covered":16,"percent":80,"noncode":0}, +// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100}, +// CHECK-SAME: "regions":{"count":10,"covered":7,"notcovered":3,"percent":70}} + +// Close the export object, data array, and root object +// CHECK-SAME: }]} Index: test/tools/llvm-cov/Inputs/regionMarkers.json =================================================================== --- /dev/null +++ test/tools/llvm-cov/Inputs/regionMarkers.json @@ -0,0 +1,47 @@ +// Metadata section +// CHECK: {"version":"1.0.0","type":"llvm.coverage.json.export","data":[ + +// Open Export +// CHECK-SAME: {"object":"{{[^\"]+}}","files":[ + +// File Object +// CHECK-SAME: {"filename":"/Users/bogner/code/llvm/test/tools/llvm-cov/showRegionMarkers.cpp", +// CHECK-SAME: "segments":[ +// CHECK-SAME: [3,12,1111000,1,1],[6,10,0,1,1],[8,4,1111000,1,0], +// CHECK-SAME: [8,10,1111000,1,1],[10,4,1111000,1,0],[13,19,112211000,1,1], +// CHECK-SAME: [13,26,1111000,1,0],[13,28,111100000,1,1],[13,31,1111000,1,0], +// CHECK-SAME: [13,33,111100000,1,1],[15,4,1111000,1,0],[17,16,1111000,1,1], +// CHECK-SAME: [17,21,1111000,1,0],[17,24,0,1,1],[17,29,1111000,1,0], +// CHECK-SAME: [19,9,0,1,1],[19,14,1111000,1,0],[20,9,1111000,1,1], +// CHECK-SAME: [20,14,1111000,1,0],[23,2,0,0,0]], +// CHECK-SAME: "expansions":[], + +// Verify the Summary Section for the first file +// CHECK-SAME: "summary":{ +// CHECK-SAME: "lines":{"count":21,"covered":17,"percent":80,"noncode":0}, +// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100}, +// CHECK-SAME: "regions":{"count":10,"covered":7,"notcovered":3,"percent":70}} + +// Close Files Array +// CHECK-SAME: ], + +// Functions List +// CHECK-SAME: "functions":[ +// CHECK-SAME: {"name":"main","count":1111000,"regions":[ +// CHECK-SAME: [3,12,23,2,1111000,0,0,0],[6,10,8,4,0,0,0,0], +// CHECK-SAME: [8,10,10,4,1111000,0,0,0],[13,19,13,26,112211000,0,0,0], +// CHECK-SAME: [13,28,13,31,111100000,0,0,0],[13,33,15,4,111100000,0,0,0], +// CHECK-SAME: [17,16,17,21,1111000,0,0,0],[17,24,17,29,0,0,0,0], +// CHECK-SAME: [19,9,19,14,0,0,0,0],[20,9,20,14,1111000,0,0,0] +// CHECK-SAME: ], +// CHECK-SAME: "filenames":["/Users/bogner/code/llvm/test/tools/llvm-cov/showRegionMarkers.cpp"] +// CHECK-SAME: }], + +// Full Export Summary +// CHECK-SAME: "totals":{ +// CHECK-SAME: "lines":{"count":21,"covered":17,"percent":80,"noncode":0}, +// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100}, +// CHECK-SAME: "regions":{"count":10,"covered":7,"notcovered":3,"percent":70}} + +// Close the export object, data array, and root object +// CHECK-SAME: }]} Index: test/tools/llvm-cov/Inputs/showExpansions.json =================================================================== --- /dev/null +++ test/tools/llvm-cov/Inputs/showExpansions.json @@ -0,0 +1,73 @@ +// Metadata section +// CHECK: {"version":"1.0.0","type":"llvm.coverage.json.export","data":[ + +// Open Export +// CHECK-SAME: {"object":"{{[^\"]+}}","files":[ + +// File Object +// CHECK-SAME: {"filename":"{{[^\"]+}}/showExpansions.cpp", +// CHECK-SAME: "segments":[ +// CHECK-SAME: [4,3,99,1,1],[4,6,99,1,1],[5,4,99,1,0], +// CHECK-SAME: [5,12,99,1,1],[5,13,99,1,0],[5,14,0,0,0], +// CHECK-SAME: [7,3,1,1,1],[7,6,1,1,1],[8,12,0,1,1], +// CHECK-SAME: [9,6,1,1,0],[10,4,1,1,0],[10,12,1,1,1], +// CHECK-SAME: [10,13,1,1,0],[10,14,0,0,0],[13,3,100,1,1], +// CHECK-SAME: [13,6,100,1,1],[15,7,99,1,1],[15,24,100,1,0], +// CHECK-SAME: [17,7,1,1,1],[17,20,100,1,0],[18,4,100,1,0], +// CHECK-SAME: [18,12,100,1,1],[18,13,100,1,0],[18,14,0,0,0], +// CHECK-SAME: [22,40,1,1,1],[23,19,101,1,1],[23,26,1,1,0], +// CHECK-SAME: [23,28,100,1,1],[23,31,1,1,0],[24,5,100,1,1], +// CHECK-SAME: [24,17,1,1,0],[26,2,0,0,0]], +// CHECK-SAME: "expansions":[ +// CHECK-SAME: {"source_region":[24,5,24,17,100,0,1,1], +// CHECK-SAME: "target_regions":[ +// CHECK-SAME: [22,40,26,2,1,0,0,0],[23,19,23,26,101,0,0,0], +// CHECK-SAME: [23,28,23,31,100,0,0,0],[24,5,24,17,100,0,1,1], +// CHECK-SAME: [13,3,18,14,100,1,0,0],[13,6,18,4,100,1,0,0], +// CHECK-SAME: [15,7,15,24,99,1,2,1],[17,7,17,20,1,1,3,1], +// CHECK-SAME: [18,12,18,13,100,1,0,0],[4,3,5,14,99,2,0,0], +// CHECK-SAME: [4,6,5,4,99,2,0,0],[5,12,5,13,99,2,0,0], +// CHECK-SAME: [7,3,10,14,1,3,0,0],[7,6,10,4,1,3,0,0], +// CHECK-SAME: [8,12,9,6,0,3,0,0],[10,12,10,13,1,3,0,0]], + +// Yes, 4 of the same filename in a row +// CHECK-SAME: "filenames":[ +// CHECK-SAME: "{{[^\"]+}}/showExpansions.cpp","{{[^\"]+}}/showExpansions.cpp", +// CHECK-SAME: "{{[^\"]+}}/showExpansions.cpp","{{[^\"]+}}/showExpansions.cpp"] +// CHECK-SAME: }], + +// Verify the Summary Section for the first file +// CHECK-SAME: "summary":{ +// CHECK-SAME: "lines":{"count":17,"covered":15,"percent":88,"noncode":0}, +// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100}, +// CHECK-SAME: "regions":{"count":13,"covered":12,"notcovered":1,"percent":92}} + +// Close Files Array +// CHECK-SAME: ], + +// Functions List +// CHECK-SAME: "functions":[ +// CHECK-SAME: {"name":"main","count":1,"regions":[ +// CHECK-SAME: [22,40,26,2,1,0,0,0],[23,19,23,26,101,0,0,0], +// CHECK-SAME: [23,28,23,31,100,0,0,0],[24,5,24,17,100,0,1,1], +// CHECK-SAME: [13,3,18,14,100,1,0,0],[13,6,18,4,100,1,0,0], +// CHECK-SAME: [15,7,15,24,99,1,2,1],[17,7,17,20,1,1,3,1], +// CHECK-SAME: [18,12,18,13,100,1,0,0],[4,3,5,14,99,2,0,0], +// CHECK-SAME: [4,6,5,4,99,2,0,0],[5,12,5,13,99,2,0,0], +// CHECK-SAME: [7,3,10,14,1,3,0,0],[7,6,10,4,1,3,0,0], +// CHECK-SAME: [8,12,9,6,0,3,0,0],[10,12,10,13,1,3,0,0]], +// CHECK-SAME: "filenames":[ +// CHECK-SAME: "{{[^\"]+}}/showExpansions.cpp", +// CHECK-SAME: "{{[^\"]+}}/showExpansions.cpp", +// CHECK-SAME: "{{[^\"]+}}/showExpansions.cpp", +// CHECK-SAME: "{{[^\"]+}}/showExpansions.cpp"] +// CHECK-SAME: }], + +// Full Export Summary +// CHECK-SAME: "totals":{ +// CHECK-SAME: "lines":{"count":17,"covered":15,"percent":88,"noncode":0}, +// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100}, +// CHECK-SAME: "regions":{"count":13,"covered":12,"notcovered":1,"percent":92}} + +// Close the export object, data array, and root object +// CHECK-SAME: }]} Index: test/tools/llvm-cov/Inputs/universal-binary.json =================================================================== --- /dev/null +++ test/tools/llvm-cov/Inputs/universal-binary.json @@ -0,0 +1,36 @@ +// Metadata section +// CHECK: {"version":"1.0.0","type":"llvm.coverage.json.export","data":[ + +// Open Export +// CHECK-SAME: {"object":"{{[^\"]+}}","files":[ + +// File Object +// CHECK-SAME: {"filename":"/tmp/universal-binary.c", +// CHECK-SAME: "segments":[ +// CHECK-SAME: [4,40,100,1,1],[4,42,0,0,0]], +// CHECK-SAME: "expansions":[], + +// Verify the Summary Section for the first file +// CHECK-SAME: "summary":{ +// CHECK-SAME: "lines":{"count":1,"covered":1,"percent":100,"noncode":0}, +// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100}, +// CHECK-SAME: "regions":{"count":1,"covered":1,"notcovered":0,"percent":100}} + +// Close Files Array +// CHECK-SAME: ], + +// Functions List +// CHECK-SAME: "functions":[ +// CHECK-SAME: {"name":"main","count":100,"regions":[ +// CHECK-SAME: [4,40,4,42,100,0,0,0]], +// CHECK-SAME: "filenames":["/tmp/universal-binary.c"] +// CHECK-SAME: }], + +// Full Export Summary +// CHECK-SAME: "totals":{ +// CHECK-SAME: "lines":{"count":1,"covered":1,"percent":100,"noncode":0}, +// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100}, +// CHECK-SAME: "regions":{"count":1,"covered":1,"notcovered":0,"percent":100} + +// Close the export object, data array, and root object +// CHECK-SAME: }]} Index: test/tools/llvm-cov/binary-formats.c =================================================================== --- test/tools/llvm-cov/binary-formats.c +++ test/tools/llvm-cov/binary-formats.c @@ -7,3 +7,7 @@ // RUN: llvm-cov show %S/Inputs/binary-formats.macho32l -instr-profile %t.profdata -filename-equivalence %s | FileCheck %s // RUN: llvm-cov show %S/Inputs/binary-formats.macho64l -instr-profile %t.profdata -filename-equivalence %s | FileCheck %s // RUN: llvm-cov show %S/Inputs/binary-formats.macho32b -instr-profile %t.profdata -filename-equivalence %s | FileCheck %s + +// RUN: llvm-cov export %S/Inputs/binary-formats.macho32l -instr-profile %t.profdata -filename-equivalence %s | FileCheck %S/Inputs/binary-formats.canonical.json +// RUN: llvm-cov export %S/Inputs/binary-formats.macho64l -instr-profile %t.profdata -filename-equivalence %s | FileCheck %S/Inputs/binary-formats.canonical.json +// RUN: llvm-cov export %S/Inputs/binary-formats.macho32b -instr-profile %t.profdata -filename-equivalence %s | FileCheck %S/Inputs/binary-formats.canonical.json Index: test/tools/llvm-cov/showExpansions.cpp =================================================================== --- test/tools/llvm-cov/showExpansions.cpp +++ test/tools/llvm-cov/showExpansions.cpp @@ -24,3 +24,4 @@ DO_SOMETHING(i); // CHECK-DAG: Expansion at line [[@LINE]], 5 -> 17 return 0; } +// RUN: llvm-cov export %S/Inputs/showExpansions.covmapping -instr-profile %S/Inputs/showExpansions.profdata -filename-equivalence %s 2>&1 | FileCheck %S/Inputs/showExpansions.json Index: test/tools/llvm-cov/showHighlightedRanges.cpp =================================================================== --- test/tools/llvm-cov/showHighlightedRanges.cpp +++ test/tools/llvm-cov/showHighlightedRanges.cpp @@ -43,3 +43,4 @@ func2(9); return 0; } +// RUN: llvm-cov export %S/Inputs/highlightedRanges.covmapping -instr-profile %S/Inputs/highlightedRanges.profdata -filename-equivalence %s 2>&1 | FileCheck %S/Inputs/highlightedRanges.json Index: test/tools/llvm-cov/showLineExecutionCounts.cpp =================================================================== --- test/tools/llvm-cov/showLineExecutionCounts.cpp +++ test/tools/llvm-cov/showLineExecutionCounts.cpp @@ -69,3 +69,5 @@ // HTML:
161
[[@LINE-44]]
}
 // HTML-WHOLE-FILE: 
[[@LINE-44]]
// after
 // HTML-FILTER-NOT: 
[[@LINE-45]]
// after
+
+// RUN: llvm-cov export %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -filename-equivalence -name=main %s | FileCheck %S/Inputs/lineExecutionCounts.json
Index: test/tools/llvm-cov/showRegionMarkers.cpp
===================================================================
--- test/tools/llvm-cov/showRegionMarkers.cpp
+++ test/tools/llvm-cov/showRegionMarkers.cpp
@@ -23,3 +23,5 @@
 }
 
 // RUN: llvm-cov show %S/Inputs/regionMarkers.covmapping -instr-profile %t.profdata -show-regions -dump -filename-equivalence %s 2>&1 | FileCheck %s
+
+// RUN: llvm-cov export %S/Inputs/regionMarkers.covmapping -instr-profile %t.profdata -filename-equivalence %s 2>&1  %s | FileCheck %S/Inputs/regionMarkers.json
Index: test/tools/llvm-cov/universal-binary.c
===================================================================
--- test/tools/llvm-cov/universal-binary.c
+++ test/tools/llvm-cov/universal-binary.c
@@ -5,6 +5,8 @@
 
 // RUN: llvm-profdata merge %S/Inputs/universal-binary.proftext -o %t.profdata
 // RUN: llvm-cov show %S/Inputs/universal-binary -instr-profile %t.profdata -filename-equivalence %s -arch x86_64 | FileCheck %s
+// RUN: llvm-cov export %S/Inputs/universal-binary -instr-profile %t.profdata -filename-equivalence %s -arch x86_64 | FileCheck %S/Inputs/universal-binary.json
+
 
 // RUN: not llvm-cov show %S/Inputs/universal-binary -instr-profile %t.profdata -filename-equivalence %s -arch i386 2>&1 | FileCheck --check-prefix=WRONG-ARCH %s
 // WRONG-ARCH: Failed to load coverage
Index: tools/llvm-cov/CMakeLists.txt
===================================================================
--- tools/llvm-cov/CMakeLists.txt
+++ tools/llvm-cov/CMakeLists.txt
@@ -4,6 +4,7 @@
   llvm-cov.cpp
   gcov.cpp
   CodeCoverage.cpp
+  CoverageExporterJson.cpp
   CoverageFilters.cpp
   CoverageReport.cpp
   CoverageSummaryInfo.cpp
Index: tools/llvm-cov/CodeCoverage.cpp
===================================================================
--- tools/llvm-cov/CodeCoverage.cpp
+++ tools/llvm-cov/CodeCoverage.cpp
@@ -38,6 +38,11 @@
 using namespace llvm;
 using namespace coverage;
 
+void exportCoverageDataToJson(StringRef ObjectFilename,
+                              const CoverageViewOptions &Options,
+                              const coverage::CoverageMapping &CoverageMapping,
+                              raw_ostream &OS);
+
 namespace {
 /// \brief The implementation of the coverage tool.
 class CodeCoverageTool {
@@ -46,7 +51,9 @@
     /// \brief The show command.
     Show,
     /// \brief The report command.
-    Report
+    Report,
+    /// \brief The export command.
+    Export
   };
 
   /// \brief Print the error message to the error output stream.
@@ -94,6 +101,9 @@
   int report(int argc, const char **argv,
              CommandLineParserType commandLineParser);
 
+  int export_(int argc, const char **argv,
+              CommandLineParserType commandLineParser);
+
   std::string ObjectFilename;
   CoverageViewOptions ViewOpts;
   std::string PGOFilename;
@@ -534,6 +544,8 @@
     return show(argc, argv, commandLineParser);
   case Report:
     return report(argc, argv, commandLineParser);
+  case Export:
+    return export_(argc, argv, commandLineParser);
   }
   return 0;
 }
@@ -694,6 +706,24 @@
   return 0;
 }
 
+int CodeCoverageTool::export_(int argc, const char **argv,
+                              CommandLineParserType commandLineParser) {
+
+  auto Err = commandLineParser(argc, argv);
+  if (Err)
+    return Err;
+
+  auto Coverage = load();
+  if (!Coverage) {
+    error("Could not load coverage information");
+    return 1;
+  }
+
+  exportCoverageDataToJson(ObjectFilename, ViewOpts, *Coverage.get(), outs());
+
+  return 0;
+}
+
 int showMain(int argc, const char *argv[]) {
   CodeCoverageTool Tool;
   return Tool.run(CodeCoverageTool::Show, argc, argv);
@@ -703,3 +733,8 @@
   CodeCoverageTool Tool;
   return Tool.run(CodeCoverageTool::Report, argc, argv);
 }
+
+int exportMain(int argc, const char *argv[]) {
+  CodeCoverageTool Tool;
+  return Tool.run(CodeCoverageTool::Export, argc, argv);
+}
Index: tools/llvm-cov/CoverageExporterJson.cpp
===================================================================
--- /dev/null
+++ tools/llvm-cov/CoverageExporterJson.cpp
@@ -0,0 +1,428 @@
+//===- CoverageExporterJson.cpp - Code coverage export --------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements export of a code coverage to JSON.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+//
+// The json code coverage export follows the following format
+// Root: dict => Root Element containing metadata
+// -- Data: array => Homogeneous array of one or more export objects
+// ---- Export: dict => Json representation of one CoverageMapping
+// ------ Files: array => List of objects describing coverage for files
+// -------- File: dict => Coverage for a single file
+// ---------- Segments: array => List of Segments contained in the file
+// ------------ Segment: dict => Describes a segment of the file with a counter
+// ---------- Expansions: array => List of expansion records
+// ------------ Expansion: dict => Object that descibes a single expansion
+// -------------- CountedRegion: dict => The region to be expanded
+// -------------- TargetRegions: array => List of Regions in the expansion
+// ---------------- CountedRegion: dict => Single Region in the expansion
+// ---------- Summary: dict => Object summarizing the coverage for this file
+// ------------ LineCoverage: dict => Object summarizing line coverage
+// ------------ FunctionCoverage: dict => Object summarizing function coverage
+// ------------ RegionCoverage: dict => Object summarizing region coverage
+// ------ Functions: array => List of objects describing coverage for functions
+// -------- Function: dict => Coverage info for a single function
+// ---------- Filenames: array => List of filenames that the function relates to
+// ---- Summary: dict => Object summarizing the coverage for the entire binary
+// ------ LineCoverage: dict => Object summarizing line coverage
+// ------ FunctionCoverage: dict => Object summarizing function coverage
+// ------ RegionCoverage: dict => Object summarizing region coverage
+//
+//===----------------------------------------------------------------------===//
+
+#include "CoverageSummaryInfo.h"
+#include "CoverageViewOptions.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
+#include 
+
+/// \brief Major version of the JSON Coverage Export Format.
+#define LLVM_COVERAGE_EXPORT_JSON_MAJOR 1
+
+/// \brief Minor version of the JSON Coverage Export Format.
+#define LLVM_COVERAGE_EXPORT_JSON_MINOR 0
+
+/// \brief Patch version of the JSON Coverage Export Format.
+#define LLVM_COVERAGE_EXPORT_JSON_PATCH 0
+
+/// \brief Version combined as a string.
+#define LLVM_COVERAGE_EXPORT_JSON_STR "1.0.0"
+
+/// \brief Unique type identifier for JSON coverage export.
+#define LLVM_COVERAGE_EXPORT_JSON_TYPE_STR "llvm.coverage.json.export"
+
+using namespace llvm;
+using namespace coverage;
+
+class CoverageExporterJson {
+  /// \brief A Name of the object file coverage is for.
+  StringRef ObjectFilename;
+
+  /// \brief Various options to guide the coverage renderer.
+  const CoverageViewOptions &Options;
+
+  /// \brief Output stream to print JSON to.
+  raw_ostream &OS;
+
+  /// \brief The full CoverageMapping object to export.
+  CoverageMapping Coverage;
+
+  /// \brief States that the JSON rendering machine can be in.
+  enum JsonState { None, NonEmptyElement, EmptyElement };
+
+  /// \brief Tracks state of the JSON output.
+  std::stack State;
+
+  /// \brief Get the object filename.
+  StringRef getObjectFilename() const { return ObjectFilename; }
+
+  /// \brief Retrieve the CoverageViewOptions.
+  const CoverageViewOptions &getOptions() const { return Options; }
+
+  /// \brief Emit a serialized scalar.
+  void emitSerialized(const int64_t &value) { OS << value; }
+
+  /// \brief Emit a serialized string.
+  void emitSerialized(const std::string &value) { OS << "\"" << value << "\""; }
+
+  /// \brief Emit a comma if there is a previous element to delimit.
+  void emitComma() {
+    if (State.top() == JsonState::NonEmptyElement) {
+      OS << ",";
+    } else if (State.top() == JsonState::EmptyElement) {
+      State.pop();
+      assert((State.size() >= 1) && "Closed too many JSON elements");
+      State.push(JsonState::NonEmptyElement);
+    }
+  }
+
+  /// \brief Emit a starting dictionary/object character.
+  void emitDictStart() {
+    emitComma();
+    State.push(JsonState::EmptyElement);
+    OS << "{";
+  }
+
+  /// \brief Emit a dictionary/object key but no value.
+  void emitDictKey(const std::string &key) {
+    emitComma();
+    OS << "\"" << key << "\":";
+    State.pop();
+    assert((State.size() >= 1) && "Closed too many JSON elements");
+
+    // We do not want to emit a comma after this key.
+    State.push(JsonState::EmptyElement);
+  }
+
+  /// \brief Emit a dictionary/object key/value pair.
+  template 
+  void emitDictElement(const std::string &key, const V &Value) {
+    emitComma();
+    emitSerialized(key);
+    OS << ":";
+    emitSerialized(Value);
+  }
+
+  /// \brief Emit a closing dictionary/object character.
+  void emitDictEnd() {
+    State.pop();
+    assert((State.size() >= 1) && "Closed too many JSON elements");
+    OS << "}";
+  }
+
+  /// \brief Emit a starting array character.
+  void emitArrayStart() {
+    emitComma();
+    State.push(JsonState::EmptyElement);
+    OS << "[";
+  }
+
+  /// \brief Emit an array element.
+  template  void emitArrayElement(const V &Value) {
+    emitComma();
+    emitSerialized(Value);
+  }
+
+  /// \brief emit a closing array character.
+  void emitArrayEnd() {
+    State.pop();
+    assert((State.size() >= 1) && "Closed too many JSON elements");
+    OS << "]";
+  }
+
+  /// \brief Render the CoverageMapping object.
+  void renderRoot() {
+    // Start Root of JSON object.
+    emitDictStart();
+
+    emitDictElement("version", LLVM_COVERAGE_EXPORT_JSON_STR);
+    emitDictElement("type", LLVM_COVERAGE_EXPORT_JSON_TYPE_STR);
+    emitDictKey("data");
+
+    // Start List of Exports.
+    emitArrayStart();
+
+    // Start Export.
+    emitDictStart();
+    emitDictElement("object", getObjectFilename());
+
+    emitDictKey("files");
+    FileCoverageSummary Totals = FileCoverageSummary("Totals");
+    renderFiles(Coverage.getUniqueSourceFiles(), Totals);
+
+    emitDictKey("functions");
+    renderFunctions(Coverage.getCoveredFunctions());
+
+    emitDictKey("totals");
+    renderSummary(Totals);
+
+    // End Export.
+    emitDictEnd();
+
+    // End List of Exports.
+    emitArrayEnd();
+
+    // End Root of JSON Object.
+    emitDictEnd();
+
+    assert((State.top() == JsonState::None) &&
+           "All Elements In JSON were Closed");
+  };
+
+  /// \brief Render an array of all the given functions.
+  void renderFunctions(iterator_range) {
+    // Start List of Functions.
+    emitArrayStart();
+
+    for (const auto &Function : Coverage.getCoveredFunctions()) {
+      // Start Function.
+      emitDictStart();
+
+      emitDictElement("name", Function.Name);
+      emitDictElement("count", Function.ExecutionCount);
+      emitDictKey("regions");
+
+      renderRegions(Function.CountedRegions);
+
+      emitDictKey("filenames");
+
+      // Start Filenames for Function.
+      emitArrayStart();
+
+      for (const auto &FileName : Function.Filenames)
+        emitArrayElement(FileName);
+
+      // End Filenames for Function.
+      emitArrayEnd();
+
+      // End Function.
+      emitDictEnd();
+    }
+
+    // End List of Functions.
+    emitArrayEnd();
+  }
+
+  /// \brief Render an array of all the source files, also pass back a Summary.
+  void renderFiles(ArrayRef SourceFiles,
+                   FileCoverageSummary &Summary) {
+    // Start List of Files.
+    emitArrayStart();
+    for (const auto &SourceFile : SourceFiles) {
+      // Render the file.
+      auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
+      renderFile(std::move(FileCoverage));
+
+      for (const auto &F : Coverage.getCoveredFunctions(SourceFile))
+        Summary.addFunction(FunctionCoverageSummary::get(F));
+    }
+
+    // End List of Files.
+    emitArrayEnd();
+  }
+
+  /// \brief Render a single file.
+  void renderFile(CoverageData FileCoverage) {
+    // Start File.
+    emitDictStart();
+
+    emitDictElement("filename", FileCoverage.getFilename());
+    emitDictKey("segments");
+
+    // Start List of Segments.
+    emitArrayStart();
+
+    for (const auto Segment : FileCoverage) {
+      renderSegment(Segment);
+    }
+
+    // End List of Segments.
+    emitArrayEnd();
+
+    emitDictKey("expansions");
+
+    // Start List of Expansions.
+    emitArrayStart();
+
+    for (const auto &Expansion : FileCoverage.getExpansions())
+      renderExpansion(Expansion);
+
+    // End List of Expansions.
+    emitArrayEnd();
+
+    FileCoverageSummary Summary =
+        FileCoverageSummary(FileCoverage.getFilename());
+    for (const auto &F :
+         Coverage.getCoveredFunctions(FileCoverage.getFilename()))
+      Summary.addFunction(FunctionCoverageSummary::get(F));
+
+    emitDictKey("summary");
+    renderSummary(Summary);
+
+    // End File.
+    emitDictEnd();
+  }
+
+  /// \brief Render a CoverageSegment.
+  void renderSegment(CoverageSegment Segment) {
+    // Start Segment.
+    emitArrayStart();
+
+    emitArrayElement(Segment.Line);
+    emitArrayElement(Segment.Col);
+    emitArrayElement(Segment.Count);
+    emitArrayElement(Segment.HasCount);
+    emitArrayElement(Segment.IsRegionEntry);
+
+    // End Segment.
+    emitArrayEnd();
+  }
+
+  /// \brief Render an ExpansionRecord.
+  void renderExpansion(const ExpansionRecord &Expansion) {
+    // Start Expansion.
+    emitDictStart();
+
+    // Mark the beginning and end of this expansion in the source file.
+    emitDictKey("source_region");
+    renderRegion(Expansion.Region);
+
+    // Enumerate the coverage information for the expansion.
+    emitDictKey("target_regions");
+    renderRegions(Expansion.Function.CountedRegions);
+
+    emitDictKey("filenames");
+    // Start List of Filenames to map the fileIDs.
+    emitArrayStart();
+    for (const auto &Filename : Expansion.Function.Filenames)
+      emitArrayElement(Filename);
+    // End List of Filenames.
+    emitArrayEnd();
+
+    // End Expansion.
+    emitDictEnd();
+  }
+
+  /// \brief Render a list of CountedRegions.
+  void renderRegions(ArrayRef Regions) {
+    // Start List of Regions.
+    emitArrayStart();
+
+    for (const auto &Region : Regions)
+      renderRegion(Region);
+
+    // End List of Regions.
+    emitArrayEnd();
+  };
+
+  /// \brief Render a single CountedRegion.
+  void renderRegion(CountedRegion Region) {
+    // Start CountedRegion.
+    emitArrayStart();
+
+    emitArrayElement(Region.LineStart);
+    emitArrayElement(Region.ColumnStart);
+    emitArrayElement(Region.LineEnd);
+    emitArrayElement(Region.ColumnEnd);
+    emitArrayElement(Region.ExecutionCount);
+    emitArrayElement(Region.FileID);
+    emitArrayElement(Region.ExpandedFileID);
+    emitArrayElement(Region.Kind);
+
+    // End CountedRegion.
+    emitArrayEnd();
+  }
+
+  /// \brief Render a FileCoverageSummary.
+  void renderSummary(FileCoverageSummary Summary) {
+    // Start Summary for the file.
+    emitDictStart();
+
+    emitDictKey("lines");
+
+    // Start Line Coverage Summary.
+    emitDictStart();
+    emitDictElement("count", Summary.LineCoverage.NumLines);
+    emitDictElement("covered", Summary.LineCoverage.Covered);
+    emitDictElement("percent", Summary.LineCoverage.getPercentCovered());
+    emitDictElement("noncode", Summary.LineCoverage.NonCodeLines);
+    // End Line Coverage Summary.
+    emitDictEnd();
+
+    emitDictKey("functions");
+
+    // Start Function Coverage Summary.
+    emitDictStart();
+    emitDictElement("count", Summary.FunctionCoverage.NumFunctions);
+    emitDictElement("covered", Summary.FunctionCoverage.Executed);
+    emitDictElement("percent", Summary.FunctionCoverage.getPercentCovered());
+    // End Function Coverage Summary.
+    emitDictEnd();
+
+    emitDictKey("regions");
+
+    // Start Region Coverage Summary.
+    emitDictStart();
+    emitDictElement("count", Summary.RegionCoverage.NumRegions);
+    emitDictElement("covered", Summary.RegionCoverage.Covered);
+    emitDictElement("notcovered", Summary.RegionCoverage.NotCovered);
+    emitDictElement("percent", Summary.RegionCoverage.getPercentCovered());
+    // End Region Coverage Summary.
+    emitDictEnd();
+
+    // End Summary for the file.
+    emitDictEnd();
+  }
+
+public:
+  CoverageExporterJson(StringRef ObjectFilename,
+                       const CoverageViewOptions &Options,
+                       const CoverageMapping &CoverageMapping, raw_ostream &OS)
+      : ObjectFilename(ObjectFilename), Options(Options), OS(OS),
+        Coverage(CoverageMapping) {
+    State.push(JsonState::None);
+  }
+
+  /// \brief Print the CoverageMapping.
+  void print() { renderRoot(); }
+};
+
+/// \brief Export the given CoverageMapping to a JSON Format.
+void exportCoverageDataToJson(StringRef ObjectFilename,
+                              const CoverageViewOptions &Options,
+                              const CoverageMapping &CoverageMapping,
+                              raw_ostream &OS) {
+  auto Exporter =
+      CoverageExporterJson(ObjectFilename, Options, CoverageMapping, OS);
+
+  Exporter.print();
+}
Index: tools/llvm-cov/llvm-cov.cpp
===================================================================
--- tools/llvm-cov/llvm-cov.cpp
+++ tools/llvm-cov/llvm-cov.cpp
@@ -30,6 +30,9 @@
 /// \brief The main entry point for the 'report' subcommand.
 int reportMain(int argc, const char *argv[]);
 
+/// \brief The main entry point for the 'export' subcommand.
+int exportMain(int argc, const char *argv[]);
+
 /// \brief The main entry point for the 'convert-for-testing' subcommand.
 int convertForTestingMain(int argc, const char *argv[]);
 
@@ -38,12 +41,14 @@
 
 /// \brief Top level help.
 static int helpMain(int argc, const char *argv[]) {
-  errs() << "Usage: llvm-cov {gcov|report|show} [OPTION]...\n\n"
+  errs() << "Usage: llvm-cov {export|gcov|report|show} [OPTION]...\n\n"
          << "Shows code coverage information.\n\n"
          << "Subcommands:\n"
+         << "  export: Export instrprof file to structured format.\n"
          << "  gcov:   Work with the gcov format.\n"
-         << "  show:   Annotate source files using instrprof style coverage.\n"
-         << "  report: Summarize instrprof style coverage information.\n";
+         << "  report: Summarize instrprof style coverage information.\n"
+         << "  show:   Annotate source files using instrprof style coverage.\n";
+
   return 0;
 }
 
@@ -71,6 +76,7 @@
                             .Case("gcov", gcovMain)
                             .Case("report", reportMain)
                             .Case("show", showMain)
+                            .Case("export", exportMain)
                             .Cases("-h", "-help", "--help", helpMain)
                             .Cases("-version", "--version", versionMain)
                             .Default(nullptr);