Add typecheck test for SysML calc defs as function symbols#99
Add typecheck test for SysML calc defs as function symbols#99mathias-pfeiffer merged 7 commits intorelease/7.8.xfrom
Conversation
| throw new IllegalStateException("CalcUsage has no body elements: " + adaptee.getFullName()); | ||
| } | ||
|
|
||
| var elem = ast.getSysMLElement(0); |
There was a problem hiding this comment.
Stattdessen das Element mit "return" finden
| ); | ||
| } | ||
|
|
||
| ASTAnonymousUsage anon = (ASTAnonymousUsage) elem; |
There was a problem hiding this comment.
Kein Grund für einen Cast
| throw new IllegalStateException("Calc return has no specialization: " + adaptee.getFullName()); | ||
| } | ||
|
|
||
| ASTSpecialization spec = anon.getSpecialization(0); |
There was a problem hiding this comment.
Um die Specialization, also den Typen zu finden, kannst du einen Visitor auf das ungecastete elem loslassen
| } | ||
|
|
||
| protected SymTypeExpression deriveReturnType() { | ||
| if (!adaptee.isPresentAstNode()) { |
There was a problem hiding this comment.
Stattdessen den Type bereits am CalcDefSymbol speichern
|
|
||
| ASTCalcUsage ast = adaptee.getAstNode(); | ||
|
|
||
| if (ast.getSysMLElementList().isEmpty()) { |
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
s.o., SymTypeExpressionFactory.createTopType()
| return SymTypeExpressionFactory.createFromSymbol(typeSymbol); | ||
| } | ||
|
|
||
| // fallback for primitive names if needed |
There was a problem hiding this comment.
Dieser Fall sollte nie eintreten, entfernen
| public void endVisit(ASTCalcUsage node) { | ||
| if (node.isPresentSymbol()) { | ||
| CalcUsageSymbol symbol = node.getSymbol(); | ||
| CalcReturnSpecVisitor visitor = new CalcReturnSpecVisitor(); |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
Keine eigene Klasse (s.u.), sondern direkt (ad-hoc) in Adapter definieren
| } | ||
| } | ||
|
|
||
| public Optional<ASTSpecialization> getSpecializationReturn() { |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
Direkt SymType berechnen, keine Zwischenschritte
| protected ASTSpecialization specializationReturn; | ||
|
|
||
| @Override | ||
| public void visit(ASTAnonymousUsage node) { |
There was a problem hiding this comment.
Auch ein Visit für Attribute Usages implementieren
| @Override | ||
| public void visit(ASTAnonymousUsage node) { | ||
| if (specializationReturn == null && node.getModifier().isReturn() | ||
| && !node.getSpecializationList().isEmpty()) { |
There was a problem hiding this comment.
Wenn empty, dann ist der Type Obscure! (SymTypeObscure bzw. Factory.createObscureType)
| var traverser = SysMLActionsMill.inheritanceTraverser(); | ||
| traverser.add4SysMLBasis(visitor); | ||
|
|
||
| for (ASTSysMLElement elem : node.getSysMLElementList()) { |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
Sehr gut
| public void testSimpleModel() throws Exception { | |
| public void testValid() throws Exception { |
| checker.checkAll(ast); | ||
|
|
||
| assertTrue(Log.getFindings().isEmpty(), ()-> Log.getFindings().toString()); | ||
| } |
There was a problem hiding this comment.
Bitte noch einen testInvalid hinzufügen:
| } | |
| } | |
| @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") |
|
Die Versionsnummer in gradle.properties muss noch angepasst (inkrementiert) werden |
5bdda1f to
6e41942
Compare
| public void endVisit(ASTCalcUsage node) { | ||
| if (node.isPresentSymbol()) { | ||
| CalcUsageSymbol symbol = node.getSymbol(); | ||
| final SymTypeExpression[] returnType = new SymTypeExpression[1]; |
There was a problem hiding this comment.
Kein Array verwenden
| final SymTypeExpression[] returnType = new SymTypeExpression[1]; | |
| SymTypeExpression returnType = SymTypeExpressionFactory.createTopType(); |
| @Override | ||
| public void endVisit(ASTCalcUsage node) { | ||
| if (node.isPresentSymbol()) { | ||
| CalcUsageSymbol symbol = node.getSymbol(); |
There was a problem hiding this comment.
Wird nur 1x benutzt, entfernen
| 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 |
There was a problem hiding this comment.
Quatsch, einfach "der letzte gewinnt" und eine CoCo schreiben, die prüft, dass es maximal 1 mit Modifier "return" gibt
| // 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 |
There was a problem hiding this comment.
| 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 |
There was a problem hiding this comment.
s.o., keine Checks auf null
| }); | ||
| node.accept(traverser); | ||
|
|
||
| if (returnType[0] != null) { |
There was a problem hiding this comment.
Keine Checks, einfach setzen
| if (returnType[0] != null) { | |
| symbol.setReturnType(returnType[0]); |
Added