Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile out assertions that would never run anyway #1099

Merged
merged 1 commit into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading