Skip to content

Commit b2c283c

Browse files
Yuh Shin Ongfacebook-github-bot
Yuh Shin Ong
authored andcommitted
Support PartialKind::from_json
Summary: Changes the JSON representation of PartialKind from the string "Partial:<label>:<name>" to a JSON structure (similar to TransformKind). Makes parsing sharded models from JSON easier. Used in --replay-mode, and potentially JAR caching (--sharded-input-models). Conversion to string representation is done in mariana_trench_parser_objects.py, similar to TransformKinds. Similar support for TriggeredPartialKind coming up next. NOTE: There is now a `PartialKind::from_json()` and `PartialKind::from_rule_json()`. The latter is pre-existing and renamed. It supports parsing partial kinds from rules where the name and labels are nested in different objects: ``` { "name": "Blah", "code": 1, "description": "multi source rule", "multi_sources": { "a": [ "Source1" ], "b": [ "Source2" ] }, "partial_sinks": [ "MyPartialSink" ] } ``` Reviewed By: arthaud Differential Revision: D71245841 fbshipit-source-id: e086e05c7d7bb61fcb5402f5eca3ff1cc115e1cc
1 parent 6f7d8fb commit b2c283c

File tree

8 files changed

+144
-37
lines changed

8 files changed

+144
-37
lines changed

source/Kind.cpp

+21-10
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,28 @@ const Kind* Kind::from_json(const Json::Value& value, Context& context) {
4141
const auto leaf_kind =
4242
JsonValidation::object_or_string(value, /* field */ "kind");
4343

44-
// An object means it's a TransformKind.
44+
// Some kinds are represented as an object. Use unique keys in them to
45+
// determine the Kind.
4546
if (leaf_kind.isObject()) {
46-
return TransformKind::from_json(leaf_kind, context);
47+
if (leaf_kind.isMember("base")) {
48+
return TransformKind::from_json(leaf_kind, context);
49+
} else if (leaf_kind.isMember("partial_label")) {
50+
return PartialKind::from_json(leaf_kind, context);
51+
} else {
52+
throw JsonValidationError(
53+
value,
54+
"kind",
55+
/* expected */ "TransformKind or PartialKind nested in an object.");
56+
}
4757
}
4858

4959
if (value.isMember("partial_label")) {
50-
return context.kind_factory->get_partial(
51-
leaf_kind.asString(),
52-
JsonValidation::string(value, /* field */ "partial_label"));
60+
// "partial_label" in the outer object is a legacy format that is no longer
61+
// supported. It should be nested within the "kind" object.
62+
throw JsonValidationError(
63+
value,
64+
"partial_label",
65+
/* expected */ "'partial_label' nested in a 'kind' object.");
5366
}
5467

5568
return Kind::from_trace_string(leaf_kind.asString(), context);
@@ -81,11 +94,9 @@ const Kind* Kind::from_trace_string(const std::string& kind, Context& context) {
8194
kind,
8295
/* expected */ "Non-TriggeredPartial Kind");
8396
} else if (boost::starts_with(kind, "Partial:")) {
84-
// Note that parsing partial kinds from the JSON is supported, but not
85-
// from the string representation.
86-
throw KindNotSupportedError(
87-
kind,
88-
/* expected */ "Non-Partial Kind");
97+
// Parsing of PartialKinds from the JSON is supported, but it no longer uses
98+
// the old string representation.
99+
throw KindNotSupportedError(kind, /* expected */ "Non-Partial Kind");
89100
} else if (kind.find_first_of(":@") != std::string::npos) {
90101
// Note that parsing transform kinds from the JSON is supported, but it
91102
// no longer uses the old string representation.

source/MultiSourceMultiSinkRule.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ std::unique_ptr<Rule> MultiSourceMultiSinkRule::from_json(
136136
JsonValidation::nonempty_array(value, "partial_sinks")) {
137137
for (const auto& label : labels) {
138138
partial_sink_kinds.insert(
139-
PartialKind::from_json(sink_kind, label, context));
139+
PartialKind::from_rule_json(sink_kind, label, context));
140140
}
141141
}
142142

source/PartialKind.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,30 @@ void PartialKind::show(std::ostream& out) const {
1515
out << "Partial:" << name_ << ":" << label_;
1616
}
1717

18+
Json::Value PartialKind::to_json() const {
19+
auto nestedValue = Json::Value(Json::objectValue);
20+
nestedValue["name"] = name_;
21+
nestedValue["partial_label"] = label_;
22+
23+
auto value = Json::Value(Json::objectValue);
24+
value["kind"] = nestedValue;
25+
26+
return value;
27+
}
28+
1829
const PartialKind* PartialKind::from_json(
30+
const Json::Value& value,
31+
Context& context) {
32+
// Notable asymmetry with to_json():
33+
// to_json() nests the value in a "kind" field to be consistent with the
34+
// overridden Kind::to_json().
35+
// from_json(value, ...) assumes `value` has been extracted from "kind" field.
36+
auto name = JsonValidation::string(value, /* field */ "name");
37+
auto label = JsonValidation::string(value, /* field */ "partial_label");
38+
return context.kind_factory->get_partial(name, label);
39+
}
40+
41+
const PartialKind* PartialKind::from_rule_json(
1942
const Json::Value& value,
2043
const std::string& label,
2144
Context& context) {

source/PartialKind.h

+6
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,16 @@ class PartialKind final : public Kind {
3838

3939
void show(std::ostream&) const override;
4040

41+
Json::Value to_json() const override;
4142
static const PartialKind* from_json(
43+
const Json::Value& value,
44+
Context& context);
45+
46+
static const PartialKind* from_rule_json(
4247
const Json::Value& value,
4348
const std::string& partial_label,
4449
Context& context);
50+
4551
std::string to_trace_string() const override;
4652

4753
const auto& name() const {

source/tests/JsonTest.cpp

+21-3
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,14 @@ TEST_F(JsonTest, Sanitizer) {
533533
.to_json()));
534534
EXPECT_EQ(
535535
test::parse_json(
536-
R"({"sanitize": "sources", "kinds": [{"kind": "Kind1"}, {"kind": "Kind2"}, {"kind": "Partial:Kind3:a"}]})"),
536+
R"({
537+
"sanitize": "sources",
538+
"kinds": [
539+
{"kind": "Kind1"},
540+
{"kind": "Kind2"},
541+
{"kind": {"name": "Kind3", "partial_label": "a"}}
542+
]
543+
})"),
537544
test::sorted_json(Sanitizer(
538545
SanitizerKind::Sources,
539546
/* kinds */
@@ -2215,7 +2222,12 @@ TEST_F(JsonTest, Model) {
22152222
"method": "LData;.method:(LData;LData;)V",
22162223
"sanitizers": [
22172224
{"sanitize": "sources", "kinds": [{"kind": "Kind1"}]},
2218-
{"sanitize": "sinks", "kinds": [{"kind": "Kind1"}, {"kind": "Partial:Kind2:a"}]}
2225+
{
2226+
"sanitize": "sinks",
2227+
"kinds": [
2228+
{"kind": "Kind1"},
2229+
{"kind": {"name": "Kind2", "partial_label": "a"}}
2230+
]}
22192231
]
22202232
})#")));
22212233
EXPECT_EQ(
@@ -2299,7 +2311,13 @@ TEST_F(JsonTest, Model) {
22992311
test::sorted_json(test::parse_json(R"#({
23002312
"method": "LData;.method:(LData;LData;)V",
23012313
"sanitizers": [
2302-
{"sanitize": "sinks", "kinds": [{"kind": "Kind1"}, {"kind": "Partial:Kind2:a"}]},
2314+
{
2315+
"sanitize": "sinks",
2316+
"kinds": [
2317+
{"kind": "Kind1"},
2318+
{"kind": {"name": "Kind2", "partial_label": "a"}}
2319+
]
2320+
},
23032321
{"sanitize": "sinks", "port": "Argument(2)", "kinds": [{"kind": "Kind1"}, {"kind": "Kind3"}]},
23042322
{"sanitize": "sources", "port": "Argument(1)"}
23052323
]

source/tests/KindTest.cpp

+2-9
Original file line numberDiff line numberDiff line change
@@ -105,18 +105,11 @@ TEST_F(KindTest, SerializationDeserialization) {
105105
Kind::from_json(transform_kind->to_json(), context), transform_kind);
106106
}
107107

108-
// Deserializing Partial and Triggered Kinds are not currently supported.
109-
// These are trickier to parse, and for now, are not needed unless
110-
// multi-source/sink rules are used when analysis caching where
111-
// deserialization of the cached result happens.
112108
const auto* partial_kind =
113109
context.kind_factory->get_partial("PartialKind", "label");
114-
EXPECT_THROW(
115-
Kind::from_json(partial_kind->to_json(), context), KindNotSupportedError);
116-
EXPECT_THROW(
117-
Kind::from_trace_string(partial_kind->to_trace_string(), context),
118-
KindNotSupportedError);
110+
EXPECT_EQ(Kind::from_json(partial_kind->to_json(), context), partial_kind);
119111

112+
// Deserializing Triggered Kinds is not currently supported.
120113
auto source_kinds_a =
121114
Rule::KindSet{context.kind_factory->get("NamedSourceKindA")};
122115
auto source_kinds_b =

source/tests/integration/end-to-end/code/literal_source/expected_output.json

+50-10
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,11 @@
11561156
"kinds" :
11571157
[
11581158
{
1159-
"kind" : "Partial:TestSink:regex",
1159+
"kind" :
1160+
{
1161+
"name" : "TestSink",
1162+
"partial_label" : "regex"
1163+
},
11601164
"origins" :
11611165
[
11621166
{
@@ -1181,7 +1185,11 @@
11811185
"kinds" :
11821186
[
11831187
{
1184-
"kind" : "Partial:TestSink:aci",
1188+
"kind" :
1189+
{
1190+
"name" : "TestSink",
1191+
"partial_label" : "aci"
1192+
},
11851193
"origins" :
11861194
[
11871195
{
@@ -2335,7 +2343,11 @@
23352343
"kinds" :
23362344
[
23372345
{
2338-
"kind" : "Partial:TestSink:regex",
2346+
"kind" :
2347+
{
2348+
"name" : "TestSink",
2349+
"partial_label" : "regex"
2350+
},
23392351
"origins" :
23402352
[
23412353
{
@@ -2360,7 +2372,11 @@
23602372
"kinds" :
23612373
[
23622374
{
2363-
"kind" : "Partial:TestSink:aci",
2375+
"kind" :
2376+
{
2377+
"name" : "TestSink",
2378+
"partial_label" : "aci"
2379+
},
23642380
"origins" :
23652381
[
23662382
{
@@ -2516,7 +2532,11 @@
25162532
"kinds" :
25172533
[
25182534
{
2519-
"kind" : "Partial:TestSink:aci",
2535+
"kind" :
2536+
{
2537+
"name" : "TestSink",
2538+
"partial_label" : "aci"
2539+
},
25202540
"origins" :
25212541
[
25222542
{
@@ -2526,7 +2546,11 @@
25262546
]
25272547
},
25282548
{
2529-
"kind" : "Partial:TestSink:regex",
2549+
"kind" :
2550+
{
2551+
"name" : "TestSink",
2552+
"partial_label" : "regex"
2553+
},
25302554
"origins" :
25312555
[
25322556
{
@@ -2551,7 +2575,11 @@
25512575
"kinds" :
25522576
[
25532577
{
2554-
"kind" : "Partial:TestSink:aci",
2578+
"kind" :
2579+
{
2580+
"name" : "TestSink",
2581+
"partial_label" : "aci"
2582+
},
25552583
"origins" :
25562584
[
25572585
{
@@ -2561,7 +2589,11 @@
25612589
]
25622590
},
25632591
{
2564-
"kind" : "Partial:TestSink:regex",
2592+
"kind" :
2593+
{
2594+
"name" : "TestSink",
2595+
"partial_label" : "regex"
2596+
},
25652597
"origins" :
25662598
[
25672599
{
@@ -2699,7 +2731,11 @@
26992731
"kinds" :
27002732
[
27012733
{
2702-
"kind" : "Partial:TestSink:regex",
2734+
"kind" :
2735+
{
2736+
"name" : "TestSink",
2737+
"partial_label" : "regex"
2738+
},
27032739
"origins" :
27042740
[
27052741
{
@@ -2724,7 +2760,11 @@
27242760
"kinds" :
27252761
[
27262762
{
2727-
"kind" : "Partial:TestSink:aci",
2763+
"kind" :
2764+
{
2765+
"name" : "TestSink",
2766+
"partial_label" : "aci"
2767+
},
27282768
"origins" :
27292769
[
27302770
{

source/tests/integration/end-to-end/code/multi_sources/expected_output.json

+20-4
Original file line numberDiff line numberDiff line change
@@ -1568,7 +1568,11 @@
15681568
[
15691569
"sink-a"
15701570
],
1571-
"kind" : "Partial:TestSink:a",
1571+
"kind" :
1572+
{
1573+
"name" : "TestSink",
1574+
"partial_label" : "a"
1575+
},
15721576
"origins" :
15731577
[
15741578
{
@@ -1597,7 +1601,11 @@
15971601
[
15981602
"sink-b"
15991603
],
1600-
"kind" : "Partial:TestSink:b",
1604+
"kind" :
1605+
{
1606+
"name" : "TestSink",
1607+
"partial_label" : "b"
1608+
},
16011609
"origins" :
16021610
[
16031611
{
@@ -2184,7 +2192,11 @@
21842192
[
21852193
"sink-a"
21862194
],
2187-
"kind" : "Partial:TestSinkSingleArg:a",
2195+
"kind" :
2196+
{
2197+
"name" : "TestSinkSingleArg",
2198+
"partial_label" : "a"
2199+
},
21882200
"origins" :
21892201
[
21902202
{
@@ -2198,7 +2210,11 @@
21982210
[
21992211
"sink-b"
22002212
],
2201-
"kind" : "Partial:TestSinkSingleArg:b",
2213+
"kind" :
2214+
{
2215+
"name" : "TestSinkSingleArg",
2216+
"partial_label" : "b"
2217+
},
22022218
"origins" :
22032219
[
22042220
{

0 commit comments

Comments
 (0)