Skip to content

Add typecheck test for SysML calc defs as function symbols#99

Merged
mathias-pfeiffer merged 7 commits intorelease/7.8.xfrom
ln/calc-defs-as-functions
Apr 27, 2026
Merged

Add typecheck test for SysML calc defs as function symbols#99
mathias-pfeiffer merged 7 commits intorelease/7.8.xfrom
ln/calc-defs-as-functions

Conversation

@linggd
Copy link
Copy Markdown
Collaborator

@linggd linggd commented Apr 14, 2026

Added

  • Added a test for handling SysML calc defs as function symbols.
  • Added an adapter to treat CalcUsage as function symbols.
  • Added calculation for calc usage in TypesCompleter

throw new IllegalStateException("CalcUsage has no body elements: " + adaptee.getFullName());
}

var elem = ast.getSysMLElement(0);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stattdessen das Element mit "return" finden

);
}

ASTAnonymousUsage anon = (ASTAnonymousUsage) elem;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kein Grund für einen Cast

throw new IllegalStateException("Calc return has no specialization: " + adaptee.getFullName());
}

ASTSpecialization spec = anon.getSpecialization(0);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Um die Specialization, also den Typen zu finden, kannst du einen Visitor auf das ungecastete elem loslassen

}

protected SymTypeExpression deriveReturnType() {
if (!adaptee.isPresentAstNode()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stattdessen den Type bereits am CalcDefSymbol speichern


ASTCalcUsage ast = adaptee.getAstNode();

if (ast.getSysMLElementList().isEmpty()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Der Default Type ist "Any", das Analog der MontiCore-Types-Welt ist SymTypeExpressionFactory.createTopType()

ASTSpecialization spec = anon.getSpecialization(0);

if (spec.getSuperTypesList().isEmpty()) {
throw new IllegalStateException("Calc return specialization has no super type: " + adaptee.getFullName());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s.o., SymTypeExpressionFactory.createTopType()

return SymTypeExpressionFactory.createFromSymbol(typeSymbol);
}

// fallback for primitive names if needed
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dieser Fall sollte nie eintreten, entfernen

@mathias-pfeiffer mathias-pfeiffer marked this pull request as draft April 16, 2026 09:57
@linggd linggd marked this pull request as ready for review April 21, 2026 11:30
public void endVisit(ASTCalcUsage node) {
if (node.isPresentSymbol()) {
CalcUsageSymbol symbol = node.getSymbol();
CalcReturnSpecVisitor visitor = new CalcReturnSpecVisitor();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Direkt hier die Klasse implementieren, keine eigene Klasse anlegen

import de.monticore.lang.sysmlbasis._visitor.SysMLBasisVisitor2;
import java.util.Optional;

public class CalcReturnSpecVisitor implements SysMLBasisVisitor2 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keine eigene Klasse (s.u.), sondern direkt (ad-hoc) in Adapter definieren

}
}

public Optional<ASTSpecialization> getSpecializationReturn() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

braucht dann keinen Getter, sondern setzt direkt die Variable ausserhalb des Visitors (in der visit-Methode von Adapter)

import java.util.Optional;

public class CalcReturnSpecVisitor implements SysMLBasisVisitor2 {
protected ASTSpecialization specializationReturn;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Direkt SymType berechnen, keine Zwischenschritte

protected ASTSpecialization specializationReturn;

@Override
public void visit(ASTAnonymousUsage node) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auch ein Visit für Attribute Usages implementieren

@Override
public void visit(ASTAnonymousUsage node) {
if (specializationReturn == null && node.getModifier().isReturn()
&& !node.getSpecializationList().isEmpty()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wenn empty, dann ist der Type Obscure! (SymTypeObscure bzw. Factory.createObscureType)

var traverser = SysMLActionsMill.inheritanceTraverser();
traverser.add4SysMLBasis(visitor);

for (ASTSysMLElement elem : node.getSysMLElementList()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keine For-Loops, sondern direkt den Visitor ausführen und den ersten Return-Type nehmen, der gefunden wird und im korrekten Scope liegt (returnType.enclosingScope == node.getSpannedScope oder so ähnlich)

public class CalcUsageAsFunctionsTest {

@Test
public void testSimpleModel() throws Exception {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sehr gut

Suggested change
public void testSimpleModel() throws Exception {
public void testValid() throws Exception {

checker.checkAll(ast);

assertTrue(Log.getFindings().isEmpty(), ()-> Log.getFindings().toString());
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bitte noch einen testInvalid hinzufügen:

Suggested change
}
}
@Test
void testInvalid() {
var model = "... calc bar { return : nat } ...";
...
assertThat(Log.getFindings()).hasSize(1);
assertThat(Log.getFindings().get(0).getMessage()).containts("0x12354 Type was nat")

@mathias-pfeiffer
Copy link
Copy Markdown
Contributor

Die Versionsnummer in gradle.properties muss noch angepasst (inkrementiert) werden

@mathias-pfeiffer mathias-pfeiffer marked this pull request as draft April 24, 2026 10:11
@linggd linggd force-pushed the ln/calc-defs-as-functions branch from 5bdda1f to 6e41942 Compare April 26, 2026 12:19
@linggd linggd marked this pull request as ready for review April 26, 2026 12:39
public void endVisit(ASTCalcUsage node) {
if (node.isPresentSymbol()) {
CalcUsageSymbol symbol = node.getSymbol();
final SymTypeExpression[] returnType = new SymTypeExpression[1];
Copy link
Copy Markdown
Contributor

@mathias-pfeiffer mathias-pfeiffer Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kein Array verwenden

Suggested change
final SymTypeExpression[] returnType = new SymTypeExpression[1];
SymTypeExpression returnType = SymTypeExpressionFactory.createTopType();

@Override
public void endVisit(ASTCalcUsage node) {
if (node.isPresentSymbol()) {
CalcUsageSymbol symbol = node.getSymbol();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wird nur 1x benutzt, entfernen

Suggested change
CalcUsageSymbol symbol = node.getSymbol();

traverser.add4SysMLBasis(new SysMLBasisVisitor2() {
@Override
public void visit(ASTAnonymousUsage retNode) {
// Store only the first return type declared directly in calc usage
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quatsch, einfach "der letzte gewinnt" und eine CoCo schreiben, die prüft, dass es maximal 1 mit Modifier "return" gibt

Suggested change
// Store only the first return type declared directly in calc usage

@Override
public void visit(ASTAnonymousUsage retNode) {
// Store only the first return type declared directly in calc usage
if (returnType[0] == null
Copy link
Copy Markdown
Contributor

@mathias-pfeiffer mathias-pfeiffer Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (returnType[0] == null
if (node.getModifier().isReturn()
&& retNode.getEnclosingScope() == node.getSpannedScope()) {
// This code is limited to the first type in the list
List<SymTypeExpression> types = getTypeCompletion(retNode.getSpecializationList(), false);
returnType = types.isEmpty() ? SymTypeExpressionFactory.createObscureType() : types.get(0);
}

traverser.add4SysMLParts(new SysMLPartsVisitor2() {
@Override
public void visit(ASTAttributeUsage retNode) {
if (returnType[0] == null
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s.o., keine Checks auf null

});
node.accept(traverser);

if (returnType[0] != null) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keine Checks, einfach setzen

Suggested change
if (returnType[0] != null) {
symbol.setReturnType(returnType[0]);

@mathias-pfeiffer mathias-pfeiffer merged commit 8c6a83c into release/7.8.x Apr 27, 2026
5 of 6 checks passed
@mathias-pfeiffer mathias-pfeiffer deleted the ln/calc-defs-as-functions branch April 27, 2026 13:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants