From 1cfdd61cca8c5609a7a9d2337939531be7fc6d7f Mon Sep 17 00:00:00 2001 From: kkkk1258999 Date: Thu, 20 Aug 2026 17:44:00 +0900 Subject: [PATCH] [2447] Escape the block comment terminator when exporting a comment body getCommentBody concatenated the body between "/* " and " */" without any escaping, so a body containing the terminator closed the comment early and the rest of it was exported as if it were SysML v2 code, giving a file which does not parse. Documenting a piece of code is enough to run into it. The grammar defines a comment as a non greedy match up to the first terminator, with no escape sequence and no nesting, so that sequence cannot be represented inside a comment body. It is separated by a space instead, and reported as a warning through the existing report consumer, since the exported text is then not exactly the one which was written and that should not happen silently. The reverse replacement is deliberately not done on import: a body may legitimately contain the separated form, and turning it back would corrupt it. getCommentBody is used for the body of a Comment, of a Documentation and of a TextualRepresentation, so all three are covered. Bug: https://github.com/eclipse-syson/syson/issues/2447 Signed-off-by: kkkk1258999 --- CHANGELOG.adoc | 2 ++ .../textual/SysMLElementSerializerTest.java | 15 ++++++++ .../textual/SysMLElementSerializer.java | 36 ++++++++++++++++++- .../pages/release-notes/2026.9.0.adoc | 4 +++ 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index cc66f2aca2..957c4c2fd0 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -52,6 +52,8 @@ This also fixes `relatedFeature`, `sourceFeature` and `targetFeature`, which wer - https://github.com/eclipse-syson/syson/issues/2226[#2226] [import] Fix textual import of annotations on relationships so their `annotatedElement` is set and they are returned by `Element#getOwnedAnnotation()`. - https://github.com/eclipse-syson/syson/issues/2419[#2419] [export] Fix the export of the prefix metadata carried by the ends of a connector, which were dropped when those ends are declared inline. The ends of a connector created from a diagram are owned through an `EndFeatureMembership` and are exported inline, so their metadata, such as the `#original` and `#derive` of a requirement derivation, were lost. +- https://github.com/eclipse-syson/syson/issues/2447[#2447] [export] Fix the export of a comment body containing `*/`, which closed the block comment early and produced a file that could not be parsed. +The grammar defines a comment as a non greedy match up to the first `*/`, with no escape sequence and no nesting, so that sequence is exported as `* /` and a warning is reported, since the exported text is then not exactly the one that was written. - https://github.com/eclipse-syson/syson/issues/2340[#2340] [diagrams] Replace the name of the _New Perform action_ tool to _New Perform Action_ to be consistent with other tools. - https://github.com/eclipse-syson/syson/issues/2437[#2437] [metamodel] Fix elementId when creating a FlowDefinition - https://github.com/eclipse-syson/syson/issues/2384[#2384] [import] Fix the import of `TransitionUsage` using _start_ which now set the source to the `StateUsage` _start_ from the standard library instead of `ActionUsage` _start_ from the standard library. diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/sysml/textual/SysMLElementSerializerTest.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/sysml/textual/SysMLElementSerializerTest.java index d2f15880ae..eb00e27c97 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/sysml/textual/SysMLElementSerializerTest.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/sysml/textual/SysMLElementSerializerTest.java @@ -1979,6 +1979,21 @@ public void portUsageFull() { } + @Test + public void documentationContainingACommentTerminator() { + PartUsage partUsage = this.builder.createWithName(PartUsage.class, "PartUsage1"); + this.builder.createIn(Documentation.class, partUsage).setBody("Closing a block comment looks like */ in the code"); + + // The terminator is separated so it no longer closes the comment, which would leave the rest of the body + // exported as if it were SysML v2 code. + this.assertTextualFormEquals(""" + part PartUsage1 { + doc /* Closing a block comment looks like * / in the code */ + }""", partUsage); + assertTrue(this.status.stream() + .anyMatch(reported -> reported.severity() == Severity.WARNING && reported.message().contains("closes a comment"))); + } + @Test public void documentation() { diff --git a/backend/services/syson-sysml-metamodel-services/src/main/java/org/eclipse/syson/sysml/metamodel/services/textual/SysMLElementSerializer.java b/backend/services/syson-sysml-metamodel-services/src/main/java/org/eclipse/syson/sysml/metamodel/services/textual/SysMLElementSerializer.java index 73e8c5a510..a01513524f 100644 --- a/backend/services/syson-sysml-metamodel-services/src/main/java/org/eclipse/syson/sysml/metamodel/services/textual/SysMLElementSerializer.java +++ b/backend/services/syson-sysml-metamodel-services/src/main/java/org/eclipse/syson/sysml/metamodel/services/textual/SysMLElementSerializer.java @@ -170,6 +170,12 @@ public class SysMLElementSerializer extends SysmlSwitch { private static final String SPACE = " "; + /** The sequence closing a block comment, which cannot appear inside a comment body. */ + private static final String COMMENT_TERMINATOR = "*/"; + + /** The form the block comment terminator is exported as, so it no longer closes the comment. */ + private static final String ESCAPED_COMMENT_TERMINATOR = "* /"; + private final String lineSeparator; private final String indentation; @@ -2530,10 +2536,38 @@ private T getDirectContainer(EObject element, java.lang.Class expected) { private String getCommentBody(String body) { Appender subBuilder = this.newAppender(); - subBuilder.append("/* ").append(body).append(" */"); + subBuilder.append("/* ").append(this.escapeCommentTerminator(body)).append(" */"); return subBuilder.toString(); } + /** + * Replace the occurrences of the block comment terminator in a comment body. + *

