Skip to content

Behavior Annex cannot name a Data Model Annex enumeration literal 🤖 #3282

Description

@lwrage

Summary

The Data Model Annex declares an enumeration data type by giving a data classifier Data_Model::Data_Representation => Enum together with Data_Model::Enumerators => ("A", "B"). An enumerator is a StringLiteral inside that property association, not a declared EnumerationLiteral in any AADL namespace, so the Behavior Annex can only name it through the AS5506/3 Rev A D.7 property_reference alternative that writes a prefix before #. value_constant has no enumeration-literal alternative, so a bare enumerator name is not legal BA and is correctly rejected; the prefixed property reference is the only standard-legal form.

That form does not work, and it fails silently.

DeclarativeToStrictTranslator.toPropertyReference resolves the property definition with resolveQualified, then resolves each NamedPropertyField against that definition with resolvePropertyField. For Data_Model::Enumerators the definition is a Property whose type is list of aadlstring, so field resolution walks BasicProperty to the ListType and finds no named child. The prefix's own property association — the one that actually carries ("A", "B") — is never consulted, because that fallback only runs when resolveQualified fails to find the property definition. The field holder is therefore built with a null element.

Nothing reports that. AadlBaTypeChecker.checkResolvedModel only inspects ElementHolder, and PropertyElementHolder extends BehaviorElement, IndexableElement rather than ElementHolder, so the null element is invisible to the resolution check and checkResolvedTypes proceeds. AadlBaUtils.getDataRepresentation(PropertyReference) then dereferences the null element and throws:

java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "element" is null
	at org.osate.ba.utils.AadlBaUtils.getDataRepresentation(AadlBaUtils.java:321)
	at org.osate.ba.utils.AadlBaUtils.getDataRepresentation(AadlBaUtils.java:367)
	at org.osate.ba.utils.AadlBaUtils.getDataRepresentation(AadlBaUtils.java:468)
	at org.osate.ba.utils.AadlBaUtils.getTypeHolder(AadlBaUtils.java:922)
	at org.osate.ba.utils.AadlBaUtils.getTypeHolder(AadlBaUtils.java:1036)
	at org.osate.ba.analyzers.AadlBaTypeChecker.getType(AadlBaTypeChecker.java:536)
	at org.osate.ba.analyzers.AadlBaTypeChecker.checkFactor(AadlBaTypeChecker.java:513)
	...
	at org.osate.ba.analyzers.AadlBaTypeChecker.checkResolvedTypes(AadlBaTypeChecker.java:143)
	at org.osate.xtext.aadl2.ba.validation.BehaviorAnnexValidator.checkBehaviorAnnex(BehaviorAnnexValidator.java:204)

AadlBaTypeChecker.getType catches only DimensionException and UnsupportedOperationException, so the NullPointerException escapes checkResolvedTypes, aborting the remaining strict checkers for that annex. Xtext swallows it. The net effect is that a reference to an enumerator, a reference to an enumerator that does not exist, and every later diagnostic in the same annex are all reported as nothing at all.

Even if the field resolved, the type would be wrong. A StringLiteral is a PropertyExpression, so getDataRepresentation(PropertyReference) would classify the enumerator as STRING, which does not conform to the ENUM representation of the data classifier that declares it. AadlBaUtils.toDataModelEnumLiteral and DataModelEnumLiteral exist for exactly this pairing of classifier and string literal, and both currently have no callers.

Reproduction

The model has no unrelated AADL errors and no unresolved core references.

package EnumProbe
public
	with Data_Model;

	data direction_type
		properties
			Data_Model::Data_Representation => Enum;
			Data_Model::Enumerators => ("Opening", "Closing");
	end direction_type;

	data int_type
		properties
			Data_Model::Data_Representation => Integer;
	end int_type;

	data bool_type
		properties
			Data_Model::Data_Representation => Boolean;
	end bool_type;

	abstract host
	end host;

	abstract implementation host.impl
		subcomponents
			state_value: data direction_type;
			int_value: data int_type;
			bool_value: data bool_type;
		annex behavior_specification {**
			states
				start: initial state;
				done: final state;
			transitions
				canary: start -[]-> done {
					int_value := bool_value
				};
				enumerator: start -[]-> done {
					state_value := direction_type#Data_Model::Enumerators.Opening
				};
				absent: start -[]-> done {
					state_value := direction_type#Data_Model::Enumerators.NotAnEnumerator
				};
				numeric: start -[]-> done {
					int_value := direction_type#Data_Model::Enumerators.Opening + 1
				};
		**};
	end host.impl;
end EnumProbe;

Validating this reports exactly one diagnostic, on the canary transition:

ERROR | [bool_value] | type error for 'assignment', 'EnumProbe::int_type' expected, found 'EnumProbe::bool_type'.

The canary transition proves the type checker runs and works. The three transitions after it report nothing:

  • enumerator is the standard-legal form and should be accepted, but is accepted only because validation has already been aborted.
  • absent names an enumerator that is not in the Enumerators list and must be rejected.
  • numeric uses an enumeration value where the operator requires a numeric type and must be rejected.

Removing the canary transition leaves the annex with no diagnostics at all.

Expected behavior

  • direction_type#Data_Model::Enumerators.Opening resolves to the StringLiteral for "Opening" in the Enumerators association of direction_type, and types as the ENUM representation of direction_type, so assigning it to a direction_type value is accepted and assigning it to a value of a different enumeration data type is rejected.
  • direction_type#Data_Model::Enumerators.NotAnEnumerator is reported, because the name is not an element of the Enumerators list.
  • Using an enumeration value as an operand of an arithmetic operator is reported.
  • No NullPointerException escapes the strict checkers, and diagnostics that follow an unresolvable property field in the same annex are still reported. This applies to any unresolvable property field, not only an enumerator.
  • The first property name holder keeps the referenced Property definition rather than a declaratively selected PropertyAssociation, preserving Keep prefixed Behavior Annex property references symbolic for instance lookup 🤖 #3222.

Relevant code

  • ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/translation/DeclarativeToStrictTranslator.java — toPropertyReference chooses primaryElement and walks fields; resolvePropertyField(Element, String) and resolvePropertyField(EObject, String) never see the prefix's property association when the property definition resolves.
  • ba/org.osate.ba/src/org/osate/ba/utils/AadlBaUtils.java — getDataRepresentation(PropertyReference) dereferences a null holder element and has no case for a Data Model Annex enumerator; getTypeHolder(Value, ComponentClassifier) sets no classifier for a ValueConstant; toDataModelEnumLiteral and DataModelEnumLiteral are unused.
  • ba/org.osate.ba/src/org/osate/ba/analyzers/AadlBaTypeChecker.java — checkResolvedModel inspects only ElementHolder, so a PropertyElementHolder with a null element does not stop checkResolvedTypes; getType does not catch NullPointerException.
  • ba/org.osate.ba/src/org/osate/ba/analyzers/AdaLikeDataTypeChecker.java — conformsTo relates neither ENUM to ENUM_LITERAL nor STRING to ENUM.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions