Skip to content

Commit

Permalink
Compile out assertions that are obviously invalid
Browse files Browse the repository at this point in the history
Signed-off-by: Juan Cruz Viotti <[email protected]>
  • Loading branch information
jviotti committed Sep 2, 2024
1 parent b29de65 commit 9e0e571
Show file tree
Hide file tree
Showing 4 changed files with 214 additions and 1 deletion.
31 changes: 30 additions & 1 deletion src/jsonschema/default_compiler_2019_09.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ auto compiler_2019_09_applicator_dependentschemas(
const SchemaCompilerDynamicContext &dynamic_context)
-> SchemaCompilerTemplate {
assert(schema_context.schema.at(dynamic_context.keyword).is_object());
SchemaCompilerTemplate children;

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "object") {
return {};
}

SchemaCompilerTemplate children;
for (const auto &entry :
schema_context.schema.at(dynamic_context.keyword).as_object()) {
if (!is_schema(entry.second)) {
Expand Down Expand Up @@ -48,6 +54,12 @@ auto compiler_2019_09_validation_dependentrequired(
return {};
}

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "object") {
return {};
}

SchemaCompilerValueStringMap dependencies;
for (const auto &entry :
schema_context.schema.at(dynamic_context.keyword).as_object()) {
Expand Down Expand Up @@ -90,6 +102,11 @@ auto compiler_2019_09_applicator_contains_conditional_annotate(
const SchemaCompilerSchemaContext &schema_context,
const SchemaCompilerDynamicContext &dynamic_context,
const bool annotate) -> SchemaCompilerTemplate {
if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "array") {
return {};
}

std::size_t minimum{1};
if (schema_context.schema.defines("minContains")) {
Expand Down Expand Up @@ -192,6 +209,12 @@ auto compiler_2019_09_applicator_unevaluateditems(
const SchemaCompilerSchemaContext &schema_context,
const SchemaCompilerDynamicContext &dynamic_context)
-> SchemaCompilerTemplate {
if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "array") {
return {};
}

SchemaCompilerTemplate children{compile(context, schema_context,
relative_dynamic_context,
empty_pointer, empty_pointer)};
Expand Down Expand Up @@ -227,6 +250,12 @@ auto compiler_2019_09_applicator_unevaluatedproperties(
const SchemaCompilerSchemaContext &schema_context,
const SchemaCompilerDynamicContext &dynamic_context)
-> SchemaCompilerTemplate {
if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "object") {
return {};
}

SchemaCompilerValueStrings dependencies{"unevaluatedProperties"};

if (schema_context.vocabularies.contains(
Expand Down
131 changes: 131 additions & 0 deletions src/jsonschema/default_compiler_draft4.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,12 @@ auto compiler_draft4_validation_required(
-> SchemaCompilerTemplate {
assert(schema_context.schema.at(dynamic_context.keyword).is_array());

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "object") {
return {};
}

if (schema_context.schema.at(dynamic_context.keyword).empty()) {
return {};
} else if (schema_context.schema.at(dynamic_context.keyword).size() > 1) {
Expand Down Expand Up @@ -308,6 +314,12 @@ auto compiler_draft4_applicator_properties(
return {};
}

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "object") {
return {};
}

const auto loads_unevaluated_keywords =
schema_context.vocabularies.contains(
"https://json-schema.org/draft/2019-09/vocab/applicator") ||
Expand Down Expand Up @@ -430,6 +442,12 @@ auto compiler_draft4_applicator_patternproperties(
return {};
}

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "object") {
return {};
}

const auto loads_unevaluated_keywords =
schema_context.vocabularies.contains(
"https://json-schema.org/draft/2019-09/vocab/applicator") ||
Expand Down Expand Up @@ -477,6 +495,12 @@ auto compiler_draft4_applicator_additionalproperties_conditional_annotation(
const SchemaCompilerSchemaContext &schema_context,
const SchemaCompilerDynamicContext &dynamic_context,
const bool annotate) -> SchemaCompilerTemplate {
if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "object") {
return {};
}

SchemaCompilerTemplate children{compile(context, schema_context,
relative_dynamic_context,
empty_pointer, empty_pointer)};
Expand Down Expand Up @@ -523,6 +547,13 @@ auto compiler_draft4_validation_pattern(
const SchemaCompilerDynamicContext &dynamic_context)
-> SchemaCompilerTemplate {
assert(schema_context.schema.at(dynamic_context.keyword).is_string());

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "string") {
return {};
}

const auto &regex_string{
schema_context.schema.at(dynamic_context.keyword).to_string()};
return {make<SchemaCompilerAssertionRegex>(
Expand All @@ -541,6 +572,12 @@ auto compiler_draft4_validation_format(
return {};
}

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "string") {
return {};
}

// Regular expressions

static const std::string FORMAT_REGEX_IPV4{
Expand Down Expand Up @@ -598,6 +635,12 @@ auto compiler_draft4_applicator_items_array(
return {};
}

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "array") {
return {};
}

// The idea here is to precompile all possibilities depending on the size
// of the instance array up to the size of the `items` keyword array.
// For example, if `items` is set to `[ {}, {}, {} ]`, we create 3
Expand Down Expand Up @@ -668,6 +711,12 @@ auto compiler_draft4_applicator_items_conditional_annotation(
const SchemaCompilerSchemaContext &schema_context,
const SchemaCompilerDynamicContext &dynamic_context,
const bool annotate) -> SchemaCompilerTemplate {
if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "array") {
return {};
}

if (is_schema(schema_context.schema.at(dynamic_context.keyword))) {
if (annotate) {
SchemaCompilerTemplate children;
Expand Down Expand Up @@ -712,6 +761,12 @@ auto compiler_draft4_applicator_additionalitems_from_cursor(
const SchemaCompilerSchemaContext &schema_context,
const SchemaCompilerDynamicContext &dynamic_context,
const std::size_t cursor, const bool annotate) -> SchemaCompilerTemplate {
if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "array") {
return {};
}

SchemaCompilerTemplate children{make<SchemaCompilerLoopItems>(
true, context, schema_context, relative_dynamic_context,
SchemaCompilerValueUnsignedInteger{cursor},
Expand All @@ -736,6 +791,12 @@ auto compiler_draft4_applicator_additionalitems_conditional_annotation(
const SchemaCompilerSchemaContext &schema_context,
const SchemaCompilerDynamicContext &dynamic_context,
const bool annotate) -> SchemaCompilerTemplate {
if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "array") {
return {};
}

assert(schema_context.schema.is_object());

// Nothing to do here
Expand Down Expand Up @@ -767,6 +828,12 @@ auto compiler_draft4_applicator_dependencies(
const SchemaCompilerSchemaContext &schema_context,
const SchemaCompilerDynamicContext &dynamic_context)
-> SchemaCompilerTemplate {
if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "object") {
return {};
}

assert(schema_context.schema.at(dynamic_context.keyword).is_object());
SchemaCompilerTemplate children;
SchemaCompilerValueStringMap dependencies;
Expand Down Expand Up @@ -840,6 +907,12 @@ auto compiler_draft4_validation_uniqueitems(
return {};
}

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "array") {
return {};
}

return {make<SchemaCompilerAssertionUnique>(
true, context, schema_context, dynamic_context, SchemaCompilerValueNone{},
SchemaCompilerTemplate{})};
Expand All @@ -854,6 +927,12 @@ auto compiler_draft4_validation_maxlength(
schema_context.schema.at(dynamic_context.keyword).is_integer_real());
assert(schema_context.schema.at(dynamic_context.keyword).is_positive());

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "string") {
return {};
}

// TODO: As an optimization, if `minLength` is set to the same number, do
// a single size equality assertion
return {make<SchemaCompilerAssertionSizeLess>(
Expand All @@ -876,6 +955,12 @@ auto compiler_draft4_validation_minlength(
schema_context.schema.at(dynamic_context.keyword).is_integer_real());
assert(schema_context.schema.at(dynamic_context.keyword).is_positive());

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "string") {
return {};
}

// TODO: As an optimization, if `maxLength` is set to the same number, do
// a single size equality assertion
return {make<SchemaCompilerAssertionSizeGreater>(
Expand All @@ -898,6 +983,12 @@ auto compiler_draft4_validation_maxitems(
schema_context.schema.at(dynamic_context.keyword).is_integer_real());
assert(schema_context.schema.at(dynamic_context.keyword).is_positive());

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "array") {
return {};
}

// TODO: As an optimization, if `minItems` is set to the same number, do
// a single size equality assertion
return {make<SchemaCompilerAssertionSizeLess>(
Expand All @@ -920,6 +1011,12 @@ auto compiler_draft4_validation_minitems(
schema_context.schema.at(dynamic_context.keyword).is_integer_real());
assert(schema_context.schema.at(dynamic_context.keyword).is_positive());

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "array") {
return {};
}

// TODO: As an optimization, if `maxItems` is set to the same number, do
// a single size equality assertion
return {make<SchemaCompilerAssertionSizeGreater>(
Expand All @@ -942,6 +1039,12 @@ auto compiler_draft4_validation_maxproperties(
schema_context.schema.at(dynamic_context.keyword).is_integer_real());
assert(schema_context.schema.at(dynamic_context.keyword).is_positive());

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "object") {
return {};
}

// TODO: As an optimization, if `minProperties` is set to the same number, do
// a single size equality assertion
return {make<SchemaCompilerAssertionSizeLess>(
Expand All @@ -964,6 +1067,12 @@ auto compiler_draft4_validation_minproperties(
schema_context.schema.at(dynamic_context.keyword).is_integer_real());
assert(schema_context.schema.at(dynamic_context.keyword).is_positive());

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "object") {
return {};
}

// TODO: As an optimization, if `maxProperties` is set to the same number, do
// a single size equality assertion
return {make<SchemaCompilerAssertionSizeGreater>(
Expand All @@ -984,6 +1093,13 @@ auto compiler_draft4_validation_maximum(
-> SchemaCompilerTemplate {
assert(schema_context.schema.at(dynamic_context.keyword).is_number());

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "integer" &&
schema_context.schema.at("type").to_string() != "number") {
return {};
}

// TODO: As an optimization, if `minimum` is set to the same number, do
// a single equality assertion

Expand All @@ -1010,6 +1126,13 @@ auto compiler_draft4_validation_minimum(
-> SchemaCompilerTemplate {
assert(schema_context.schema.at(dynamic_context.keyword).is_number());

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "integer" &&
schema_context.schema.at("type").to_string() != "number") {
return {};
}

// TODO: As an optimization, if `maximum` is set to the same number, do
// a single equality assertion

Expand All @@ -1036,6 +1159,14 @@ auto compiler_draft4_validation_multipleof(
-> SchemaCompilerTemplate {
assert(schema_context.schema.at(dynamic_context.keyword).is_number());
assert(schema_context.schema.at(dynamic_context.keyword).is_positive());

if (schema_context.schema.defines("type") &&
schema_context.schema.at("type").is_string() &&
schema_context.schema.at("type").to_string() != "integer" &&
schema_context.schema.at("type").to_string() != "number") {
return {};
}

return {make<SchemaCompilerAssertionDivisible>(
true, context, schema_context, dynamic_context,
JSON{schema_context.schema.at(dynamic_context.keyword)},
Expand Down
Loading

0 comments on commit 9e0e571

Please sign in to comment.