Skip to content
Open
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 @@ -388,7 +390,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 @@ -10,8 +10,6 @@ public class CD2JavaGenCoCos extends CD4CodeCoCosDelegator {
protected void addCheckerForAllCoCos(CD4CodeCoCoChecker checker) {
super.addCheckerForAllCoCos(checker);
checker.addCoCo(new CDAssociationUniqueInHierarchy());
checker.addCoCo(new CDNoAttributesInInterfaces());
checker.addCoCo(new CDNoOutgoingAssocs4Interfaces());
checker.addCoCo(new CDSingleClassInheritance());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@
*/
public class CDAssociationUnique implements CDBasisASTCDDefinitionCoCo {

/**
* @param node class to check.
*/
@Override
public void check(ASTCDDefinition node) {

Expand All @@ -37,59 +34,65 @@ public void check(ASTCDDefinition node) {

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

// if they share a right role-name, the referenced types on the left should not be the
// same
if (deriveRoleName(assoc1, AssocSide.RIGHT).equals(deriveRoleName(assoc2,
AssocSide.RIGHT))) {
checkRef(node, findTypeByFullName(assoc1, assoc1.getLeftQualifiedName().getQName()),
findTypeByFullName(assoc2, assoc2.getLeftQualifiedName().getQName()), assoc1);
AssocSide.RIGHT)) && assoc1.getCDAssocDir().isDefinitiveNavigableRight() && assoc2
.getCDAssocDir().isDefinitiveNavigableRight()) {
checkRef(assoc1, assoc2, findTypeByFullName(assoc1, assoc1.getLeftQualifiedName()
.getQName()), findTypeByFullName(assoc2, assoc2.getLeftQualifiedName().getQName()));
}

// We also consider a left-to-right role name match ...
if (deriveRoleName(assoc1, AssocSide.LEFT).equals(deriveRoleName(assoc2,
AssocSide.RIGHT))) {
checkRef(node, findTypeByFullName(assoc1, assoc1.getRightQualifiedName().getQName()),
findTypeByFullName(assoc2, assoc2.getLeftQualifiedName().getQName()), assoc1);
if (deriveRoleName(assoc1, AssocSide.LEFT).equals(deriveRoleName(assoc2, AssocSide.RIGHT))
&& assoc1.getCDAssocDir().isDefinitiveNavigableLeft() && assoc2.getCDAssocDir()
.isDefinitiveNavigableRight()) {
checkRef(assoc1, assoc2, findTypeByFullName(assoc1, assoc1.getRightQualifiedName()
.getQName()), findTypeByFullName(assoc2, assoc2.getLeftQualifiedName().getQName()));
}
// ... as well as a right-to-left match
if (deriveRoleName(assoc1, AssocSide.RIGHT).equals(deriveRoleName(assoc2,
AssocSide.LEFT))) {
checkRef(node, findTypeByFullName(assoc1, assoc1.getLeftQualifiedName().getQName()),
findTypeByFullName(assoc2, assoc2.getRightQualifiedName().getQName()), assoc1);
if (deriveRoleName(assoc1, AssocSide.RIGHT).equals(deriveRoleName(assoc2, AssocSide.LEFT))
&& assoc1.getCDAssocDir().isDefinitiveNavigableRight() && assoc2.getCDAssocDir()
.isDefinitiveNavigableLeft()) {
checkRef(assoc1, assoc2, findTypeByFullName(assoc1, assoc1.getLeftQualifiedName()
.getQName()), findTypeByFullName(assoc2, assoc2.getRightQualifiedName()
.getQName()));
}
}
}
}
}

/**
* helper-method to find types by full-name
*/
/** helper-method to find types by full-name */
protected ASTCDType findTypeByFullName(ASTCDAssociation node, String fullName) {

Optional<CDTypeSymbol> optSymbol = node.getEnclosingScope().resolveCDType(fullName);
if (optSymbol.isPresent()) {
return optSymbol.get().getAstNode();
}

Log.error("0xCDCE2: Could not find: " + fullName + ".");
Log.error("0xCDCE2: Could not find: " + fullName + ".", node.get_SourcePositionStart());
return null;
}

/** Check if type2 is the same as type1. */
protected void checkRef(ASTCDDefinition node, ASTCDType type1, ASTCDType type2,
ASTCDAssociation assoc1) {
protected void checkRef(ASTCDAssociation assoc1, ASTCDAssociation assoc2, ASTCDType type1,
ASTCDType type2) {
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
.get_SourcePositionEnd() : null);
Log.error(String.format("0xCDCE1: %s has duplicate associations %s at %s and %s, "
+ "i.e. 2 different associations with the same target role-name for a given source-type."
+ "This may lead to conflicts in the generated code and is therefore not permitted "
+ "for code generation purposes.", type1.getName(), assoc1.getPrintableName(), assoc1
.get_SourcePositionStart(), assoc2.get_SourcePositionStart()), assoc2
.get_SourcePositionStart());
}
}

