Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
import de.monticore.cd4analysis.trafo.CDAssociationCreateFieldsFromAllRoles;
import de.monticore.cd4analysis.trafo.CDAssociationCreateFieldsFromNavigableRoles;
import de.monticore.cd4code.CD4CodeMill;
import de.monticore.cd4code._cocos.CD4CodeCoCoChecker;
import de.monticore.cd4code._symboltable.ICD4CodeArtifactScope;
import de.monticore.cd4code._visitor.CD4CodeTraverser;
import de.monticore.cdbasis.CDBasisMill;
import de.monticore.cdbasis._ast.ASTCDClass;
import de.monticore.cdbasis._ast.ASTCDCompilationUnit;
import de.monticore.cdbasis.trafo.CDBasisDefaultPackageTrafo;
import de.monticore.cdgen.cocos.CD2JavaGenCoCos;
import de.monticore.cdinterfaceandenum._ast.ASTCDEnum;
import de.monticore.cdinterfaceandenum._ast.ASTCDInterface;
import de.monticore.generating.GeneratorSetup;
Expand Down Expand Up @@ -395,7 +397,8 @@ public void runBeforeSTCoCos(ASTCDCompilationUnit ast) {
* @param ast the original ast
*/
public void runCoCos(ASTCDCompilationUnit ast) {
super.runCoCos(ast);
CD4CodeCoCoChecker checker = new CD2JavaGenCoCos().getCheckerForAllCoCos();
checker.checkAll(ast);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ protected void addCheckerForAllCoCos(CD4CodeCoCoChecker checker) {
checker.addCoCo(new CDAssociationUniqueInHierarchy());
checker.addCoCo(new CDNoAttributesInInterfaces());
checker.addCoCo(new CDNoOutgoingAssocs4Interfaces());
checker.addCoCo(new CDNoOutgoingAssocs4LibraryTypes());
checker.addCoCo(new CDSingleClassInheritance());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import de.monticore.cdassociation._ast.ASTCDAssocSide;
import de.monticore.cdassociation._ast.ASTCDAssociation;
import de.monticore.cdbasis._ast.ASTCDDefinition;
import de.monticore.cdbasis._ast.ASTCDType;
import de.monticore.cdbasis._cocos.CDBasisASTCDDefinitionCoCo;
import de.monticore.cdbasis._symboltable.CDTypeSymbol;
import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol;
import de.monticore.types.check.SymTypeExpression;
import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedName;
import de.monticore.types3.TypeCheck3;
import de.se_rwth.commons.logging.Log;
import org.apache.commons.lang3.StringUtils;

Expand Down Expand Up @@ -40,32 +42,32 @@ public void check(ASTCDDefinition node) {
if (assoc1.getCDAssocDir().isDefinitiveNavigableRight() && assoc2.getCDAssocDir()
.isDefinitiveNavigableRight() && deriveRoleName(assoc1, AssocSide.RIGHT).equals(
deriveRoleName(assoc2, AssocSide.RIGHT))) {
checkRef(node, findTypeByFullName(assoc1, assoc1.getLeftQualifiedName().getQName()),
findTypeByFullName(assoc2, assoc2.getLeftQualifiedName().getQName()), assoc1);
checkRef(node, findTypeByFullName(assoc1.getLeftQualifiedName()),
findTypeByFullName(assoc2.getLeftQualifiedName()), assoc1);
}

// if they allow navigation from right to left and share a left role-name,
// the referenced types on the right should not be the same
if (assoc1.getCDAssocDir().isDefinitiveNavigableLeft() && assoc2.getCDAssocDir()
.isDefinitiveNavigableLeft() && deriveRoleName(assoc1, AssocSide.LEFT).equals(
deriveRoleName(assoc2, AssocSide.LEFT))) {
checkRef(node, findTypeByFullName(assoc1, assoc1.getRightQualifiedName().getQName()),
findTypeByFullName(assoc2, assoc2.getRightQualifiedName().getQName()), assoc1);
checkRef(node, findTypeByFullName(assoc1.getRightQualifiedName()),
findTypeByFullName(assoc2.getRightQualifiedName()), assoc1);
}

// We also consider a left-to-right role name and navigation match ...
if (assoc1.getCDAssocDir().isDefinitiveNavigableLeft() && assoc2.getCDAssocDir()
.isDefinitiveNavigableRight() && deriveRoleName(assoc1, AssocSide.LEFT).equals(
deriveRoleName(assoc2, AssocSide.RIGHT))) {
checkRef(node, findTypeByFullName(assoc1, assoc1.getRightQualifiedName().getQName()),
findTypeByFullName(assoc2, assoc2.getLeftQualifiedName().getQName()), assoc1);
checkRef(node, findTypeByFullName(assoc1.getRightQualifiedName()),
findTypeByFullName(assoc2.getLeftQualifiedName()), assoc1);
}
// ... as well as a right-to-left match
if (assoc1.getCDAssocDir().isDefinitiveNavigableRight() && assoc2.getCDAssocDir()
.isDefinitiveNavigableLeft() && deriveRoleName(assoc1, AssocSide.RIGHT).equals(
deriveRoleName(assoc2, AssocSide.LEFT))) {
checkRef(node, findTypeByFullName(assoc1, assoc1.getLeftQualifiedName().getQName()),
findTypeByFullName(assoc2, assoc2.getRightQualifiedName().getQName()), assoc1);
checkRef(node, findTypeByFullName(assoc1.getLeftQualifiedName()),
findTypeByFullName(assoc2.getRightQualifiedName()), assoc1);
}
}
}
Expand All @@ -75,24 +77,25 @@ public void check(ASTCDDefinition node) {
/**
* helper-method to find types by full-name
*/
protected ASTCDType findTypeByFullName(ASTCDAssociation node, String fullName) {
protected TypeSymbol findTypeByFullName(ASTMCQualifiedName qualifiedName) {

Optional<CDTypeSymbol> optSymbol = node.getEnclosingScope().resolveCDType(fullName);
if (optSymbol.isPresent()) {
return optSymbol.get().getAstNode();
final SymTypeExpression typeExpression = TypeCheck3.symTypeFromAST(qualifiedName);
if (typeExpression.hasTypeInfo()) {
return typeExpression.getTypeInfo();
}

Log.error("0xCDCE2: Could not find: " + fullName + ".");
// This should never be reached, the symbol table completer should have logged an error before and exited
Log.debug("Cannot find symbol " + qualifiedName.getQName() + ".", CDAssociationUnique.class.getName());
return null;
}

/** Check if type2 is the same as type1. */
protected void checkRef(ASTCDDefinition node, ASTCDType type1, ASTCDType type2,
ASTCDAssociation assoc1) {
protected void checkRef(ASTCDDefinition node, TypeSymbol type1, TypeSymbol type2,
ASTCDAssociation assoc) {
if (type1.equals(type2)) {
Log.error(String.format("0xCDCE1: %s has a duplicate association to %s", type1.getName(),
type2.getName()), assoc1.isPresent_SourcePositionStart() ? assoc1
.get_SourcePositionStart() : null, assoc1.isPresent_SourcePositionEnd() ? assoc1
type2.getName()), assoc.isPresent_SourcePositionStart() ? assoc
.get_SourcePositionStart() : null, assoc.isPresent_SourcePositionEnd() ? assoc
.get_SourcePositionEnd() : null);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import de.monticore.cdassociation._ast.ASTCDAssociation;
import de.monticore.cdbasis._ast.ASTCDDefinition;
import de.monticore.cdbasis._ast.ASTCDType;
import de.monticore.symbols.basicsymbols._ast.ASTType;
import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol;
import de.se_rwth.commons.logging.Log;

Expand All @@ -20,26 +21,26 @@ protected void checkRef(ASTCDDefinition node, ASTCDType type1, ASTCDType type2,
ASTCDAssociation assoc1) {
super.checkRef(node, type1, type2, assoc1);
// We now also check if the types are in a sub/super-type relation
checkSuper(type1, type2);
checkSuper(type2, type1);
checkSuper(type1, type2, assoc);
checkSuper(type2, type1, assoc);
}

/** Check if type2 is a super-type of type1. */
protected void checkSuper(ASTCDType type1, ASTCDType type2) {
protected void checkSuper(TypeSymbol type1, TypeSymbol type2, ASTCDAssociation assoc) {

Stack<TypeSymbol> typesToVisit = new Stack<>();

// getSymbol().getSuperClassesOnly() did not work for some reason
type1.getSymbol().getSuperClassesOnly().forEach(s -> typesToVisit.push(s.getTypeInfo()));
type1.getSuperClassesOnly().forEach(s -> typesToVisit.push(s.getTypeInfo()));

// getSymbol().getInterfaces() did not work for some reason
type1.getSymbol().getInterfaceList().forEach(s -> typesToVisit.push(s.getTypeInfo()));
type1.getInterfaceList().forEach(s -> typesToVisit.push(s.getTypeInfo()));

while (!typesToVisit.isEmpty()) {
final TypeSymbol nextType = typesToVisit.pop();
if (nextType.getFullName().equals(type2.getSymbol().getFullName())) {
if (nextType.getFullName().equals(type2.getFullName())) {
Log.error(String.format("0xCDCE6: %s redefines an association of %s.", type1.getName(),
type2.getName()));
type2.getName()), assoc.get_SourcePositionStart(), assoc.get_SourcePositionEnd());
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public class CDNoAttributesInInterfaces implements CD4CodeBasisASTCDInterfaceCoC
@Override
public void check(ASTCDInterface node) {
if (node.getCDAttributeList() != null && !node.getCDAttributeList().isEmpty()) {
Log.error(String.format(ERROR_MESSAGE, node.getName()), node.get_SourcePositionStart());
Log.error(String.format(ERROR_MESSAGE, node.getName()),
node.get_SourcePositionStart(), node.get_SourcePositionEnd());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.cdgen.cocos;

import de.monticore.cd4code.CD4CodeMill;
import de.monticore.cdassociation._cocos.CDAssociationASTCDAssociationCoCo;
import de.monticore.cdassociation._ast.ASTCDAssociation;
import de.monticore.cdinterfaceandenum._ast.ASTCDInterface;
import de.monticore.types.check.SymTypeExpression;
import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType;
import de.monticore.types3.TypeCheck3;
import de.se_rwth.commons.logging.Log;

public class CDNoOutgoingAssocs4Interfaces implements CDAssociationASTCDAssociationCoCo {
Expand All @@ -28,12 +31,16 @@ public void check(ASTCDAssociation node) {

protected void checkSide(ASTMCQualifiedType type, ASTCDAssociation context) {
// Resolve the symbol for the type and check if it's an interface
context.getEnclosingScope().resolveCDType(type.printType()).ifPresent(symbol -> {
if (symbol.getAstNode() instanceof ASTCDInterface) {
Log.error(String.format(ERROR_MESSAGE, symbol.getName()), context
.get_SourcePositionStart());
final SymTypeExpression typeExpression = TypeCheck3.symTypeFromAST(type);
if (typeExpression.hasTypeInfo() && !typeExpression.getTypeInfo().isPresentAstNode()) {
if (typeExpression.isObjectType()
&& typeExpression.hasTypeInfo()
&& CD4CodeMill.typeDispatcher().isOOSymbolsOOType(typeExpression.getTypeInfo())
&& CD4CodeMill.typeDispatcher().asOOSymbolsOOType(typeExpression.getTypeInfo()).isIsInterface()) {
Log.error(String.format(ERROR_MESSAGE, type.printType()),
context.get_SourcePositionStart(), context.get_SourcePositionEnd());
}
});
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.cdgen.cocos;

import de.monticore.cdassociation._ast.ASTCDAssociation;
import de.monticore.cdassociation._cocos.CDAssociationASTCDAssociationCoCo;
import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol;
import de.monticore.types.check.SymTypeExpression;
import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType;
import de.monticore.types3.TypeCheck3;
import de.se_rwth.commons.logging.Log;

public class CDNoOutgoingAssocs4LibraryTypes implements CDAssociationASTCDAssociationCoCo {

public static final String ERROR_CODE = "0xCDCE7";
public static final String ERROR_MESSAGE = ERROR_CODE
+ ": Cannot add outgoing associations to imported library type %s.";

@Override
public void check(ASTCDAssociation node) {
// An association is outgoing from the left side if it is navigable from left to right
if (node.getCDAssocDir().isDefinitiveNavigableRight()) {
checkSide(node.getLeft().getMCQualifiedType(), node);
}
// An association is outgoing from the right side if it is navigable from right to left
if (node.getCDAssocDir().isDefinitiveNavigableLeft()) {
checkSide(node.getRight().getMCQualifiedType(), node);
}

}

protected void checkSide(ASTMCQualifiedType type, ASTCDAssociation context) {
// Resolve the symbol for the type and check if it does not have an ASTNode, i.e., is imported
final SymTypeExpression typeExpression = TypeCheck3.symTypeFromAST(type);
if (typeExpression.hasTypeInfo() && !typeExpression.getTypeInfo().isPresentAstNode()) {
Log.error(String.format(ERROR_MESSAGE, type.printType()),
context.get_SourcePositionStart(), context.get_SourcePositionEnd());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public class CDSingleClassInheritance implements CDBasisASTCDClassCoCo {
@Override
public void check(ASTCDClass node) {
if (node.getSuperclassList().size() > 1) {
Log.error(String.format(ERROR_MESSAGE, node.getName()), node.get_SourcePositionStart());
Log.error(String.format(ERROR_MESSAGE, node.getName()),
node.get_SourcePositionStart(), node.get_SourcePositionEnd());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,11 @@ public void testDuplicatesDifferentClassesWithExplicitRoles() throws IOException
runTestForErrorCode(model, ERROR_CODE);
}

@Test
public void testDuplicatesWithC2MC() throws IOException {
String model = "classdiagram DuplicateAssocs {" + " class A;"
+ " association A <-> java.lang.Integer;" + " association A <-> java.lang.Integer;" + "}";
runTestForErrorCode(model, ERROR_CODE);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.cdgen.cocos;

import de.monticore.cd4code._cocos.CD4CodeCoCoChecker;
import de.monticore.cd4code.cocos.AbstractJavaGenCoCoTest;
import org.junit.jupiter.api.Test;

import java.io.IOException;

public class CDNoOutgoingAssocs4LibraryTypesTest extends AbstractJavaGenCoCoTest {

@Override
protected CD4CodeCoCoChecker createChecker() {
CD4CodeCoCoChecker checker = new CD4CodeCoCoChecker();
checker.addCoCo(new CDNoOutgoingAssocs4LibraryTypes());
return checker;
}

@Test
public void testValidAssociation() throws IOException {
String model = "classdiagram Valid {" + " interface I;" + " class C;"
+ " association C -> I;" + "}";
runTest(model, false);
}

@Test
public void testInvalidDirectedAssociation() throws IOException {
String model = "classdiagram Invalid {" + " class C;"
+ " association java.lang.Integer -> C;" + "}";
runTestForErrorCode(model, CDNoOutgoingAssocs4LibraryTypes.ERROR_CODE);
}

@Test
public void testInvalidBidirectionalAssociation() throws IOException {
String model = "classdiagram Invalid {" + " class C;"
+ " association java.lang.Integer <-> C;" + "}";
runTestForErrorCode(model, CDNoOutgoingAssocs4LibraryTypes.ERROR_CODE);
}

@Test
public void testUndirectedAssociation() throws IOException {
// An undirected association is not definitively navigable, so it does not trigger an error.
String model = "classdiagram Valid {" + " class C;"
+ " association java.lang.Integer -- C;" + "}";
runTest(model, false);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,25 @@ classdiagram CDAssociationUniqueInHierarchyValid {
}

package p2 {
class A2;
class B2;
class A2;
class B2;

class superclass2;
class subclass2 extends superclass2;
class superclass2;
class subclass2 extends superclass2;

association superclass2 -> (foo) A2;
association subclass2 -> (bar) B2;
association superclass2 -> (foo) A2;
association subclass2 -> (bar) B2;
}

package p3 {
class A3;
class B3;
package p3 {
class A3;
class B3;

class superclass3;
class subclass3 extends superclass3;
class superclass3;
class subclass3 extends superclass3;

association p3.superclass3 -> (foo) A3;
association p3.subclass3 (foo) <- B3;
}
association p3.superclass3 -> (foo) A3;
association p3.subclass3 (foo) <- B3;
}

}
Loading