diff --git a/cdlang/src/cdGenIntTest/java/getter/GetterDecoratorResultTest.java b/cdlang/src/cdGenIntTest/java/getter/GetterDecoratorResultTest.java index af4817bfb..fc11d6bee 100644 --- a/cdlang/src/cdGenIntTest/java/getter/GetterDecoratorResultTest.java +++ b/cdlang/src/cdGenIntTest/java/getter/GetterDecoratorResultTest.java @@ -20,11 +20,11 @@ public void test() throws Exception { obj.__setMyInt(42); Assertions.assertEquals(42, obj.getMyInt()); - // Check if the boolean is prefixed with is & has the "public" default visibility (via default) + // Check if the boolean is prefixed with is and has relaxed protected visibility Method isMyBool = TestGetter.TestGetterC.class.getDeclaredMethod("isMyBool"); - Assertions.assertTrue(Modifier.isPublic(isMyBool.getModifiers())); + Assertions.assertFalse(Modifier.isPublic(isMyBool.getModifiers())); Assertions.assertFalse(Modifier.isPrivate(isMyBool.getModifiers())); - Assertions.assertFalse(Modifier.isProtected(isMyBool.getModifiers())); + Assertions.assertTrue(Modifier.isProtected(isMyBool.getModifiers())); // Test NoGetter / public Assertions.assertEquals(0, obj.pubX); diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/GetterDecorator.java b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/GetterDecorator.java index 4f4899055..110b63ab9 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/GetterDecorator.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/GetterDecorator.java @@ -91,8 +91,8 @@ protected Optional decorateMandatory(ASTCDType decoratedType, String name = (MCTypeFacade.getInstance().isBooleanType(attribute.getMCType()) ? "is" : "get") + StringTransformations.capitalize(attribute.getName()); ASTMCType type = attribute.getMCType().deepClone(); - ASTCDMethod method = CDMethodFacade.getInstance().createMethod(attribute.getModifier() - .deepClone(), type, name); + ASTCDMethod method = CDMethodFacade.getInstance().createMethod(getSourceModifier(attribute), + type, name); glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint( "methods.Get", attribute))); method.getModifier().setAbstract(attribute.getModifier().isDerived()); @@ -115,8 +115,8 @@ protected Optional decorateOptional(ASTCDType decoratedType, String generatedErrorCode = getCDGenService().getGeneratedErrorCode(attribute.getName() + attribute.getMCType().printType()); - ASTCDMethod getMethod = CDMethodFacade.getInstance().createMethod(attribute.getModifier() - .deepClone(), type, name); + ASTCDMethod getMethod = CDMethodFacade.getInstance().createMethod(getSourceModifier(attribute), + type, name); String nativeAttributeName = StringUtils.capitalize(getCDGenService().getNativeAttributeName( attribute.getName())); glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, getMethod, new TemplateHookPoint( @@ -134,8 +134,8 @@ protected Optional decorateOptional(ASTCDType decoratedType, protected Optional decorateOptionalIsPresent(ASTCDType decoratedType, ASTCDAttribute attribute) { - ASTCDMethod isPresentMethod = CDMethodFacade.getInstance().createMethod(attribute.getModifier() - .deepClone(), MCTypeFacade.getInstance().createBooleanType(), "isPresent" + ASTCDMethod isPresentMethod = CDMethodFacade.getInstance().createMethod(getSourceModifier( + attribute), MCTypeFacade.getInstance().createBooleanType(), "isPresent" + StringTransformations.capitalize(attribute.getName())); glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, isPresentMethod, new TemplateHookPoint("methods.opt.IsPresent4Opt", attribute))); @@ -154,8 +154,8 @@ protected Optional decorateSet(ASTCDType decoratedType, String name = "get" + StringTransformations.capitalize(attribute.getName()); ASTMCType type = getCDGenService().getFirstTypeArgument(attribute.getMCType()).deepClone(); - ASTCDMethod getListMethod = CDMethodFacade.getInstance().createMethod(attribute.getModifier() - .deepClone(), MCTypeFacadeFix.createSetTypeOf(type), name); + ASTCDMethod getListMethod = CDMethodFacade.getInstance().createMethod(getSourceModifier( + attribute), MCTypeFacadeFix.createSetTypeOf(type), name); glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, getListMethod, new TemplateHookPoint( "methods.Get", attribute))); getListMethod.getModifier().setAbstract(attribute.getModifier().isDerived()); @@ -175,8 +175,8 @@ protected Optional decorateList(ASTCDType decoratedType, String name = "get" + StringTransformations.capitalize(attribute.getName()); ASTMCType type = getCDGenService().getFirstTypeArgument(attribute.getMCType()).deepClone(); - ASTCDMethod getListMethod = CDMethodFacade.getInstance().createMethod(attribute.getModifier() - .deepClone(), MCTypeFacadeFix.createListTypeOf(type), name); + ASTCDMethod getListMethod = CDMethodFacade.getInstance().createMethod(getSourceModifier( + attribute), MCTypeFacadeFix.createListTypeOf(type), name); glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, getListMethod, new TemplateHookPoint( "methods.Get", attribute))); getListMethod.getModifier().setAbstract(attribute.getModifier().isDerived()); @@ -224,6 +224,7 @@ protected void decorateWithAssocFunctions(ASTCDType decoratedType, ASTCDAttribut capitalizedAttributeNameWithS), String.format(HASHCODE, capitalizedAttributeNameWithS))) { ASTCDMethod method = CDMethodFacade.getInstance().createMethodByDefinition(signature); + method.setModifier(getSourceModifier(attribute)); addToClass(decoratedType, method); this.glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, method, createListImplementation(method, capitalizedAttributeNameWithOutS))); @@ -237,7 +238,7 @@ protected void decorateWithAssocFunctions(ASTCDType decoratedType, ASTCDAttribut capitalizedAttributeNameWithS), String.format(SUBLIST, attributeType, capitalizedAttributeNameWithS))) { ASTCDMethod method = CDMethodFacade.getInstance().createMethodByDefinition(signature); - method.setModifier(attribute.getModifier().deepClone()); + method.setModifier(getSourceModifier(attribute)); addToClass(decoratedType, method); this.glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, method, createListImplementation(method, capitalizedAttributeNameWithOutS))); diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/NavigableSetterDecorator.java b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/NavigableSetterDecorator.java index ecc3a5f16..c813ad4c3 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/NavigableSetterDecorator.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/NavigableSetterDecorator.java @@ -208,8 +208,12 @@ protected SetterDecorator.MethodInformation decorate(ASTCDClass decParent, CDRol SetterDecorator.SetterMethodKind kind, String templateName, String methodName, List params, String paramName, Object... templateParams) { - ASTCDMethod method = CDMethodFacade.getInstance().createMethod(role.getAssocSide().getModifier() - .deepClone(), methodName, params); + var modifier = role.getAssocSide().getModifier().deepClone(); + // Local synchronization methods can be called by an association end in another package. + modifier.setPrivate(false); + modifier.setProtected(false); + modifier.setPublic(true); + ASTCDMethod method = CDMethodFacade.getInstance().createMethod(modifier, methodName, params); glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint( templateName, templateParams))); diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/SetterDecorator.java b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/SetterDecorator.java index 4ebdeba88..bf3f4470f 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/SetterDecorator.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/SetterDecorator.java @@ -166,8 +166,8 @@ protected Optional decorate(ASTCDType decParent, ASTCDAttribu SetterMethodKind kind, String templateName, String methodName, List params, Object... templateParams) { - ASTCDMethod method = CDMethodFacade.getInstance().createMethod(attribute.getModifier() - .deepClone(), methodName, params); + ASTCDMethod method = CDMethodFacade.getInstance().createMethod(getSourceModifier(attribute), + methodName, params); glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint( templateName, templateParams))); diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/data/AbstractDecorator.java b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/data/AbstractDecorator.java index ec7a5e0d5..c6f9f13e1 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/data/AbstractDecorator.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/data/AbstractDecorator.java @@ -7,6 +7,7 @@ import de.monticore.cd4codebasis._ast.ASTCDMethod; import de.monticore.cdbasis._ast.*; import de.monticore.generating.templateengine.GlobalExtensionManagement; +import de.monticore.umlmodifier._ast.ASTModifier; import java.util.Optional; /** @@ -71,6 +72,20 @@ else if (member instanceof ASTCDAttribute attribute) { return true; } + /** + * Returns the original model modifier for an attribute. For attributes generated from association + * roles, the association side modifier is the source of truth because accessor decorators must + * derive their visibility from the modeled role, not from the already generated field. + * + * @param attribute the generated or modeled attribute + * @return the source modifier to use for visibility-sensitive derived members + */ + protected ASTModifier getSourceModifier(ASTCDAttribute attribute) { + var role = decoratorData.fieldToRoles.get(attribute.getSymbol()); + return role == null ? attribute.getModifier().deepClone() : role.getAssocSide().getModifier() + .deepClone(); + } + public CDGenService getCDGenService() { return decoratorData.cdGenService; } /** For Decorators not specifying any additional data */ diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/trafo/DefaultVisibilityPublicTrafo.java b/cdlang/src/main/java/de/monticore/cd/codegen/trafo/DefaultVisibilityPublicTrafo.java index c25809391..847e903ca 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/trafo/DefaultVisibilityPublicTrafo.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/trafo/DefaultVisibilityPublicTrafo.java @@ -1,10 +1,64 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.cd.codegen.trafo; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDClass; +import de.monticore.cdbasis._visitor.CDBasisVisitor2; +import de.monticore.cd4codebasis._ast.ASTCDConstructor; +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cd4codebasis._visitor.CD4CodeBasisVisitor2; +import de.monticore.cdassociation._ast.ASTCDAssocSide; +import de.monticore.cdassociation._visitor.CDAssociationVisitor2; import de.monticore.umlmodifier._ast.ASTModifier; import de.monticore.umlmodifier._visitor.UMLModifierVisitor2; -public class DefaultVisibilityPublicTrafo implements UMLModifierVisitor2 { +public class DefaultVisibilityPublicTrafo implements UMLModifierVisitor2, CDBasisVisitor2, + CD4CodeBasisVisitor2, CDAssociationVisitor2 { + + protected int classDepth; + + @Override + public void visit(ASTCDClass node) { + classDepth++; + } + + @Override + public void endVisit(ASTCDClass node) { + classDepth--; + } + + @Override + public void visit(ASTCDAttribute node) { + relaxClassMemberVisibility(node.getModifier()); + } + + @Override + public void visit(ASTCDMethod node) { + relaxClassMemberVisibility(node.getModifier()); + } + + @Override + public void visit(ASTCDConstructor node) { + relaxClassMemberVisibility(node.getModifier()); + } + + @Override + public void visit(ASTCDAssocSide node) { + relaxVisibility(node.getModifier()); + } + + protected void relaxClassMemberVisibility(ASTModifier modifier) { + if (classDepth > 0) { + relaxVisibility(modifier); + } + } + + protected void relaxVisibility(ASTModifier modifier) { + if (!modifier.isPublic() && !modifier.isProtected()) { + modifier.setPrivate(false); + modifier.setProtected(true); + } + } @Override public void visit(ASTModifier node) { diff --git a/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java b/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java index f311afe7c..aab4484e6 100644 --- a/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java +++ b/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java @@ -453,7 +453,11 @@ public Collection trafoBeforeSymtab(Collection ast.accept(trafo.getTraverser())); // TODO: Have this be done via the config-options (#4310) var t = CD4CodeMill.inheritanceTraverser(); - t.add4UMLModifier(new DefaultVisibilityPublicTrafo()); + var visibilityTrafo = new DefaultVisibilityPublicTrafo(); + t.add4CDBasis(visibilityTrafo); + t.add4CD4CodeBasis(visibilityTrafo); + t.add4CDAssociation(visibilityTrafo); + t.add4UMLModifier(visibilityTrafo); asts.forEach(ast -> ast.accept(t)); return asts; } diff --git a/cdlang/src/test/java/de/monticore/cd/cdgen/BuilderDecoratorTest.java b/cdlang/src/test/java/de/monticore/cd/cdgen/BuilderDecoratorTest.java index 9691a9c54..28964f788 100644 --- a/cdlang/src/test/java/de/monticore/cd/cdgen/BuilderDecoratorTest.java +++ b/cdlang/src/test/java/de/monticore/cd/cdgen/BuilderDecoratorTest.java @@ -63,7 +63,7 @@ enum TestEnum { } interface Level1Interface; class Level2class implements Level1Interface{ - int myInt; + public int myInt; } }"""); diff --git a/cdlang/src/test/java/de/monticore/cd/cdgen/DefaultCD2PojoDecoratorTest.java b/cdlang/src/test/java/de/monticore/cd/cdgen/DefaultCD2PojoDecoratorTest.java index 0f81a741c..39de3dc22 100644 --- a/cdlang/src/test/java/de/monticore/cd/cdgen/DefaultCD2PojoDecoratorTest.java +++ b/cdlang/src/test/java/de/monticore/cd/cdgen/DefaultCD2PojoDecoratorTest.java @@ -3,13 +3,23 @@ import de.monticore.cd.codegen.DecoratorConfig; import de.monticore.cd4code.CD4CodeMill; +import de.monticore.cdbasis._ast.ASTCDClass; import de.monticore.generating.GeneratorSetup; import de.monticore.generating.templateengine.GlobalExtensionManagement; import de.monticore.generating.templateengine.TemplateController; import de.monticore.generating.templateengine.TemplateHookPoint; import de.monticore.runtime.junit.MCAssertions; - +import de.monticore.umlmodifier._ast.ASTModifier; +import de.se_rwth.commons.logging.Log; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaFileObject; +import javax.tools.ToolProvider; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -19,6 +29,103 @@ */ public class DefaultCD2PojoDecoratorTest extends AbstractDecoratorTest { + protected void compileGeneratedSources() throws Exception { + var compiler = ToolProvider.getSystemJavaCompiler(); + Assertions.assertNotNull(compiler, "The generation regression test requires a JDK"); + var diagnostics = new DiagnosticCollector(); + Path classes = outputDir.toPath().resolve("compiled"); + Files.createDirectories(classes); + try ( + var files = Files.walk(outputDir.toPath()); + var manager = compiler.getStandardFileManager(diagnostics, null, null) + ) { + List sources = files.filter(path -> path.toString().endsWith(".java")).map(Path::toFile) + .collect(Collectors.toList()); + String loggingPath = new File(Log.class.getProtectionDomain().getCodeSource().getLocation() + .toURI()).getAbsolutePath(); + Assertions.assertTrue(compiler.getTask(null, manager, diagnostics, List.of("-d", classes + .toString(), "-classpath", loggingPath), null, manager.getJavaFileObjectsFromFiles( + sources)).call(), diagnostics.getDiagnostics().toString()); + } + } + + @Test + public void testRelaxedClassMemberVisibility() throws Exception { + var ast = CD4CodeMill.parser().parse_String(""" + classdiagram RelaxedVisibility { + class A { + private A(); + private String privateValue; + String packageValue; + private void privateMethod(); + void packageMethod(); + public void publicMethod(); + protected void protectedMethod(); + } + class B {} + association A -> (privateBs) B [*] private; + association A -> (packageBs) B [*]; + association A -> (privateOrderedBs) B [*] private {ordered}; + association A -> (packageOrderedBs) B [*] {ordered}; + association A -> (privateOptionalB) B [0..1] private; + association A -> (packageOptionalB) B [0..1]; + association A -> (publicBs) B [*] public; + package Inner { + class InnerB {} + } + association A (innerB) <-> (a) Inner.InnerB; + } + """).orElseThrow(); + + var result = doTest(ast); + var clazz = result.getDecoratedCD().getCDDefinition().getCDClassesList().get(0); + assertProtectedOnly(clazz.getCDConstructorList().get(0).getModifier()); + for (String attributeName : List.of("privateValue", "packageValue", "privateBs", "packageBs", + "privateOrderedBs", "packageOrderedBs", "privateOptionalB", "packageOptionalB")) { + var modifier = clazz.getCDAttributeList().stream().filter(attribute -> attribute.getName() + .equals(attributeName)).findFirst().orElseThrow().getModifier(); + assertProtectedOnly(modifier); + } + for (String methodName : List.of("privateMethod", "packageMethod", "getPrivateValue", + "setPrivateValue", "getPackageValue", "setPackageValue")) { + var modifier = clazz.getCDMethodList().stream().filter(method -> method.getName().equals( + methodName)).findFirst().orElseThrow().getModifier(); + assertProtectedOnly(modifier); + } + for (String memberSuffix : List.of("PrivateBs", "PackageBs", "PrivateOrderedBs", + "PackageOrderedBs", "PrivateOptionalB", "PackageOptionalB")) { + var generatedMethods = clazz.getCDMethodList().stream().filter(method -> method.getName() + .endsWith(memberSuffix)).collect(Collectors.toList()); + Assertions.assertFalse(generatedMethods.isEmpty(), memberSuffix); + generatedMethods.forEach(method -> assertProtectedOnly(method.getModifier())); + } + Assertions.assertTrue(clazz.getCDMethodList().stream().filter(method -> method.getName().equals( + "publicMethod")).findFirst().orElseThrow().getModifier().isPublic()); + Assertions.assertTrue(clazz.getCDMethodList().stream().filter(method -> method.getName().equals( + "protectedMethod")).findFirst().orElseThrow().getModifier().isProtected()); + var publicAssociationMethods = clazz.getCDMethodList().stream().filter(method -> method + .getName().endsWith("PublicBs")).collect(Collectors.toList()); + Assertions.assertFalse(publicAssociationMethods.isEmpty()); + publicAssociationMethods.forEach(method -> Assertions.assertTrue(method.getModifier() + .isPublic())); + var innerClass = (ASTCDClass) result.getDecoratedCD().getCDDefinition().getCDPackagesList().get( + 0).getCDElementList().get(0); + for (var associationClass : List.of(clazz, innerClass)) { + var localMethods = associationClass.getCDMethodList().stream().filter(method -> method + .getName().endsWith("Local")).collect(Collectors.toList()); + Assertions.assertFalse(localMethods.isEmpty()); + localMethods.forEach(method -> Assertions.assertTrue(method.getModifier().isPublic())); + } + MCAssertions.assertNoFindings(); + compileGeneratedSources(); + } + + protected void assertProtectedOnly(ASTModifier modifier) { + Assertions.assertTrue(modifier.isProtected()); + Assertions.assertFalse(modifier.isPrivate()); + Assertions.assertFalse(modifier.isPublic()); + } + @Test public void testAll() throws Exception { var opt = CD4CodeMill.parser().parse_String("classdiagram TestDefaultCD2Pojo {\n" diff --git a/cdlang/src/test/java/de/monticore/cd/cdgen/GetterDecoratorTest.java b/cdlang/src/test/java/de/monticore/cd/cdgen/GetterDecoratorTest.java index cbc443c64..3d0825fc0 100644 --- a/cdlang/src/test/java/de/monticore/cd/cdgen/GetterDecoratorTest.java +++ b/cdlang/src/test/java/de/monticore/cd/cdgen/GetterDecoratorTest.java @@ -25,8 +25,8 @@ public void testGetter() throws Exception { boolean myBool; public int myInt; <> public int pubX; } - public association TestGetterC -> (roleB) Other [*]; - public association TestGetterC -> (orderedRole) Other [*] {ordered}; + public association TestGetterC -> (roleB) Other [*] public; + public association TestGetterC -> (orderedRole) Other [*] public {ordered}; <> public class Other { } <> public class AlreadyExisting { diff --git a/cdlang/src/test/java/de/monticore/cd/cdgen/ObserverDecoratorTest.java b/cdlang/src/test/java/de/monticore/cd/cdgen/ObserverDecoratorTest.java index f087acc26..69daeba55 100644 --- a/cdlang/src/test/java/de/monticore/cd/cdgen/ObserverDecoratorTest.java +++ b/cdlang/src/test/java/de/monticore/cd/cdgen/ObserverDecoratorTest.java @@ -42,25 +42,25 @@ void testObserver() throws Exception { <> class CB {} <> class CC {} <> class CD {} - association CA <-> CB; - association CA <-> CC [*]; - association CA <-> CD [0..1]; + association public CA <-> CB public; + association public CA <-> CC [*] public; + association public CA <-> CD [0..1] public; <> class DA {} <> class DB {} <> class DC {} <> class DD {} - association DA <-> DB; - association DA <-> DC [*]; - association DA <-> DD [0..1]; + association public DA <-> DB public; + association public DA <-> DC [*] public; + association public DA <-> DD [0..1] public; <> class EA {} <> class EB {} <> class EC {} <> class ED {} - association EA <-> EB; - association EA <-> EC [*]; - association EA <-> ED [0..1]; + association public EA <-> EB public; + association public EA <-> EC [*] public; + association public EA <-> ED [0..1] public; }"""); diff --git a/cdlang/src/test/java/de/monticore/cd/cdgen/VisitorDecoratorTest.java b/cdlang/src/test/java/de/monticore/cd/cdgen/VisitorDecoratorTest.java index 4378be76a..165b168c7 100644 --- a/cdlang/src/test/java/de/monticore/cd/cdgen/VisitorDecoratorTest.java +++ b/cdlang/src/test/java/de/monticore/cd/cdgen/VisitorDecoratorTest.java @@ -24,7 +24,7 @@ void testVisitor() throws Exception { classdiagram TestVisitor { public class A { int prim; - B b; + public B b; -> (manyB) B [*] public; -> (optB1) B [0..1] public; -> (optB2) B [0..1] public; @@ -32,7 +32,7 @@ public class A { // -> (privateB) B [1] private; // TODO: Compilation error! } public class B { - String bName; + public String bName; } public class C { //<-> (manyC) C1 [*] public; - bidirectional not part of CDDirectComposition @@ -44,10 +44,10 @@ public class C2 {} public class C3 {} public class C4 {} public class C5 {} - association [0..1] C <-> (manyC) C1 [*]; - association [0..1] C <-> (optC) C2 [0..1]; - association [*] C <-> (manyManyC) C3 [*]; - association C <-> (manyC4) C4 [*]; + association public [0..1] C <-> (manyC) C1 [*] public; + association public [0..1] C <-> (optC) C2 [0..1] public; + association public [*] C <-> (manyManyC) C3 [*] public; + association public C <-> (manyC4) C4 [*] public; class WithTO {} }"""); diff --git a/language-server/src/main/java/de/monticore/cd4analysis/_lsp/features/code_lens/AssociationCodeLensStrategy.java b/language-server/src/main/java/de/monticore/cd4analysis/_lsp/features/code_lens/AssociationCodeLensStrategy.java index 068c388b2..e681dc176 100644 --- a/language-server/src/main/java/de/monticore/cd4analysis/_lsp/features/code_lens/AssociationCodeLensStrategy.java +++ b/language-server/src/main/java/de/monticore/cd4analysis/_lsp/features/code_lens/AssociationCodeLensStrategy.java @@ -8,7 +8,6 @@ import de.mclsg.lsp.features.code_lens.CodeLensStrategy; import de.mclsg.lsp.features.reference.CommonReferencesProvider; import de.mclsg.parser.MatchedToken; -import de.monticore.cd4analysis._lsp.code_lens.CD4AnalysisServerCommandCodeLens; import de.monticore.cd4analysis._parser.CD4AnalysisParserInfo; import de.monticore.cdbasis._symboltable.CDTypeSymbol; import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; @@ -20,6 +19,7 @@ import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; import org.eclipse.lsp4j.CodeLens; +import org.eclipse.lsp4j.Command; public class AssociationCodeLensStrategy implements CodeLensStrategy { @@ -64,7 +64,7 @@ public Optional apply(MatchedToken matchedToken) { String title = "Part of " + associationTokens.size() + " Association" + (associationTokens.size() > 1 ? "s" : ""); - return new CD4AnalysisServerCommandCodeLens(matchedToken.range, title, "", List.of()); + return new CodeLens(matchedToken.range, new Command(title, "", List.of()), null); }).filter(Objects::nonNull).map(cl -> (CodeLens) cl).findFirst(); }