Skip to content

Commit d876a5e

Browse files
committed
Prevent further broken reference linter errors
Signed-off-by: Juan Cruz Viotti <[email protected]>
1 parent 94ff49b commit d876a5e

22 files changed

+664
-74
lines changed

src/core/jsonschema/frame.cc

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -987,13 +987,7 @@ auto SchemaFrame::dereference(const Location &location,
987987
return {SchemaReferenceType::Static, destination->second};
988988
}
989989

990-
auto SchemaFrame::references_to(const Pointer &pointer) const -> std::vector<
991-
std::reference_wrapper<const typename References::value_type>> {
992-
std::vector<std::reference_wrapper<const typename References::value_type>>
993-
result;
994-
995-
// TODO: This is currently very slow, as we need to loop on every reference
996-
// to brute force whether it points to the desired entry or not
990+
auto SchemaFrame::has_references_to(const Pointer &pointer) const -> bool {
997991
for (const auto &reference : this->references_) {
998992
assert(!reference.first.second.empty());
999993
assert(reference.first.second.back().is_property());
@@ -1003,7 +997,7 @@ auto SchemaFrame::references_to(const Pointer &pointer) const -> std::vector<
1003997
{reference.first.first, reference.second.destination})};
1004998
if (match != this->locations_.cend() &&
1005999
match->second.pointer == pointer) {
1006-
result.emplace_back(reference);
1000+
return true;
10071001
}
10081002
} else {
10091003
for (const auto &location : this->locations_) {
@@ -1013,14 +1007,44 @@ auto SchemaFrame::references_to(const Pointer &pointer) const -> std::vector<
10131007
if (!reference.second.fragment.has_value() ||
10141008
URI{location.first.second}.fragment().value_or("") ==
10151009
reference.second.fragment.value()) {
1016-
result.emplace_back(reference);
1010+
return true;
10171011
}
10181012
}
10191013
}
10201014
}
10211015
}
10221016

1023-
return result;
1017+
return false;
1018+
}
1019+
1020+
auto SchemaFrame::has_references_through(const Pointer &pointer) const -> bool {
1021+
for (const auto &reference : this->references_) {
1022+
assert(!reference.first.second.empty());
1023+
assert(reference.first.second.back().is_property());
1024+
1025+
if (reference.first.first == SchemaReferenceType::Static) {
1026+
const auto match{this->locations_.find(
1027+
{reference.first.first, reference.second.destination})};
1028+
if (match != this->locations_.cend() &&
1029+
match->second.pointer.starts_with(pointer)) {
1030+
return true;
1031+
}
1032+
} else {
1033+
for (const auto &location : this->locations_) {
1034+
if (location.second.type == LocationType::Anchor &&
1035+
location.first.first == SchemaReferenceType::Dynamic &&
1036+
location.second.pointer.starts_with(pointer)) {
1037+
if (!reference.second.fragment.has_value() ||
1038+
URI{location.first.second}.fragment().value_or("") ==
1039+
reference.second.fragment.value()) {
1040+
return true;
1041+
}
1042+
}
1043+
}
1044+
}
1045+
}
1046+
1047+
return false;
10241048
}
10251049

10261050
} // namespace sourcemeta::core

src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,13 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaFrame {
233233
-> std::pair<SchemaReferenceType,
234234
std::optional<std::reference_wrapper<const Location>>>;
235235

236-
/// Find all references to a given location pointer
237-
[[nodiscard]] auto references_to(const Pointer &pointer) const -> std::vector<
238-
std::reference_wrapper<const typename References::value_type>>;
236+
/// Check if there are any references to a given location pointer
237+
[[nodiscard]] auto has_references_to(const Pointer &pointer) const -> bool;
238+
239+
/// Check if there are any references that go through a given location pointer
240+
/// (i.e., references to the pointer or any of its descendants)
241+
[[nodiscard]] auto has_references_through(const Pointer &pointer) const
242+
-> bool;
239243

240244
private:
241245
Mode mode_;

src/extension/alterschema/common/content_schema_without_media_type.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ class ContentSchemaWithoutMediaType final : public SchemaTransformRule {
1010
condition(const sourcemeta::core::JSON &schema,
1111
const sourcemeta::core::JSON &,
1212
const sourcemeta::core::Vocabularies &vocabularies,
13-
const sourcemeta::core::SchemaFrame &,
14-
const sourcemeta::core::SchemaFrame::Location &,
13+
const sourcemeta::core::SchemaFrame &frame,
14+
const sourcemeta::core::SchemaFrame::Location &location,
1515
const sourcemeta::core::SchemaWalker &,
1616
const sourcemeta::core::SchemaResolver &) const
1717
-> sourcemeta::core::SchemaTransformRule::Result override {
@@ -20,6 +20,8 @@ class ContentSchemaWithoutMediaType final : public SchemaTransformRule {
2020
Vocabularies::Known::JSON_Schema_2019_09_Content}) &&
2121
schema.is_object() && schema.defines("contentSchema") &&
2222
!schema.defines("contentMediaType"));
23+
ONLY_CONTINUE_IF(!frame.has_references_through(
24+
location.relative_pointer.concat({"contentSchema"})));
2325
return APPLIES_TO_KEYWORDS("contentSchema");
2426
}
2527

