Skip to content
Draft
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,13 @@ public void endVisit(ASTCDAssociation node) {

public void setupModifiers(ASTModifier assocSideModifier, ASTModifier assocModifier,
CDRoleSymbol roleSymbol) {
roleSymbol.setIsPublic(assocSideModifier.isPublic() || assocModifier.isPublic());
roleSymbol.setIsPrivate(assocSideModifier.isPrivate() || assocModifier.isPrivate());
roleSymbol.setIsProtected(assocSideModifier.isProtected() || assocModifier.isProtected());
roleSymbol.setIsPublic(assocSideModifier.isPublic());
roleSymbol.setIsPrivate(assocSideModifier.isPrivate());
roleSymbol.setIsProtected(assocSideModifier.isProtected());
roleSymbol.setIsStatic(assocSideModifier.isStatic() || assocModifier.isStatic());
roleSymbol.setIsFinal(assocSideModifier.isFinal() || assocModifier.isFinal());
roleSymbol.setIsDerived(assocSideModifier.isDerived() || assocModifier.isDerived());
roleSymbol.setIsReadOnly(assocSideModifier.isReadonly() || assocModifier.isReadonly());
}

public static void addRoleToTheirType(CDRoleSymbol symbol, TypeSymbol otherType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ protected void addEbnfCoCos(CDAssociationCoCoChecker checker) {
checker.addCoCo(new CDAssociationOrderedCardinalityGreaterOne());
checker.addCoCo(new CDAssociationRoleNameLowerCase());
checker.addCoCo(new CDAssociationRoleNameNoConflictWithLocalAttribute());
checker.addCoCo(new CDAssociationModifierCoCo());
checker.addCoCo(new CDAssociationJavaClassTypeCoCo());
}

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

import de.monticore.cdassociation._ast.ASTCDAssociation;
import de.monticore.cdassociation._cocos.CDAssociationASTCDAssociationCoCo;
import de.monticore.cdassociation._symboltable.ICDAssociationScope;
import de.monticore.cdbasis._symboltable.CDTypeSymbol;
import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol;
import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType;
import de.se_rwth.commons.logging.Log;

public class CDAssociationJavaClassTypeCoCo implements CDAssociationASTCDAssociationCoCo {

@Override
public void check(ASTCDAssociation node) {
check(node, node.getLeft().getMCQualifiedType(), "left");
check(node, node.getRight().getMCQualifiedType(), "right");
}

protected void check(ASTCDAssociation a, ASTMCQualifiedType qualifiedType, String sideName) {

if (qualifiedType == null || a == null) {
return;
}

ICDAssociationScope scope = a.getEnclosingScope();
String qName = qualifiedType.getMCQualifiedName().getQName();

var optTypeSymbol = scope.resolveType(qName);

if (optTypeSymbol.isPresent()) {
TypeSymbol typeSymbol = optTypeSymbol.get();

if (!(typeSymbol instanceof CDTypeSymbol)) {
String assocName = a.isPresentName() ? a.getName() : "unnamed";

Log.error(String.format(
"0xCDA64: Java class '%s' cannot be used on the %s side of association '%s'.", qName,
sideName, assocName), a.get_SourcePositionStart());

}
}
}

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

import de.monticore.cdassociation._ast.ASTCDAssociation;
import de.monticore.cdassociation._cocos.CDAssociationASTCDAssociationCoCo;
import de.monticore.umlmodifier._ast.ASTModifier;
import de.se_rwth.commons.logging.Log;

public class CDAssociationModifierCoCo implements CDAssociationASTCDAssociationCoCo {

@Override
public void check(ASTCDAssociation a) {

//----------------------------------check the visibility modifiers-----------------------------------------------------------
//main modifier
boolean hasMainVisibility = false;
if (a.getModifier() != null) {
ASTModifier mainModifier = a.getModifier();
hasMainVisibility = mainModifier.isPublic() || mainModifier.isProtected() || mainModifier
.isPrivate();
}

//left modifier
boolean hasLeftVisibility = false;
if (a.getLeft().getModifier() != null) {
ASTModifier leftModifier = a.getLeft().getModifier();
hasLeftVisibility = leftModifier.isPublic() || leftModifier.isProtected() || leftModifier
.isPrivate();
}

//right modifier
boolean hasRightVisibility = false;
if (a.getRight().getModifier() != null) {
ASTModifier rightModifier = a.getRight().getModifier();
hasRightVisibility = rightModifier.isPublic() || rightModifier.isProtected() || rightModifier
.isPrivate();
}

if (hasMainVisibility && (hasLeftVisibility || hasRightVisibility)) {
Log.warn(
"Association cannot combine a main visibility modifier with individual role visibility modifiers.",
a.get_SourcePositionStart());
}

//check whether the association or symbolRole use the static modifier
boolean mainStatic = a.getModifier() != null && a.getModifier().isStatic();
boolean leftStatic = a.getLeft().getModifier() != null && a.getLeft().getModifier().isStatic();
boolean rightStatic = a.getRight().getModifier() != null && a.getRight().getModifier()
.isStatic();

if (mainStatic || leftStatic || rightStatic) {
String assocName = a.isPresentName() ? a.getName() : "unnamed";
Log.error(String.format("0xCDA61: The association '%s' must not use static modifiers.",
assocName), a.get_SourcePositionStart());
}
}

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

import de.monticore.cdassociation.cocos.ebnf.CDAssociationJavaClassTypeCoCo;
import de.monticore.cdbasis._ast.ASTCDCompilationUnit;
import de.monticore.testcdassociation.CDAssociationTestBasis;
import de.se_rwth.commons.logging.Log;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;

public class CDAssociationLeftAndRightJavaClassInvalidTest extends CDAssociationTestBasis {

@Test
public void testValid() throws IOException {
coCoChecker.addCoCo(new CDAssociationJavaClassTypeCoCo());
final Optional<ASTCDCompilationUnit> optAST = p.parse(getFilePath(
"cdassociation/cocos/CDAssociationLeftAndRightJavaClassValid.cd"));
assertTrue(optAST.isPresent());

final ASTCDCompilationUnit ast = optAST.get();
Log.getFindings().clear();
createSymTab(ast);
completeSymTab(ast);
coCoChecker.checkAll(ast);
assertTrue(Log.getFindings().isEmpty());
}

@Test
public void testInvalid() throws IOException {

coCoChecker.addCoCo(new CDAssociationJavaClassTypeCoCo());
final Optional<ASTCDCompilationUnit> optAST = p.parse(getFilePath(
"cdassociation/cocos/CDAssociationLeftAndRightJavaClassInvalid.cd"));
assertTrue(optAST.isPresent());

final ASTCDCompilationUnit ast = optAST.get();
Log.getFindings().clear();
createSymTab(ast);
completeSymTab(ast);
coCoChecker.checkAll(ast);
assertTrue(Log.getFindings().get(0).getMsg().startsWith("0xCDA64"));
assertEquals(4, Log.getFindings().size());
Log.clearFindings();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* (c) https://github.com/MontiCore/monticore */

classdiagram CDAssociationLeftAndRightJavaClassInvalid{

class A{
}

//left side is an external java class
association leftJava java.lang.String -> A;

// right side is an external java class
association rightJava A -> java.lang.Integer;

// both sides are external java classes
association bothJava java.lang.Boolean -> java.lang.Long;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* (c) https://github.com/MontiCore/monticore */

classdiagram CDAssociationLeftAndRightJavaClassInvalid{

public class A{
java.lang.String attributeA1;
java.lang.Integer attributeA2;
}

private abstract class B{
readonly int attributeB1;
final java.lang.String attributeB2;
}

protected static class C {
}

association abstract B -> A;
association [0..2] A -> B;

association A -> C;

}
Loading