Merge pull request 'schemagen: reject self-referential array $ref cycles instead of crashing' (#49) from weaselbot/weaseljson:weaselbot/issue-33 into main
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-arm64, ubuntu-latest-arm64, true) (push) Successful in 57s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-arm64, ubuntu-latest-arm64, false) (push) Successful in 52s
CI / pre-commit (push) Successful in 51s
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-amd64, ubuntu-latest-amd64, true) (push) Successful in 1m35s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-amd64, ubuntu-latest-amd64, false) (push) Successful in 1m28s
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-arm64, ubuntu-latest-arm64, true) (push) Successful in 57s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-arm64, ubuntu-latest-arm64, false) (push) Successful in 52s
CI / pre-commit (push) Successful in 51s
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-amd64, ubuntu-latest-amd64, true) (push) Successful in 1m35s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-amd64, ubuntu-latest-amd64, false) (push) Successful in 1m28s
Reviewed-on: #49
This commit was merged in pull request #49.
This commit is contained in:
@@ -272,6 +272,24 @@ class Builder:
|
||||
"""Names generated internally that must not collide with user types."""
|
||||
return name in ("Root", "RootScalar")
|
||||
|
||||
@staticmethod
|
||||
def _array_reaches(target, ty):
|
||||
"""Return True if `target` can be reached from `ty` by following
|
||||
TArr element types. This detects self-referential array cycles that
|
||||
cannot be expressed as C++ structs."""
|
||||
seen = set()
|
||||
stack = [ty]
|
||||
while stack:
|
||||
cur = stack.pop()
|
||||
if cur is target:
|
||||
return True
|
||||
if id(cur) in seen:
|
||||
continue
|
||||
seen.add(id(cur))
|
||||
if isinstance(cur, TArr):
|
||||
stack.append(cur.elem)
|
||||
return False
|
||||
|
||||
def ref_name(self, ref):
|
||||
if not ref.startswith("#/"):
|
||||
raise GenError(f"only local $ref supported, got: {ref}")
|
||||
@@ -359,6 +377,12 @@ class Builder:
|
||||
)
|
||||
t.elem = elem
|
||||
t.elem_nullable = elem_nullable
|
||||
# Self-referential array cycles (directly or through a chain of
|
||||
# array definitions) cannot be represented as a C++ value type.
|
||||
if self._array_reaches(t, elem):
|
||||
raise GenError(
|
||||
"recursive array type is not supported: " f"{defname or hint!r}"
|
||||
)
|
||||
return result
|
||||
|
||||
scalar = {
|
||||
|
||||
Reference in New Issue
Block a user