RUN: sancov -merge %p/Inputs/test-linux_x86_64.0.symcov %p/Inputs/test-linux_x86_64.1.symcov| FileCheck --check-prefix=MERGE2 %s
MERGE1: {
-MERGE1-NEXT: "covered-points" : ["4e132b", "4e1472", "4e1520", "4e1553", "4e1586"],
-MERGE1-NEXT: "binary-hash" : "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5",
-MERGE1-NEXT: "point-symbol-info" : {
-MERGE1-NEXT: "test/tools/sancov/Inputs/foo.cpp" : {
-MERGE1-NEXT: "foo()" : {
-MERGE1-NEXT: "4e178c" : "5:0"
+MERGE1-NEXT: "covered-points": [
+MERGE1-NEXT: "4e132b",
+MERGE1-NEXT: "4e1472",
+MERGE1-NEXT: "4e1520",
+MERGE1-NEXT: "4e1553",
+MERGE1-NEXT: "4e1586"
+MERGE1-NEXT: ],
+MERGE1-NEXT: "binary-hash": "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5",
+MERGE1-NEXT: "point-symbol-info": {
+MERGE1-NEXT: "test/tools/sancov/Inputs/foo.cpp": {
+MERGE1-NEXT: "foo()": {
+MERGE1-NEXT: "4e178c": "5:0"
MERGE1-NEXT: }
MERGE1-NEXT: },
-MERGE1-NEXT: "test/tools/sancov/Inputs/test.cpp" : {
-MERGE1-NEXT: "bar(std::string)" : {
-MERGE1-NEXT: "4e132b" : "12:0"
+MERGE1-NEXT: "test/tools/sancov/Inputs/test.cpp": {
+MERGE1-NEXT: "bar(std::string)": {
+MERGE1-NEXT: "4e132b": "12:0"
MERGE1-NEXT: },
-MERGE1-NEXT: "main" : {
-MERGE1-NEXT: "4e1472" : "14:0",
-MERGE1-NEXT: "4e14c2" : "16:9",
-MERGE1-NEXT: "4e1520" : "17:5",
-MERGE1-NEXT: "4e1553" : "17:5",
-MERGE1-NEXT: "4e1586" : "17:5",
-MERGE1-NEXT: "4e1635" : "19:1",
-MERGE1-NEXT: "4e1690" : "17:5"
+MERGE1-NEXT: "main": {
+MERGE1-NEXT: "4e1472": "14:0",
+MERGE1-NEXT: "4e14c2": "16:9",
+MERGE1-NEXT: "4e1520": "17:5",
+MERGE1-NEXT: "4e1553": "17:5",
+MERGE1-NEXT: "4e1586": "17:5",
+MERGE1-NEXT: "4e1635": "19:1",
+MERGE1-NEXT: "4e1690": "17:5"
MERGE1-NEXT: }
MERGE1-NEXT: }
MERGE1-NEXT: }
MERGE1-NEXT: }
MERGE2: {
-MERGE2-NEXT: "covered-points" : ["04e132b", "04e1472", "04e1520", "04e1553", "04e1586", "14e132b", "14e1472", "14e14c2", "14e1520", "14e1553", "14e1586", "14e178c"],
-MERGE2-NEXT: "point-symbol-info" : {
-MERGE2-NEXT: "test/tools/sancov/Inputs/foo.cpp" : {
-MERGE2-NEXT: "foo()" : {
-MERGE2-NEXT: "04e178c" : "5:0",
-MERGE2-NEXT: "14e178c" : "5:0"
+MERGE2-NEXT: "covered-points": [
+MERGE2-NEXT: "04e132b",
+MERGE2-NEXT: "04e1472",
+MERGE2-NEXT: "04e1520",
+MERGE2-NEXT: "04e1553",
+MERGE2-NEXT: "04e1586",
+MERGE2-NEXT: "14e132b",
+MERGE2-NEXT: "14e1472",
+MERGE2-NEXT: "14e14c2",
+MERGE2-NEXT: "14e1520",
+MERGE2-NEXT: "14e1553",
+MERGE2-NEXT: "14e1586",
+MERGE2-NEXT: "14e178c"
+MERGE2-NEXT: ],
+MERGE2-NEXT: "binary-hash": "",
+MERGE2-NEXT: "point-symbol-info": {
+MERGE2-NEXT: "test/tools/sancov/Inputs/foo.cpp": {
+MERGE2-NEXT: "foo()": {
+MERGE2-NEXT: "04e178c": "5:0",
+MERGE2-NEXT: "14e178c": "5:0"
MERGE2-NEXT: }
MERGE2-NEXT: },
-MERGE2-NEXT: "test/tools/sancov/Inputs/test.cpp" : {
-MERGE2-NEXT: "bar(std::string)" : {
-MERGE2-NEXT: "04e132b" : "12:0",
-MERGE2-NEXT: "14e132b" : "12:0"
+MERGE2-NEXT: "test/tools/sancov/Inputs/test.cpp": {
+MERGE2-NEXT: "bar(std::string)": {
+MERGE2-NEXT: "04e132b": "12:0",
+MERGE2-NEXT: "14e132b": "12:0"
MERGE2-NEXT: },
-MERGE2-NEXT: "main" : {
-MERGE2-NEXT: "04e1472" : "14:0",
-MERGE2-NEXT: "04e14c2" : "16:9",
-MERGE2-NEXT: "04e1520" : "17:5",
-MERGE2-NEXT: "04e1553" : "17:5",
-MERGE2-NEXT: "04e1586" : "17:5",
-MERGE2-NEXT: "04e1635" : "19:1",
-MERGE2-NEXT: "04e1690" : "17:5",
-MERGE2-NEXT: "14e1472" : "14:0",
-MERGE2-NEXT: "14e14c2" : "16:9",
-MERGE2-NEXT: "14e1520" : "17:5",
-MERGE2-NEXT: "14e1553" : "17:5",
-MERGE2-NEXT: "14e1586" : "17:5",
-MERGE2-NEXT: "14e1635" : "19:1",
-MERGE2-NEXT: "14e1690" : "17:5"
+MERGE2-NEXT: "main": {
+MERGE2-NEXT: "04e1472": "14:0",
+MERGE2-NEXT: "04e14c2": "16:9",
+MERGE2-NEXT: "04e1520": "17:5",
+MERGE2-NEXT: "04e1553": "17:5",
+MERGE2-NEXT: "04e1586": "17:5",
+MERGE2-NEXT: "04e1635": "19:1",
+MERGE2-NEXT: "04e1690": "17:5",
+MERGE2-NEXT: "14e1472": "14:0",
+MERGE2-NEXT: "14e14c2": "16:9",
+MERGE2-NEXT: "14e1520": "17:5",
+MERGE2-NEXT: "14e1553": "17:5",
+MERGE2-NEXT: "14e1586": "17:5",
+MERGE2-NEXT: "14e1635": "19:1",
+MERGE2-NEXT: "14e1690": "17:5"
MERGE2-NEXT: }
MERGE2-NEXT: }
MERGE2-NEXT: }
MERGE2-NEXT: }
-
RUN: sancov -symbolize -strip_path_prefix="llvm/" %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.0.sancov | FileCheck %s
CHECK: {
-CHECK-NEXT: "covered-points" : ["4e132b", "4e1472", "4e1520", "4e1553", "4e1586"],
-CHECK-NEXT: "binary-hash" : "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5",
-CHECK-NEXT: "point-symbol-info" : {
-CHECK-NEXT: "test/tools/sancov/Inputs/test.cpp" : {
-CHECK-NEXT: "bar(std::string)" : {
-CHECK-NEXT: "4e132b" : "12:0"
+CHECK-NEXT: "covered-points": [
+CHECK-NEXT: "4e132b",
+CHECK-NEXT: "4e1472",
+CHECK-NEXT: "4e1520",
+CHECK-NEXT: "4e1553",
+CHECK-NEXT: "4e1586"
+CHECK-NEXT: ],
+CHECK-NEXT: "binary-hash": "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5",
+CHECK-NEXT: "point-symbol-info": {
+CHECK-NEXT: "test/tools/sancov/Inputs/test.cpp": {
+CHECK-NEXT: "bar(std::string)": {
+CHECK-NEXT: "4e132b": "12:0"
CHECK-NEXT: },
-CHECK-NEXT: "main" : {
-CHECK-NEXT: "4e1472" : "14:0",
-CHECK-NEXT: "4e14c2" : "16:9",
-CHECK-NEXT: "4e1520" : "17:5",
-CHECK-NEXT: "4e1553" : "17:5",
-CHECK-NEXT: "4e1586" : "17:5",
-CHECK-NEXT: "4e1635" : "19:1",
-CHECK-NEXT: "4e1690" : "17:5"
+CHECK-NEXT: "main": {
+CHECK-NEXT: "4e1472": "14:0",
+CHECK-NEXT: "4e14c2": "16:9",
+CHECK-NEXT: "4e1520": "17:5",
+CHECK-NEXT: "4e1553": "17:5",
+CHECK-NEXT: "4e1586": "17:5",
+CHECK-NEXT: "4e1635": "19:1",
+CHECK-NEXT: "4e1690": "17:5"
CHECK-NEXT: }
CHECK-NEXT: }
CHECK-NEXT: }
CHECK-NEXT:}
-
RUN: sancov -symbolize -skip-dead-files=0 -strip_path_prefix="llvm/" %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.0.sancov | FileCheck %s
CHECK: {
-CHECK-NEXT: "covered-points" : ["4e132b", "4e1472", "4e1520", "4e1553", "4e1586"],
-CHECK-NEXT: "binary-hash" : "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5",
-CHECK-NEXT: "point-symbol-info" : {
-CHECK-NEXT: "test/tools/sancov/Inputs/foo.cpp" : {
-CHECK-NEXT: "foo()" : {
-CHECK-NEXT: "4e178c" : "5:0"
-CHECK-NEXT: }
-CHECK-NEXT: },
-CHECK-NEXT: "test/tools/sancov/Inputs/test.cpp" : {
-CHECK-NEXT: "bar(std::string)" : {
-CHECK-NEXT: "4e132b" : "12:0"
+CHECK-NEXT: "covered-points": [
+CHECK-NEXT: "4e132b",
+CHECK-NEXT: "4e1472",
+CHECK-NEXT: "4e1520",
+CHECK-NEXT: "4e1553",
+CHECK-NEXT: "4e1586"
+CHECK-NEXT: ],
+CHECK-NEXT: "binary-hash": "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5",
+CHECK-NEXT: "point-symbol-info": {
+CHECK-NEXT: "test/tools/sancov/Inputs/foo.cpp": {
+CHECK-NEXT: "foo()": {
+CHECK-NEXT: "4e178c": "5:0"
+CHECK-NEXT: }
+CHECK-NEXT: },
+CHECK-NEXT: "test/tools/sancov/Inputs/test.cpp": {
+CHECK-NEXT: "bar(std::string)": {
+CHECK-NEXT: "4e132b": "12:0"
CHECK-NEXT: },
-CHECK-NEXT: "main" : {
-CHECK-NEXT: "4e1472" : "14:0",
-CHECK-NEXT: "4e14c2" : "16:9",
-CHECK-NEXT: "4e1520" : "17:5",
-CHECK-NEXT: "4e1553" : "17:5",
-CHECK-NEXT: "4e1586" : "17:5",
-CHECK-NEXT: "4e1635" : "19:1",
-CHECK-NEXT: "4e1690" : "17:5"
+CHECK-NEXT: "main": {
+CHECK-NEXT: "4e1472": "14:0",
+CHECK-NEXT: "4e14c2": "16:9",
+CHECK-NEXT: "4e1520": "17:5",
+CHECK-NEXT: "4e1553": "17:5",
+CHECK-NEXT: "4e1586": "17:5",
+CHECK-NEXT: "4e1635": "19:1",
+CHECK-NEXT: "4e1690": "17:5"
CHECK-NEXT: }
CHECK-NEXT: }
CHECK-NEXT: }
CHECK-NEXT:}
-
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/JSON.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
return OS;
}
-// Helper for writing out JSON. Handles indents and commas using
-// scope variables for objects and arrays.
-class JSONWriter {
-public:
- JSONWriter(raw_ostream &Out) : OS(Out) {}
- JSONWriter(const JSONWriter &) = delete;
- ~JSONWriter() { OS << "\n"; }
-
- void operator<<(StringRef S) { printJSONStringLiteral(S, OS); }
-
- // Helper RAII class to output JSON objects.
- class Object {
- public:
- Object(JSONWriter *W, raw_ostream &OS) : W(W), OS(OS) {
- OS << "{";
- W->Indent++;
- }
- ~Object() {
- W->Indent--;
- OS << "\n";
- W->indent();
- OS << "}";
- }
-
- void key(StringRef Key) {
- Index++;
- if (Index > 0)
- OS << ",";
- OS << "\n";
- W->indent();
- printJSONStringLiteral(Key, OS);
- OS << " : ";
- }
-
- private:
- JSONWriter *W;
- raw_ostream &OS;
- int Index = -1;
- };
-
- Object object() { return {this, OS}; }
-
- // Helper RAII class to output JSON arrays.
- class Array {
- public:
- Array(raw_ostream &OS) : OS(OS) { OS << "["; }
- ~Array() { OS << "]"; }
- void next() {
- Index++;
- if (Index > 0)
- OS << ", ";
- }
-
- private:
- raw_ostream &OS;
- int Index = -1;
- };
-
- Array array() { return {OS}; }
-
-private:
- void indent() { OS.indent(Indent * 2); }
-
- static void printJSONStringLiteral(StringRef S, raw_ostream &OS) {
- if (S.find('"') == std::string::npos) {
- OS << "\"" << S << "\"";
- return;
- }
- OS << "\"";
- for (char Ch : S.bytes()) {
- if (Ch == '"')
- OS << "\\";
- OS << Ch;
- }
- OS << "\"";
- }
-
- raw_ostream &OS;
- int Indent = 0;
-};
-
// Output symbolized information for coverage points in JSON.
// Format:
// {
// }
// }
// }
-static void operator<<(JSONWriter &W,
+static void operator<<(json::OStream &W,
const std::vector<CoveragePoint> &Points) {
// Group points by file.
- auto ByFile(W.object());
std::map<std::string, std::vector<const CoveragePoint *>> PointsByFile;
for (const auto &Point : Points) {
for (const DILineInfo &Loc : Point.Locs) {
for (const auto &P : PointsByFile) {
std::string FileName = P.first;
- ByFile.key(FileName);
-
- // Group points by function.
- auto ByFn(W.object());
std::map<std::string, std::vector<const CoveragePoint *>> PointsByFn;
for (auto PointPtr : P.second) {
for (const DILineInfo &Loc : PointPtr->Locs) {
}
}
- for (const auto &P : PointsByFn) {
- std::string FunctionName = P.first;
- std::set<std::string> WrittenIds;
-
- ByFn.key(FunctionName);
-
- // Output <point_id> : "<line>:<col>".
- auto ById(W.object());
- for (const CoveragePoint *Point : P.second) {
- for (const auto &Loc : Point->Locs) {
- if (Loc.FileName != FileName || Loc.FunctionName != FunctionName)
- continue;
- if (WrittenIds.find(Point->Id) != WrittenIds.end())
- continue;
-
- WrittenIds.insert(Point->Id);
- ById.key(Point->Id);
- W << (utostr(Loc.Line) + ":" + utostr(Loc.Column));
- }
+ W.attributeObject(P.first, [&] {
+ // Group points by function.
+ for (const auto &P : PointsByFn) {
+ std::string FunctionName = P.first;
+ std::set<std::string> WrittenIds;
+
+ W.attributeObject(FunctionName, [&] {
+ for (const CoveragePoint *Point : P.second) {
+ for (const auto &Loc : Point->Locs) {
+ if (Loc.FileName != FileName || Loc.FunctionName != FunctionName)
+ continue;
+ if (WrittenIds.find(Point->Id) != WrittenIds.end())
+ continue;
+
+ // Output <point_id> : "<line>:<col>".
+ WrittenIds.insert(Point->Id);
+ W.attribute(Point->Id,
+ (utostr(Loc.Line) + ":" + utostr(Loc.Column)));
+ }
+ }
+ });
}
- }
+ });
}
}
-static void operator<<(JSONWriter &W, const SymbolizedCoverage &C) {
- auto O(W.object());
-
- {
- O.key("covered-points");
- auto PointsArray(W.array());
-
- for (const std::string &P : C.CoveredIds) {
- PointsArray.next();
- W << P;
- }
- }
-
- {
- if (!C.BinaryHash.empty()) {
- O.key("binary-hash");
- W << C.BinaryHash;
- }
- }
-
- {
- O.key("point-symbol-info");
- W << C.Points;
- }
+static void operator<<(json::OStream &W, const SymbolizedCoverage &C) {
+ W.object([&] {
+ W.attributeArray("covered-points", [&] {
+ for (const std::string &P : C.CoveredIds) {
+ W.value(P);
+ }
+ });
+ W.attribute("binary-hash", C.BinaryHash);
+ W.attributeObject("point-symbol-info", [&] { W << C.Points; });
+ });
}
static std::string parseScalarString(yaml::Node *N) {
}
case MergeAction:
case SymbolizeAction: { // merge & symbolize are synonims.
- JSONWriter W(outs());
+ json::OStream W(outs(), 2);
W << *Coverage;
return 0;
}