Expand All @@ -114,7 +117,7 @@ else if (assoc.isPresentName()) {
}
}

private enum AssocSide {
protected enum AssocSide {
LEFT, RIGHT;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
package de.monticore.cdgen.cocos;

import de.monticore.cdassociation._ast.ASTCDAssociation;
import de.monticore.cdbasis._ast.ASTCDDefinition;
import de.monticore.cdbasis._ast.ASTCDType;
import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol;
import de.se_rwth.commons.logging.Log;
Expand All @@ -16,16 +15,17 @@
public class CDAssociationUniqueInHierarchy extends CDAssociationUnique {

@Override
protected void checkRef(ASTCDDefinition node, ASTCDType type1, ASTCDType type2,
ASTCDAssociation assoc1) {
super.checkRef(node, type1, type2, assoc1);
protected void checkRef(ASTCDAssociation assoc1, ASTCDAssociation assoc2, ASTCDType type1,
ASTCDType type2) {
super.checkRef(assoc1, assoc2, type1, type2);
// We now also check if the types are in a sub/super-type relation
checkSuper(type1, type2);
checkSuper(type2, type1);
checkSuper(assoc1, assoc2, type1, type2);
checkSuper(assoc2, assoc1, type2, type1);
}

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

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

Expand All @@ -38,8 +38,10 @@ protected void checkSuper(ASTCDType type1, ASTCDType type2) {
while (!typesToVisit.isEmpty()) {
final TypeSymbol nextType = typesToVisit.pop();
if (nextType.getFullName().equals(type2.getSymbol().getFullName())) {
Log.error(String.format("0xCDCE6: %s redefines an association of %s.", type1.getName(),
type2.getName()));
Log.error(String.format("0xCDCE6: %s redefines an association of %s from %s at %s."
+ "Redefining associations are not supported by code generators.", type1.getName(),
type2.getName(), assoc2.get_SourcePositionStart(), assoc1.get_SourcePositionStart()),
assoc1.get_SourcePositionStart());
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,60 @@ public void testUniqueAssocName() throws IOException {
runTest(model, false);
}

@Test
public void testOnlyNavigable() throws IOException {
String model = "classdiagram DuplicateAssocs {" + " class A; class B;"
+ " association A -> B;" + " association A -> (r) B;" + "}";
runTest(model, false);
}

@Test
public void testOnlyNavigableReverse() throws IOException {
String model = "classdiagram DuplicateAssocs {" + " class A; class B;"
+ " association A -> B;" + " association B (r) <- A;" + "}";
runTest(model, false);
}

@Test
public void testOpposedAssocs() throws IOException {
String model = "classdiagram DuplicateAssocs {" + " class A; class B;"
+ " association A -> B;" + " association A <- B;" + "}";
runTest(model, false);
}

@Test
public void testOpposedAssocs2() throws IOException {
String model = "classdiagram DuplicateAssocs {" + " class A; class B;"
+ " association A -> B;" + " association B -> A;" + "}";
runTest(model, false);
}

@Test
public void testNonOpposedAssocs() throws IOException {
String model = "classdiagram DuplicateAssocs {" + " class A; class B;"
+ " association A -> B;" + " association A <-> B;" + "}";
runTestForErrorCode(model, ERROR_CODE);
}

@Test
public void testNonOpposedAssocs2() throws IOException {
String model = "classdiagram DuplicateAssocs {" + " class A; class B;"
+ " association A -> B;" + " association A <-> B;" + "}";
runTestForErrorCode(model, ERROR_CODE);
}

@Test
public void testNonOpposedAssocs3() throws IOException {
String model = "classdiagram DuplicateAssocs {" + " class A; class B;"
+ " association A -> B;" + " association B <- A;" + "}";
runTestForErrorCode(model, ERROR_CODE);
Copy link
Contributor

Choose a reason for hiding this comment

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

would it make sense to also check for the content of the error message?

Would help making sure the error messages are useful to users of a tool / makes review easier

}

@Test
public void testNonOpposedAssocsUnspecified() throws IOException {
String model = "classdiagram DuplicateAssocs {" + " class A; class B;"
+ " association A -> B;" + " association A -- B;" + "}";
runTest(model, false);
}

}
Loading