implements PLN-0121
This commit is contained in:
parent
1f1a92d43f
commit
cf14039077
@ -6,7 +6,7 @@
|
|||||||
{"type":"discussion","id":"DSC-0061","status":"open","ticket":"multi-frontend-sdk-canonical-definition","title":"Auditoria e centralizacao gradual da definicao canonica do SDK","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","sdk","stdlib","hostcalls","intrinsics","multi-frontend"],"agendas":[{"id":"AGD-0064","file":"AGD-0064-multi-frontend-sdk-canonical-definition.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0061","status":"open","ticket":"multi-frontend-sdk-canonical-definition","title":"Auditoria e centralizacao gradual da definicao canonica do SDK","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","sdk","stdlib","hostcalls","intrinsics","multi-frontend"],"agendas":[{"id":"AGD-0064","file":"AGD-0064-multi-frontend-sdk-canonical-definition.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0060","status":"open","ticket":"multi-frontend-validation-boundaries","title":"Separar validacoes de linguagem e validacoes de plataforma","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","compiler-pbs","backend","validation","multi-frontend"],"agendas":[{"id":"AGD-0063","file":"AGD-0063-multi-frontend-validation-boundaries.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0060","status":"open","ticket":"multi-frontend-validation-boundaries","title":"Separar validacoes de linguagem e validacoes de plataforma","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","compiler-pbs","backend","validation","multi-frontend"],"agendas":[{"id":"AGD-0063","file":"AGD-0063-multi-frontend-validation-boundaries.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0059","status":"open","ticket":"multi-frontend-common-lifecycle","title":"Extrair lifecycle comum das responsabilidades do frontend PBS","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","compiler-pbs","lifecycle","backend","multi-frontend"],"agendas":[{"id":"AGD-0062","file":"AGD-0062-multi-frontend-common-lifecycle.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0059","status":"open","ticket":"multi-frontend-common-lifecycle","title":"Extrair lifecycle comum das responsabilidades do frontend PBS","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","compiler-pbs","lifecycle","backend","multi-frontend"],"agendas":[{"id":"AGD-0062","file":"AGD-0062-multi-frontend-common-lifecycle.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0058","status":"in_progress","ticket":"multi-frontend-serializable-ir","title":"Manter a IR comum serializavel por design","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","ir","backend","serialization","multi-frontend"],"agendas":[{"id":"AGD-0061","file":"AGD-0061-multi-frontend-serializable-ir.md","status":"accepted","created_at":"2026-07-15","updated_at":"2026-07-15"}],"decisions":[{"id":"DEC-0044","file":"DEC-0044-serializable-common-ir-boundary.md","status":"accepted","created_at":"2026-07-15","updated_at":"2026-07-15","ref_agenda":"AGD-0061"}],"plans":[{"id":"PLN-0119","file":"PLN-0119-document-irbackend-serializability-invariants.md","status":"done","created_at":"2026-07-15","updated_at":"2026-07-15","ref_decisions":["DEC-0044"]},{"id":"PLN-0120","file":"PLN-0120-audit-public-irbackend-contract-shape.md","status":"done","created_at":"2026-07-15","updated_at":"2026-07-15","ref_decisions":["DEC-0044"]},{"id":"PLN-0121","file":"PLN-0121-add-serializable-irbackend-reflection-guardrails.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15","ref_decisions":["DEC-0044"]},{"id":"PLN-0122","file":"PLN-0122-prove-deterministic-irbackend-ordering.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15","ref_decisions":["DEC-0044"]},{"id":"PLN-0123","file":"PLN-0123-fix-concrete-irbackend-serialization-leaks.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15","ref_decisions":["DEC-0044"]}],"lessons":[]}
|
{"type":"discussion","id":"DSC-0058","status":"in_progress","ticket":"multi-frontend-serializable-ir","title":"Manter a IR comum serializavel por design","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","ir","backend","serialization","multi-frontend"],"agendas":[{"id":"AGD-0061","file":"AGD-0061-multi-frontend-serializable-ir.md","status":"accepted","created_at":"2026-07-15","updated_at":"2026-07-15"}],"decisions":[{"id":"DEC-0044","file":"DEC-0044-serializable-common-ir-boundary.md","status":"accepted","created_at":"2026-07-15","updated_at":"2026-07-15","ref_agenda":"AGD-0061"}],"plans":[{"id":"PLN-0119","file":"PLN-0119-document-irbackend-serializability-invariants.md","status":"done","created_at":"2026-07-15","updated_at":"2026-07-15","ref_decisions":["DEC-0044"]},{"id":"PLN-0120","file":"PLN-0120-audit-public-irbackend-contract-shape.md","status":"done","created_at":"2026-07-15","updated_at":"2026-07-15","ref_decisions":["DEC-0044"]},{"id":"PLN-0121","file":"PLN-0121-add-serializable-irbackend-reflection-guardrails.md","status":"done","created_at":"2026-07-15","updated_at":"2026-07-15","ref_decisions":["DEC-0044"]},{"id":"PLN-0122","file":"PLN-0122-prove-deterministic-irbackend-ordering.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15","ref_decisions":["DEC-0044"]},{"id":"PLN-0123","file":"PLN-0123-fix-concrete-irbackend-serialization-leaks.md","status":"open","created_at":"2026-07-15","updated_at":"2026-07-15","ref_decisions":["DEC-0044"]}],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0057","status":"done","ticket":"multi-frontend-frontend-backend-contract","title":"Estabilizar contrato entre frontend e backend comum","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","compiler-pbs","ir","backend","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0059","file":"discussion/lessons/DSC-0057-multi-frontend-frontend-backend-contract/LSN-0059-common-irbackend-handoff-and-backend-guardrails.md","status":"done","created_at":"2026-07-15","updated_at":"2026-07-15"}]}
|
{"type":"discussion","id":"DSC-0057","status":"done","ticket":"multi-frontend-frontend-backend-contract","title":"Estabilizar contrato entre frontend e backend comum","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","compiler-pbs","ir","backend","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0059","file":"discussion/lessons/DSC-0057-multi-frontend-frontend-backend-contract/LSN-0059-common-irbackend-handoff-and-backend-guardrails.md","status":"done","created_at":"2026-07-15","updated_at":"2026-07-15"}]}
|
||||||
{"type":"discussion","id":"DSC-0056","status":"done","ticket":"multi-frontend-remove-pbs-branches","title":"Generalizar o contrato LSP/editorial para frontends","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","compiler-pbs","studio","frontend","coupling","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0058","file":"discussion/lessons/DSC-0056-multi-frontend-remove-pbs-branches/LSN-0058-generic-frontend-editorial-contract-for-lsp.md","status":"done","created_at":"2026-07-15","updated_at":"2026-07-15"}]}
|
{"type":"discussion","id":"DSC-0056","status":"done","ticket":"multi-frontend-remove-pbs-branches","title":"Generalizar o contrato LSP/editorial para frontends","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","compiler-pbs","studio","frontend","coupling","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0058","file":"discussion/lessons/DSC-0056-multi-frontend-remove-pbs-branches/LSN-0058-generic-frontend-editorial-contract-for-lsp.md","status":"done","created_at":"2026-07-15","updated_at":"2026-07-15"}]}
|
||||||
{"type":"discussion","id":"DSC-0055","status":"done","ticket":"multi-frontend-compiler-vs-language-services","title":"Separar compilacao de servicos editoriais de frontend","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","studio","lsp","editor","frontend","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0056","file":"discussion/lessons/DSC-0055-multi-frontend-compiler-vs-language-services/LSN-0056-compile-first-frontends-with-optional-editorial-capabilities.md","status":"done","created_at":"2026-07-15","updated_at":"2026-07-15"}]}
|
{"type":"discussion","id":"DSC-0055","status":"done","ticket":"multi-frontend-compiler-vs-language-services","title":"Separar compilacao de servicos editoriais de frontend","created_at":"2026-07-15","updated_at":"2026-07-15","tags":["compiler","compiler-general","studio","lsp","editor","frontend","multi-frontend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0056","file":"discussion/lessons/DSC-0055-multi-frontend-compiler-vs-language-services/LSN-0056-compile-first-frontends-with-optional-editorial-capabilities.md","status":"done","created_at":"2026-07-15","updated_at":"2026-07-15"}]}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
id: PLN-0121
|
id: PLN-0121
|
||||||
ticket: multi-frontend-serializable-ir
|
ticket: multi-frontend-serializable-ir
|
||||||
title: Add serializable IRBackend reflection guardrails
|
title: Add serializable IRBackend reflection guardrails
|
||||||
status: open
|
status: done
|
||||||
created: 2026-07-15
|
created: 2026-07-15
|
||||||
ref_decisions: [DEC-0044]
|
ref_decisions: [DEC-0044]
|
||||||
tags: [compiler, compiler-general, ir, backend, serialization, multi-frontend]
|
tags: [compiler, compiler-general, ir, backend, serialization, multi-frontend]
|
||||||
|
|||||||
@ -43,8 +43,8 @@ to concrete positive/negative test evidence and current status.
|
|||||||
| G20-4.1.1 | `IRBackend` MUST be the common frontend-to-backend executable handoff. | `LowerToIRVMServiceTest#lowerMustAcceptManuallyConstructedCommonIRBackend` | N/A | pass | Direct backend lowering from manually constructed common IRBackend proves PBS parser/frontend services are not required. |
|
| G20-4.1.1 | `IRBackend` MUST be the common frontend-to-backend executable handoff. | `LowerToIRVMServiceTest#lowerMustAcceptManuallyConstructedCommonIRBackend` | N/A | pass | Direct backend lowering from manually constructed common IRBackend proves PBS parser/frontend services are not required. |
|
||||||
| G20-4.1.2 | Common backend code MUST NOT depend on `p.studio.compiler.pbs`. | `CommonBackendArchitectureTest#commonBackendMustNotImportPbsFrontendPackages` | N/A | pass | Source-level architectural guard rejects PBS frontend imports in common backend packages. |
|
| G20-4.1.2 | Common backend code MUST NOT depend on `p.studio.compiler.pbs`. | `CommonBackendArchitectureTest#commonBackendMustNotImportPbsFrontendPackages` | N/A | pass | Source-level architectural guard rejects PBS frontend imports in common backend packages. |
|
||||||
| G20-4.1.3 | Public `IRBackend` contract MUST NOT expose PBS AST, token, parser, semantic, or editorial types. | `IRBackendExecutableContractTest#publicIRBackendContractMustNotExposePbsTypes` | N/A | pass | Reflection guard covers public contract fields, constructors, methods, and record components. |
|
| G20-4.1.3 | Public `IRBackend` contract MUST NOT expose PBS AST, token, parser, semantic, or editorial types. | `IRBackendExecutableContractTest#publicIRBackendContractMustNotExposePbsTypes` | N/A | pass | Reflection guard covers public contract fields, constructors, methods, and record components. |
|
||||||
| G20-4.2.1 | Public `IRBackend` contract types MUST remain modelable as an acyclic, deterministic data graph. | Planned: `IRBackendExecutableContractTest` serializable contract guardrails from `PLN-0121`; deterministic ordering tests from `PLN-0122` | N/A | missing | Added by DEC-0044; executable evidence is planned before this row can move to pass. |
|
| G20-4.2.1 | Public `IRBackend` contract types MUST remain modelable as an acyclic, deterministic data graph. | `IRBackendExecutableContractTest#publicIRBackendContractMustExposeOnlySerializableShapes`; planned deterministic ordering tests from `PLN-0122` | N/A | partial | Public shape guardrails exist; deterministic ordering evidence is still planned before this row can move to pass. |
|
||||||
| G20-4.2.2 | Public `IRBackend` contract types MUST NOT expose callbacks, services, mutable/unordered collection contracts, frontend-owned objects, process-dependent lazy values, cyclic public references, or wire-format commitments. | Planned: `IRBackendExecutableContractTest` serializable contract guardrails from `PLN-0121` | N/A | missing | Guardrail implementation is intentionally separate from the spec update. |
|
| G20-4.2.2 | Public `IRBackend` contract types MUST NOT expose callbacks, services, mutable/unordered collection contracts, frontend-owned objects, process-dependent lazy values, cyclic public references, or wire-format commitments. | `IRBackendExecutableContractTest#publicIRBackendContractMustExposeOnlySerializableShapes` | N/A | pass | Reflection guard covers public contract fields, constructors, methods, record components, and generic type arguments. |
|
||||||
| G20-4.2.3 | Public `IRBackend` cross-object references MUST use explicit ids or stable symbolic keys. | Planned: public contract audit from `PLN-0120`; targeted leak fixes from `PLN-0123` when needed | N/A | missing | Existing `FileId`, `ModuleId`, `CallableId`, and `IntrinsicId` are expected allowed values when table scope is deterministic. |
|
| G20-4.2.3 | Public `IRBackend` cross-object references MUST use explicit ids or stable symbolic keys. | Planned: public contract audit from `PLN-0120`; targeted leak fixes from `PLN-0123` when needed | N/A | missing | Existing `FileId`, `ModuleId`, `CallableId`, and `IntrinsicId` are expected allowed values when table scope is deterministic. |
|
||||||
| G20-6.2 | `IRVM_EXT` MUST declare structural metadata (`pops/pushes/is_branch/is_terminator`). | `IRVMValidatorTest#validateMustApplyStructuralMetadataForCustomInternalExtension`; `IRVMValidatorTest#validateMustRejectCustomInternalExtensionWhenStructuralMetadataUnderflowsStack`; `IRVMOp` record contract (`pops/pushes/branch/terminator/internal`) | N/A | pass | Dedicated extension fixtures now assert structural metadata is consumed by validation behavior. |
|
| G20-6.2 | `IRVM_EXT` MUST declare structural metadata (`pops/pushes/is_branch/is_terminator`). | `IRVMValidatorTest#validateMustApplyStructuralMetadataForCustomInternalExtension`; `IRVMValidatorTest#validateMustRejectCustomInternalExtensionWhenStructuralMetadataUnderflowsStack`; `IRVMOp` record contract (`pops/pushes/branch/terminator/internal`) | N/A | pass | Dedicated extension fixtures now assert structural metadata is consumed by validation behavior. |
|
||||||
| G20-6.3 | `IRVM_EXT` MUST be eliminable before bytecode emission. | `OptimizeIRVMServiceTest#optimizeDefaultPassesMustEliminateUnreachableInternalExtensionBeforeEmission` | `EmitBytecodePipelineStageTest#runMustFailWhenInternalOpcodesRemain`; `EmitBytecodePipelineStageTest#runMustFailWhenInternalOpcodesRemainEvenWithNonEmptyEmissionPlan`; `IRVMValidatorTest#validateMustRejectInternalOpcodeWhenConfigured` | pass | Optimizer elimination path and emit-stage hard rejection path are both covered. |
|
| G20-6.3 | `IRVM_EXT` MUST be eliminable before bytecode emission. | `OptimizeIRVMServiceTest#optimizeDefaultPassesMustEliminateUnreachableInternalExtensionBeforeEmission` | `EmitBytecodePipelineStageTest#runMustFailWhenInternalOpcodesRemain`; `EmitBytecodePipelineStageTest#runMustFailWhenInternalOpcodesRemainEvenWithNonEmptyEmissionPlan`; `IRVMValidatorTest#validateMustRejectInternalOpcodeWhenConfigured` | pass | Optimizer elimination path and emit-stage hard rejection path are both covered. |
|
||||||
|
|||||||
@ -39,6 +39,9 @@ class BackendConformanceMatrixSpecTest {
|
|||||||
"G20-4.1.1",
|
"G20-4.1.1",
|
||||||
"G20-4.1.2",
|
"G20-4.1.2",
|
||||||
"G20-4.1.3",
|
"G20-4.1.3",
|
||||||
|
"G20-4.2.1",
|
||||||
|
"G20-4.2.2",
|
||||||
|
"G20-4.2.3",
|
||||||
"G20-6.2",
|
"G20-6.2",
|
||||||
"G20-6.3",
|
"G20-6.3",
|
||||||
"G20-6.4",
|
"G20-6.4",
|
||||||
|
|||||||
@ -11,11 +11,16 @@ import p.studio.compiler.source.tables.IntrinsicReference;
|
|||||||
import p.studio.compiler.source.tables.ModuleReference;
|
import p.studio.compiler.source.tables.ModuleReference;
|
||||||
import p.studio.utilities.structures.ReadOnlyList;
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
@ -151,6 +156,57 @@ class IRBackendExecutableContractTest {
|
|||||||
"public IRBackend contract must not expose PBS frontend types: " + violations);
|
"public IRBackend contract must not expose PBS frontend types: " + violations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void publicIRBackendContractMustExposeOnlySerializableShapes() {
|
||||||
|
final var violations = new ArrayList<String>();
|
||||||
|
|
||||||
|
for (final var contractType : PUBLIC_CONTRACT_TYPES) {
|
||||||
|
inspectSerializableContractType(contractType.getName(), contractType, violations);
|
||||||
|
for (final var field : contractType.getFields()) {
|
||||||
|
inspectSerializableContractType(
|
||||||
|
contractType.getName() + "#" + field.getName(),
|
||||||
|
field.getGenericType(),
|
||||||
|
violations);
|
||||||
|
}
|
||||||
|
for (final var constructor : contractType.getConstructors()) {
|
||||||
|
for (final var parameterType : constructor.getGenericParameterTypes()) {
|
||||||
|
inspectSerializableContractType(
|
||||||
|
contractType.getName() + "#<init>",
|
||||||
|
parameterType,
|
||||||
|
violations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (final var method : contractType.getMethods()) {
|
||||||
|
if (method.getDeclaringClass().equals(Object.class)
|
||||||
|
|| !Modifier.isPublic(method.getModifiers())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
inspectSerializableContractType(
|
||||||
|
contractType.getName() + "#" + method.getName(),
|
||||||
|
method.getGenericReturnType(),
|
||||||
|
violations);
|
||||||
|
for (final var parameterType : method.getGenericParameterTypes()) {
|
||||||
|
inspectSerializableContractType(
|
||||||
|
contractType.getName() + "#" + method.getName(),
|
||||||
|
parameterType,
|
||||||
|
violations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (contractType.isRecord()) {
|
||||||
|
for (final var component : contractType.getRecordComponents()) {
|
||||||
|
inspectSerializableContractType(
|
||||||
|
contractType.getName() + "#" + component.getName(),
|
||||||
|
component.getGenericType(),
|
||||||
|
violations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
violations.isEmpty(),
|
||||||
|
"public IRBackend contract must expose only serializable-by-design shapes: " + violations);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void callInstructionMustRequireCategorySpecificMetadata() {
|
void callInstructionMustRequireCategorySpecificMetadata() {
|
||||||
assertThrows(IllegalArgumentException.class, () -> new IRBackendExecutableFunction.Instruction(
|
assertThrows(IllegalArgumentException.class, () -> new IRBackendExecutableFunction.Instruction(
|
||||||
@ -515,4 +571,69 @@ class IRBackendExecutableContractTest {
|
|||||||
violations.add(owner + " -> " + typeName);
|
violations.add(owner + " -> " + typeName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void inspectSerializableContractType(
|
||||||
|
final String owner,
|
||||||
|
final Type type,
|
||||||
|
final ArrayList<String> violations) {
|
||||||
|
if (type == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type instanceof ParameterizedType parameterizedType) {
|
||||||
|
inspectSerializableContractType(owner, parameterizedType.getRawType(), violations);
|
||||||
|
for (final var argument : parameterizedType.getActualTypeArguments()) {
|
||||||
|
inspectSerializableContractType(owner, argument, violations);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(type instanceof Class<?> clazz)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (clazz.isPrimitive()
|
||||||
|
|| clazz.isEnum()
|
||||||
|
|| AUDITED_SUPPORT_TYPES.contains(clazz)
|
||||||
|
|| PUBLIC_CONTRACT_TYPES.contains(clazz)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isForbiddenFrontendOwnedType(clazz)) {
|
||||||
|
violations.add(owner + " exposes frontend-owned type " + clazz.getName());
|
||||||
|
}
|
||||||
|
if (isForbiddenCallbackShape(clazz)) {
|
||||||
|
violations.add(owner + " exposes callback shape " + clazz.getName());
|
||||||
|
}
|
||||||
|
if (isForbiddenMutableOrUnorderedCollection(clazz)) {
|
||||||
|
violations.add(owner + " exposes mutable or unordered collection " + clazz.getName());
|
||||||
|
}
|
||||||
|
if (isForbiddenServiceShape(clazz)) {
|
||||||
|
violations.add(owner + " exposes service-like shape " + clazz.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isForbiddenFrontendOwnedType(final Class<?> clazz) {
|
||||||
|
final var packageName = clazz.getPackageName();
|
||||||
|
return packageName.startsWith("p.studio.compiler.pbs")
|
||||||
|
|| packageName.contains(".parser")
|
||||||
|
|| packageName.contains(".semantic")
|
||||||
|
|| packageName.contains(".editor");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isForbiddenCallbackShape(final Class<?> clazz) {
|
||||||
|
return clazz.equals(Runnable.class)
|
||||||
|
|| Callable.class.isAssignableFrom(clazz)
|
||||||
|
|| Function.class.isAssignableFrom(clazz)
|
||||||
|
|| clazz.getPackageName().startsWith("java.util.function");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isForbiddenMutableOrUnorderedCollection(final Class<?> clazz) {
|
||||||
|
return !clazz.equals(ReadOnlyList.class)
|
||||||
|
&& (Collection.class.isAssignableFrom(clazz) || Map.class.isAssignableFrom(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isForbiddenServiceShape(final Class<?> clazz) {
|
||||||
|
final var simpleName = clazz.getSimpleName();
|
||||||
|
return simpleName.endsWith("Service")
|
||||||
|
|| simpleName.endsWith("Registry")
|
||||||
|
|| simpleName.endsWith("Visitor")
|
||||||
|
|| simpleName.endsWith("Provider");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user