pp_character (pp, '"');
}
+/* class pointer::token. */
+
+pointer::token::token ()
+{
+ m_parent = nullptr;
+ m_data.u_member = nullptr;
+ m_kind = kind::root_value;
+}
+
+pointer::token::token (json::object &parent, const char *member)
+{
+ m_parent = &parent;
+ m_data.u_member = xstrdup (member); // ideally we'd share
+ m_kind = kind::object_member;
+}
+
+pointer::token::token (json::array &parent, size_t index)
+{
+ m_parent = &parent;
+ m_data.u_index = index;
+ m_kind = kind::array_index;
+}
+
+pointer::token::~token ()
+{
+ if (m_kind == kind::object_member)
+ {
+ gcc_assert (m_data.u_member);
+ free (m_data.u_member);
+ }
+}
+
+pointer::token &
+pointer::token::operator= (pointer::token &&other)
+{
+ m_parent = other.m_parent;
+ m_data = other.m_data;
+ m_kind = other.m_kind;
+
+ other.m_parent = nullptr;
+ other.m_data.u_member = nullptr;
+ other.m_kind = kind::root_value;
+
+ return *this;
+}
+
/* class json::value. */
/* Dump this json::value tree to OUTF.
m_map.put (owned_key, v);
m_keys.safe_push (owned_key);
}
+
+ v->m_pointer_token = pointer::token (*this, key);
}
/* Get the json::value * for KEY.
array::append (value *v)
{
gcc_assert (v);
+ v->m_pointer_token = pointer::token (*this, m_elements.length ());
m_elements.safe_push (v);
}
JSON_NULL
};
+namespace pointer { // json::pointer
+
+/* Implementation of JSON pointer (RFC 6901). */
+
+/* A token within a JSON pointer, expressing the parent of a particular
+ JSON value, and how it is descended from that parent.
+
+ A JSON pointer can be built as a list of these tokens. */
+
+struct token
+{
+ enum class kind
+ {
+ root_value,
+ object_member,
+ array_index
+ };
+
+ token ();
+ token (json::object &parent, const char *member);
+ token (json::array &parent, size_t index);
+ token (const token &other) = delete;
+ token (token &&other) = delete;
+
+ ~token ();
+
+ token &
+ operator= (const token &other) = delete;
+
+ token &
+ operator= (token &&other);
+
+ json::value *m_parent;
+ union u
+ {
+ char *u_member;
+ size_t u_index;
+ } m_data;
+ enum kind m_kind;
+};
+
+} // namespace json::pointer
+
/* Base class of JSON value. */
class value
virtual object *dyn_cast_object () { return nullptr; }
static int compare (const json::value &val_a, const json::value &val_b);
+
+ const pointer::token &get_pointer_token () const { return m_pointer_token; }
+
+ pointer::token m_pointer_token;
};
/* Subclass of value for objects: a collection of key/value pairs
return mgr.new_location_from_range (start, start, end);
}
+static enum diagnostic_logical_location_kind_t
+get_logical_location_kind_for_json_kind (enum json::kind json_kind)
+{
+ switch (json_kind)
+ {
+ default:
+ gcc_unreachable ();
+
+ case json::JSON_OBJECT:
+ return DIAGNOSTIC_LOGICAL_LOCATION_KIND_OBJECT;
+
+ case json::JSON_ARRAY:
+ return DIAGNOSTIC_LOGICAL_LOCATION_KIND_ARRAY;
+
+ case json::JSON_INTEGER:
+ case json::JSON_FLOAT:
+ case json::JSON_STRING:
+ case json::JSON_TRUE:
+ case json::JSON_FALSE:
+ case json::JSON_NULL:
+ return DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROPERTY;
+ /* Perhaps this should be DIAGNOSTIC_LOGICAL_LOCATION_KIND_VALUE,
+ but then we need to more carefully track context. */
+ }
+}
+
+static libgdiagnostics::logical_location
+make_logical_location_from_jv (libgdiagnostics::manager &mgr,
+ const json::value &jv)
+{
+ libgdiagnostics::logical_location parent;
+ const json::pointer::token &pointer_token = jv.get_pointer_token ();
+
+ if (pointer_token.m_parent)
+ /* Recursively ensure that we have ancestor locations. */
+ parent = make_logical_location_from_jv (mgr,
+ *jv.m_pointer_token.m_parent);
+
+ std::string short_name;
+ std::string fully_qualified_name;
+ switch (pointer_token.m_kind)
+ {
+ default:
+ gcc_unreachable ();
+
+ case json::pointer::token::kind::root_value:
+ short_name = "";
+ fully_qualified_name = "";
+ break;
+
+ case json::pointer::token::kind::object_member:
+ short_name = pointer_token.m_data.u_member;
+ gcc_assert (parent.m_inner);
+ fully_qualified_name
+ = std::string (parent.get_fully_qualified_name ()) + "/" + short_name;
+ break;
+
+ case json::pointer::token::kind::array_index:
+ short_name = std::to_string (pointer_token.m_data.u_index);
+ gcc_assert (parent.m_inner);
+ fully_qualified_name
+ = std::string (parent.get_fully_qualified_name ()) + "/" + short_name;
+ break;
+ }
+
+ enum diagnostic_logical_location_kind_t kind
+ = get_logical_location_kind_for_json_kind (jv.get_kind ());
+
+ return mgr.new_logical_location (kind,
+ parent,
+ short_name.c_str (),
+ fully_qualified_name.c_str (),
+ nullptr);
+}
+
+
enum class status
{
ok,
m_json_location_map.get_range_for_value (jv));
diag.set_location (loc_range);
+ diag.set_logical_location (make_logical_location_from_jv (m_control_mgr,
+ jv));
+
diag.finish_va (gmsgid, args);
}
[ null ] // { dg-error "expected a sarifLog object as the top-level value \\\[SARIF v2.1.0 §3.1\\\]" }
+/* { dg-begin-multiline-output "" }
+In JSON array '':
+ { dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
1 | [ null ]
| ^~~~~~~~
}]
}
+/* { dg-begin-multiline-output "" }
+In JSON object '/runs/0/results/0/message':
+ { dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
6 | { "message": { "text" : "the {0} {1} fox jumps over the {2} dog" } }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}]
}
+/* { dg-begin-multiline-output "" }
+In JSON object '/runs/0/results/0/message':
+ { dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
6 | { "message": { "text" : "the {0} {1} fox jumps over the {2} dog", "arguments": ["quick", "brown"] } }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}]
}
+/* { dg-begin-multiline-output "" }
+In JSON property '/runs/0/results/0/message/text':
+ { dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
6 | { "message": { "text" : "before {} after" },
| ^~~~~~~~~~~~~~~~~
{ } // { dg-error "expected sarifLog object to have a 'version' property \\\[SARIF v2.1.0 §3.13.2\\\]" }
+/* { dg-begin-multiline-output "" }
+In JSON object '':
+ { dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
1 | { }
| ^~~
{ "version" : 42 } // { dg-error "15: expected sarifLog.version to be a JSON string; got JSON number \\\[SARIF v2.1.0 §3.13.2\\\]" }
+/* { dg-begin-multiline-output "" }
+In JSON property '/version':
+ { dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
1 | { "version" : 42 }
| ^~
{ "version": "2.1.0",
"runs": 42 } // { dg-error "expected sarifLog.runs to be 'null' or an array \\\[SARIF v2.1.0 §3.13.4\\\]" }
+/* { dg-begin-multiline-output "" }
+In JSON property '/runs':
+ { dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
2 | "runs": 42 }
| ^~
{ "version": "2.1.0" } // { dg-error "expected sarifLog object to have a 'runs' property \\\[SARIF v2.1.0 §3.13.4\\\]" }
+/* { dg-begin-multiline-output "" }
+In JSON object '':
+ { dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
1 | { "version": "2.1.0" }
| ^~~~~~~~~~~~~~~~~~~~~~
{ "version": "2.1.0",
"runs" : [42] } // { dg-error "expected element of sarifLog.runs array to be an object \\\[SARIF v2.1.0 §3.13.4\\\]" }
+/* { dg-begin-multiline-output "" }
+In JSON property '/runs/0':
+ { dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
2 | "runs" : [42] }
| ^~
]
}
+/* { dg-begin-multiline-output "" }
+In JSON property '/runs/0/results/0/level':
+ { dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
12 | "level": "mostly harmless",
| ^~~~~~~~~~~~~~~~~
]
}
+/* { dg-begin-multiline-output "" }
+In JSON property '/runs/0/results/0/locations/0/logicalLocations/0/index'
+ { dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
17 | "index": 42
| ^~
]
}
+/* { dg-begin-multiline-output "" }
+In JSON property '/runs/0/results/0/level'
+ { dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
12 | "level": "none",
| ^~~~~~