src/extension/alterschema/common/else_empty.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class ElseEmpty final : public SchemaTransformRule {
77

88
[[nodiscard]] auto
99
condition(const JSON &schema, const JSON &, const Vocabularies &vocabularies,
10-
const SchemaFrame &, const SchemaFrame::Location &,
10+
const SchemaFrame &frame, const SchemaFrame::Location &location,
1111
const SchemaWalker &, const SchemaResolver &) const
1212
-> SchemaTransformRule::Result override {
1313
ONLY_CONTINUE_IF(
@@ -20,6 +20,8 @@ class ElseEmpty final : public SchemaTransformRule {
2020
(schema.at("else").is_object() ||
2121
(!schema.defines("if") ||
2222
!(schema.at("if").is_boolean() && schema.at("if").to_boolean()))));
23+
ONLY_CONTINUE_IF(!frame.has_references_through(
24+
location.relative_pointer.concat({"else"})));
2325
return APPLIES_TO_KEYWORDS("else");
2426
}
2527

src/extension/alterschema/common/else_without_if.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ class ElseWithoutIf final : public SchemaTransformRule {
99
condition(const sourcemeta::core::JSON &schema,
1010
const sourcemeta::core::JSON &,
1111
const sourcemeta::core::Vocabularies &vocabularies,
12-
const sourcemeta::core::SchemaFrame &,
13-
const sourcemeta::core::SchemaFrame::Location &,
12+
const sourcemeta::core::SchemaFrame &frame,
13+
const sourcemeta::core::SchemaFrame::Location &location,
1414
const sourcemeta::core::SchemaWalker &,
1515
const sourcemeta::core::SchemaResolver &) const
1616
-> sourcemeta::core::SchemaTransformRule::Result override {
@@ -20,6 +20,8 @@ class ElseWithoutIf final : public SchemaTransformRule {
2020
Vocabularies::Known::JSON_Schema_Draft_7}) &&
2121
schema.is_object() && schema.defines("else") &&
2222
!schema.defines("if"));
23+
ONLY_CONTINUE_IF(!frame.has_references_through(
24+
location.relative_pointer.concat({"else"})));
2325
return APPLIES_TO_KEYWORDS("else");
2426
}
2527

src/extension/alterschema/common/if_without_then_else.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ class IfWithoutThenElse final : public SchemaTransformRule {
1010
condition(const sourcemeta::core::JSON &schema,
1111
const sourcemeta::core::JSON &,
1212
const sourcemeta::core::Vocabularies &vocabularies,
13-
const sourcemeta::core::SchemaFrame &,
14-
const sourcemeta::core::SchemaFrame::Location &,
13+
const sourcemeta::core::SchemaFrame &frame,
14+
const sourcemeta::core::SchemaFrame::Location &location,
1515
const sourcemeta::core::SchemaWalker &,
1616
const sourcemeta::core::SchemaResolver &) const
1717
-> sourcemeta::core::SchemaTransformRule::Result override {
@@ -21,6 +21,8 @@ class IfWithoutThenElse final : public SchemaTransformRule {
2121
Vocabularies::Known::JSON_Schema_Draft_7}) &&
2222
schema.is_object() && schema.defines("if") &&
2323
!schema.defines("then") && !schema.defines("else"));
24+
ONLY_CONTINUE_IF(!frame.has_references_through(
25+
location.relative_pointer.concat({"if"})));
2426
return APPLIES_TO_KEYWORDS("if");
2527
}
2628

src/extension/alterschema/common/non_applicable_additional_items.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ class NonApplicableAdditionalItems final : public SchemaTransformRule {
1010
condition(const sourcemeta::core::JSON &schema,
1111
const sourcemeta::core::JSON &,
1212
const sourcemeta::core::Vocabularies &vocabularies,
13-
const sourcemeta::core::SchemaFrame &,
14-
const sourcemeta::core::SchemaFrame::Location &,
13+
const sourcemeta::core::SchemaFrame &frame,
14+
const sourcemeta::core::SchemaFrame::Location &location,
1515
const sourcemeta::core::SchemaWalker &,
1616
const sourcemeta::core::SchemaResolver &) const
1717
-> sourcemeta::core::SchemaTransformRule::Result override {
@@ -23,6 +23,9 @@ class NonApplicableAdditionalItems final : public SchemaTransformRule {
2323
Vocabularies::Known::JSON_Schema_Draft_3}) &&
2424
schema.is_object() && schema.defines("additionalItems"));
2525

26+
ONLY_CONTINUE_IF(!frame.has_references_through(
27+
location.relative_pointer.concat({"additionalItems"})));
28+
2629
if (schema.defines("items") && is_schema(schema.at("items"))) {
2730
return APPLIES_TO_KEYWORDS("additionalItems", "items");
2831
} else if (!schema.defines("items")) {

src/extension/alterschema/common/non_applicable_type_specific_keywords.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ class NonApplicableTypeSpecificKeywords final : public SchemaTransformRule {
99
condition(const sourcemeta::core::JSON &schema,
1010
const sourcemeta::core::JSON &,
1111
const sourcemeta::core::Vocabularies &vocabularies,
12-
const sourcemeta::core::SchemaFrame &,
13-
const sourcemeta::core::SchemaFrame::Location &,
12+
const sourcemeta::core::SchemaFrame &frame,
13+
const sourcemeta::core::SchemaFrame::Location &location,
1414
const sourcemeta::core::SchemaWalker &walker,
1515
const sourcemeta::core::SchemaResolver &) const
1616
-> sourcemeta::core::SchemaTransformRule::Result override {
@@ -73,6 +73,12 @@ class NonApplicableTypeSpecificKeywords final : public SchemaTransformRule {
7373
// If none of the types that the keyword applies to is a valid
7474
// type for the current schema, then by definition we can remove it
7575
if ((metadata.instances & current_types).none()) {
76+
// Skip keywords that have references pointing to them
77+
if (frame.has_references_through(
78+
location.relative_pointer.concat({entry.first}))) {
79+
continue;
80+
}
81+
7682
positions.push_back(Pointer{entry.first});
7783
}
7884
}

src/extension/alterschema/common/not_false.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class NotFalse final : public SchemaTransformRule {
88

99
[[nodiscard]] auto
1010
condition(const JSON &schema, const JSON &, const Vocabularies &vocabularies,
11-
const SchemaFrame &, const SchemaFrame::Location &,
11+
const SchemaFrame &frame, const SchemaFrame::Location &location,
1212
const SchemaWalker &, const SchemaResolver &) const
1313
-> SchemaTransformRule::Result override {
1414
ONLY_CONTINUE_IF(vocabularies.contains_any(
@@ -20,6 +20,8 @@ class NotFalse final : public SchemaTransformRule {
2020
schema.is_object() && schema.defines("not") &&
2121
schema.at("not").is_boolean() &&
2222
!schema.at("not").to_boolean());
23+
ONLY_CONTINUE_IF(!frame.has_references_through(
24+
location.relative_pointer.concat({"not"})));
2325
return APPLIES_TO_KEYWORDS("not");
2426
}
2527

src/extension/alterschema/common/then_empty.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class ThenEmpty final : public SchemaTransformRule {
77

88
[[nodiscard]] auto
99
condition(const JSON &schema, const JSON &, const Vocabularies &vocabularies,
10-
const SchemaFrame &, const SchemaFrame::Location &,
10+
const SchemaFrame &frame, const SchemaFrame::Location &location,
1111
const SchemaWalker &, const SchemaResolver &) const
1212
-> SchemaTransformRule::Result override {
1313
ONLY_CONTINUE_IF(
@@ -20,6 +20,8 @@ class ThenEmpty final : public SchemaTransformRule {
2020
(schema.at("then").is_object() ||
2121
(!schema.defines("if") ||
2222
!(schema.at("if").is_boolean() && schema.at("if").to_boolean()))));
23+
ONLY_CONTINUE_IF(!frame.has_references_through(
24+
location.relative_pointer.concat({"then"})));
2325
return APPLIES_TO_KEYWORDS("then");
2426
}
2527

0 commit comments

Comments
 (0)