+ * The grammar defines a comment as {@code /*[\s\S]*?*}{@code /}, a non greedy match up to the first {@code *} + * {@code /}, with no escape sequence and no nesting, so that sequence cannot be represented inside a comment body. + * Left as it is, it closes the comment early and the rest of the body is exported as if it were SysML v2 code, + * giving a file which does not parse. It is separated by a space instead, which is reported since the exported text + * is then not exactly the one which was written. + *

+ *

+ * The reverse replacement is deliberately not done on import: a body may legitimately contain the separated form, + * and turning it back would corrupt it. + *

+ * + * @param body + * the body of a comment, a documentation or a textual representation + * @return the body, with any block comment terminator separated by a space + */ + private String escapeCommentTerminator(String body) { + if (body == null || !body.contains(COMMENT_TERMINATOR)) { + return body; + } + this.reportConsumer.accept(Status.warning( + "A comment body contains \"{0}\", which closes a comment. It has been exported as \"{1}\" so the text remains valid.", + COMMENT_TERMINATOR, ESCAPED_COMMENT_TERMINATOR)); + return body.replace(COMMENT_TERMINATOR, ESCAPED_COMMENT_TERMINATOR); + } + private void appendLocale(Appender builder, String local) { if (!this.isNullOrEmpty(local)) { builder.appendSpaceIfNeeded().append("locale").append(" \"").append(local).append("\""); diff --git a/doc/content/modules/user-manual/pages/release-notes/2026.9.0.adoc b/doc/content/modules/user-manual/pages/release-notes/2026.9.0.adoc index 24d8abeef1..e0b2ace5c6 100644 --- a/doc/content/modules/user-manual/pages/release-notes/2026.9.0.adoc +++ b/doc/content/modules/user-manual/pages/release-notes/2026.9.0.adoc @@ -124,6 +124,10 @@ The affected connections were missing their source and target and were therefore Exporting such a connection and importing it back no longer loses which end is which. ** Fix the import of `TransitionUsage` using _start_ which now set the source to the `StateUsage` _start_ from the standard library instead of `ActionUsage` _start_ from the standard library. +** Fix the export of a documentation, a comment or a textual representation whose text contains `*/`. +That sequence closes a comment in the SysML v2 textual notation, so the exported file could no longer be read. +It is now exported as `* /`, and a warning reports it, since the exported text is then not exactly the one that was written. + == Improvements * {product} Docker images now support `linux/amd64` and `linux/arm64` and run natively on arm64 machines such as Apple Silicon or AWS Graviton.