Skip to content

Commit 0429aa5

Browse files
@code and @literal tags behave differently in Markdown
The inline code tag and inline literal tag behave differently in Markdown Fix: #4695
1 parent 1ec8da7 commit 0429aa5

3 files changed

Lines changed: 118 additions & 18 deletions

File tree

org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2024 IBM Corporation and others.
2+
* Copyright (c) 2000, 2026 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -181,7 +181,6 @@ protected boolean commentParse() {
181181
boolean isDomParser = (this.kind & DOM_PARSER) != 0;
182182
boolean isFormatterParser = (this.kind & FORMATTER_COMMENT_PARSER) != 0;
183183
int lastStarPosition = -1;
184-
boolean isTagElementClose = false;
185184

186185
// Init scanner position
187186
this.markdown = this.source[this.javadocStart + 1] == '/';
@@ -350,9 +349,6 @@ protected boolean commentParse() {
350349
// Fix bug 51650
351350
this.textStart = -1;
352351
this.markdownHelper.resetAtLineEnd();
353-
if (this.inlineTagStarted && this.markdown) {
354-
isTagElementClose = true;
355-
}
356352
break;
357353
case '}' :
358354
if (verifText && this.tagValue == TAG_RETURN_VALUE && this.returnStatement != null) {
@@ -366,6 +362,11 @@ protected boolean commentParse() {
366362
}
367363
}
368364
boolean isLiteralOrCode = this.tagValue == TAG_LITERAL_VALUE || this.tagValue == TAG_CODE_VALUE;
365+
boolean shouldCloseInlineTag =
366+
this.inlineTagStarted
367+
&& !considerTagAsPlainText
368+
&& !(isLiteralOrCode && openingBraces != 0);
369+
369370
if (this.inlineTagStarted) {
370371
textEndPosition = this.index - 1;
371372
boolean treatAsText= considerTagAsPlainText || (this.inlineReturn && this.inlineReturnOpenBraces > 0);
@@ -380,12 +381,8 @@ protected boolean commentParse() {
380381
}
381382
if (!isFormatterParser && !treatAsText && (!this.inlineReturn || this.inlineReturnOpenBraces <= 0))
382383
this.textStart = this.index;
383-
if (!isTagElementClose && this.markdown) { //The comment parser should create a TagElement only if the previous one is closed - markdown.
384+
if (shouldCloseInlineTag) {
384385
setInlineTagStarted(false);
385-
} else if (!this.markdown) {
386-
if (!(isLiteralOrCode && openingBraces != 0)) {
387-
setInlineTagStarted(false);
388-
}
389386
}
390387
if (this.inlineReturn) {
391388
if (this.inlineReturnOpenBraces > 0) {

org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterMarkdownTest.java

Lines changed: 105 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,15 +1854,13 @@ class IllegelTagElement {}
18541854
Javadoc javadoc = typedeclaration.getJavadoc();
18551855
List<TagElement> te = javadoc.tags();
18561856
assertEquals("TagElement length is grater than one", 1, te.size());
1857-
List<TagElement> tes = (te.get(0)).fragments();
1858-
assertEquals("inner TagElement length is grater than one", 1, tes.size());
1859-
assertEquals("TagName", "@link", tes.get(0).getTagName());
1860-
List<?> fragments = tes.get(0).fragments();
1857+
List<?> tes = (te.get(0)).fragments();
1858+
assertEquals("TagName", "@link", ((TagElement)tes.get(0)).getTagName());
1859+
List<?> fragments = ((TagElement)tes.get(0)).fragments();
18611860
assertEquals("fragments count does not match", 2, fragments.size());
18621861
assertTrue(fragments.get(0) instanceof MethodRef);
18631862
assertTrue(fragments.get(1) instanceof TextElement);
1864-
assertEquals("Incorrect text", "value", fragments.get(1).toString());
1865-
assertEquals("Incorrect name", "#getValue()", fragments.get(0).toString());
1863+
assertEquals("Incorrect TagElement", 1, ((TextElement) (tes.get(1))).getFlags() & ASTNode.MALFORMED); //MALFOUND flag
18661864
}
18671865
}
18681866

@@ -2314,4 +2312,105 @@ public class Markdown{}
23142312
assertEquals("invalid tag name","@literal" ,innerTag.getTagName());
23152313
}
23162314
}
2315+
2316+
public void testInconsistencyInCodeAndLiteralTagsMarkdown4609_01() throws JavaModelException {
2317+
String source = """
2318+
/// Performs:
2319+
///
2320+
/// {@code
2321+
/// for (String s : strings) {
2322+
/// if (s.equals(value)) {
2323+
/// return 0;
2324+
/// }
2325+
/// if (s.startsWith(value)) {
2326+
/// return 1;
2327+
/// }
2328+
/// return -1;
2329+
/// }
2330+
/// }
2331+
/// The general contract of `hashCode` is:
2332+
///
2333+
/// - Whenever it is invoked on the same object more than once during
2334+
/// an execution of a Java application, the `hashCode` method
2335+
/// must consistently return the same integer, provided no information
2336+
/// used in `equals` comparisons on the object is modified.
2337+
/// This integer need not remain consistent from one execution of an
2338+
/// application to another execution of the same application.
2339+
/// - If two objects are equal according to the
2340+
/// [equals][#equals(Object)] method, then calling the
2341+
/// `hashCode` method on each of the two objects must produce the
2342+
/// same integer result.
2343+
/// - It is _not_ required that if two objects are unequal
2344+
/// according to the [equals][#equals(Object)] method, then
2345+
/// calling the `hashCode` method on each of the two objects
2346+
/// must produce distinct integer results. However, the programmer
2347+
/// should be aware that producing distinct integer results for
2348+
/// unequal objects may improve the performance of hash tables.
2349+
public class Markdown{}
2350+
""";
2351+
this.workingCopies = new ICompilationUnit[1];
2352+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/Markdown.java", source, null);
2353+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
2354+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
2355+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
2356+
Javadoc javadoc = typedeclaration.getJavadoc();
2357+
List<TagElement> tags = javadoc.tags();
2358+
List<ASTNode> frags = tags.get(0).fragments();
2359+
2360+
assertEquals("Incorrect Frags", 22, frags.size());
2361+
assertEquals("Invalid element", ASTNode.TAG_ELEMENT, frags.get(1).getNodeType());
2362+
assertEquals("Invalid Text element content", "The general contract of `hashCode` is:", frags.get(2).toString());
2363+
}
2364+
2365+
}
2366+
2367+
public void testInconsistencyInCodeAndLiteralTagsMarkdown4609_02() throws JavaModelException {
2368+
String source = """
2369+
/// Performs:
2370+
///
2371+
/// {@literal
2372+
/// for (String s : strings) {
2373+
/// if (s.equals(value)) {
2374+
/// return 0;
2375+
/// }
2376+
/// if (s.startsWith(value)) {
2377+
/// return 1;
2378+
/// }
2379+
/// return -1;
2380+
/// }
2381+
/// }
2382+
/// The general contract of `hashCode` is:
2383+
///
2384+
/// - Whenever it is invoked on the same object more than once during
2385+
/// an execution of a Java application, the `hashCode` method
2386+
/// must consistently return the same integer, provided no information
2387+
/// used in `equals` comparisons on the object is modified.
2388+
/// This integer need not remain consistent from one execution of an
2389+
/// application to another execution of the same application.
2390+
/// - If two objects are equal according to the
2391+
/// [equals][#equals(Object)] method, then calling the
2392+
/// `hashCode` method on each of the two objects must produce the
2393+
/// same integer result.
2394+
/// - It is _not_ required that if two objects are unequal
2395+
/// according to the [equals][#equals(Object)] method, then
2396+
/// calling the `hashCode` method on each of the two objects
2397+
/// must produce distinct integer results. However, the programmer
2398+
/// should be aware that producing distinct integer results for
2399+
/// unequal objects may improve the performance of hash tables.
2400+
public class Markdown{}
2401+
""";
2402+
this.workingCopies = new ICompilationUnit[1];
2403+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/Markdown.java", source, null);
2404+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
2405+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
2406+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
2407+
Javadoc javadoc = typedeclaration.getJavadoc();
2408+
List<TagElement> tags = javadoc.tags();
2409+
List<ASTNode> frags = tags.get(0).fragments();
2410+
2411+
assertEquals("Incorrect Frags", 22, frags.size());
2412+
assertEquals("Invalid element", ASTNode.TAG_ELEMENT, frags.get(1).getNodeType());
2413+
assertEquals("Invalid Text element content", "The general contract of `hashCode` is:", frags.get(2).toString());
2414+
}
2415+
}
23172416
}

org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2025 IBM Corporation and others.
2+
* Copyright (c) 2000, 2026 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -2425,7 +2425,11 @@ private Javadoc convert(org.eclipse.jdt.internal.compiler.ast.Javadoc javadoc) {
24252425
ASTNode prev = fragments.get(0);
24262426
for (int i = 1; i < fragments.size(); i++) {
24272427
ASTNode cur = fragments.get(i);
2428-
if (cur.getStartPosition() <= prev.getStartPosition()) cur.setFlags(ASTNode.MALFORMED);
2428+
if (cur.getStartPosition() <= prev.getStartPosition())
2429+
cur.setFlags(ASTNode.MALFORMED);
2430+
else if ((cur.getStartPosition() + cur.getLength()) == (prev.getStartPosition()
2431+
+ prev.getLength()))
2432+
cur.setFlags(ASTNode.MALFORMED);
24292433
prev = cur;
24302434
}
24312435
}

0 commit comments

Comments
 (0)