diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java index 000cfd46829..c297ec3b76b 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2024 IBM Corporation and others. + * Copyright (c) 2000, 2026 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -181,7 +181,6 @@ protected boolean commentParse() { boolean isDomParser = (this.kind & DOM_PARSER) != 0; boolean isFormatterParser = (this.kind & FORMATTER_COMMENT_PARSER) != 0; int lastStarPosition = -1; - boolean isTagElementClose = false; // Init scanner position this.markdown = this.source[this.javadocStart + 1] == '/'; @@ -350,9 +349,6 @@ protected boolean commentParse() { // Fix bug 51650 this.textStart = -1; this.markdownHelper.resetAtLineEnd(); - if (this.inlineTagStarted && this.markdown) { - isTagElementClose = true; - } break; case '}' : if (verifText && this.tagValue == TAG_RETURN_VALUE && this.returnStatement != null) { @@ -366,6 +362,11 @@ protected boolean commentParse() { } } boolean isLiteralOrCode = this.tagValue == TAG_LITERAL_VALUE || this.tagValue == TAG_CODE_VALUE; + boolean shouldCloseInlineTag = + this.inlineTagStarted + && !considerTagAsPlainText + && !(isLiteralOrCode && openingBraces != 0); + if (this.inlineTagStarted) { textEndPosition = this.index - 1; boolean treatAsText= considerTagAsPlainText || (this.inlineReturn && this.inlineReturnOpenBraces > 0); @@ -380,12 +381,8 @@ protected boolean commentParse() { } if (!isFormatterParser && !treatAsText && (!this.inlineReturn || this.inlineReturnOpenBraces <= 0)) this.textStart = this.index; - if (!isTagElementClose && this.markdown) { //The comment parser should create a TagElement only if the previous one is closed - markdown. + if (shouldCloseInlineTag) { setInlineTagStarted(false); - } else if (!this.markdown) { - if (!(isLiteralOrCode && openingBraces != 0)) { - setInlineTagStarted(false); - } } if (this.inlineReturn) { if (this.inlineReturnOpenBraces > 0) { diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterMarkdownTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterMarkdownTest.java index 4229ec087dc..4457bcf4a93 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterMarkdownTest.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterMarkdownTest.java @@ -1840,7 +1840,7 @@ public class ArrayInCode { } } - public void testIllegelTagElement_01() throws JavaModelException { + public void testIllegelTagElement() throws JavaModelException { String source= """ ///{@link #getValue() ///value} @@ -1854,42 +1854,13 @@ class IllegelTagElement {} Javadoc javadoc = typedeclaration.getJavadoc(); List te = javadoc.tags(); assertEquals("TagElement length is grater than one", 1, te.size()); - List tes = (te.get(0)).fragments(); - assertEquals("inner TagElement length is grater than one", 1, tes.size()); - assertEquals("TagName", "@link", tes.get(0).getTagName()); - List fragments = tes.get(0).fragments(); + List tes = (te.get(0)).fragments(); + assertEquals("TagName", "@link", ((TagElement)tes.get(0)).getTagName()); + List fragments = ((TagElement)tes.get(0)).fragments(); assertEquals("fragments count does not match", 2, fragments.size()); assertTrue(fragments.get(0) instanceof MethodRef); assertTrue(fragments.get(1) instanceof TextElement); - assertEquals("Incorrect text", "value", fragments.get(1).toString()); - assertEquals("Incorrect name", "#getValue()", fragments.get(0).toString()); - } - } - - //this is a malfound test. Need to to analysis how it works - public void testIllegelTagElement_02() throws JavaModelException { - String source= """ - ///{@link #getValue() - ///value{}} - class IllegelTagElement {} - """; - this.workingCopies = new ICompilationUnit[1]; - this.workingCopies[0] = getWorkingCopy("/Converter_23/src/markdown/gh3761/IllegelTagElement.java", source, null); - if (this.docCommentSupport.equals(JavaCore.ENABLED)) { - CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); - TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); - Javadoc javadoc = typedeclaration.getJavadoc(); - List te = javadoc.tags(); - assertEquals("TagElement length is grater than one", 1, te.size()); - List tes = (te.get(0)).fragments(); -// assertEquals("fragments count does not match", 1, tes.size()); - assertEquals("TagName", "@link", tes.get(0).getTagName()); - List fragments = tes.get(0).fragments(); - assertTrue(fragments.get(0) instanceof MethodRef); - assertTrue(fragments.get(1) instanceof TextElement); - assertEquals("Incorrect text", "value", fragments.get(1).toString()); - assertEquals("Incorrect name", "#getValue()", fragments.get(0).toString()); - assertTrue(te.get(0).getLength() < tes.get(0).getLength()); + assertEquals("Incorrect TagElement", 1, ((TextElement) (tes.get(1))).getFlags() & ASTNode.MALFORMED); //MALFOUND flag } } @@ -2314,4 +2285,105 @@ public class Markdown{} assertEquals("invalid tag name","@literal" ,innerTag.getTagName()); } } + + public void testInconsistencyInCodeAndLiteralTagsMarkdown4609_01() throws JavaModelException { + String source = """ + /// Performs: + /// + /// {@code + /// for (String s : strings) { + /// if (s.equals(value)) { + /// return 0; + /// } + /// if (s.startsWith(value)) { + /// return 1; + /// } + /// return -1; + /// } + /// } + /// The general contract of `hashCode` is: + /// + /// - Whenever it is invoked on the same object more than once during + /// an execution of a Java application, the `hashCode` method + /// must consistently return the same integer, provided no information + /// used in `equals` comparisons on the object is modified. + /// This integer need not remain consistent from one execution of an + /// application to another execution of the same application. + /// - If two objects are equal according to the + /// [equals][#equals(Object)] method, then calling the + /// `hashCode` method on each of the two objects must produce the + /// same integer result. + /// - It is _not_ required that if two objects are unequal + /// according to the [equals][#equals(Object)] method, then + /// calling the `hashCode` method on each of the two objects + /// must produce distinct integer results. However, the programmer + /// should be aware that producing distinct integer results for + /// unequal objects may improve the performance of hash tables. + public class Markdown{} + """; + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + List tags = javadoc.tags(); + List frags = tags.get(0).fragments(); + + assertEquals("Incorrect Frags", 22, frags.size()); + assertEquals("Invalid element", ASTNode.TAG_ELEMENT, frags.get(1).getNodeType()); + assertEquals("Invalid Text element content", "The general contract of `hashCode` is:", frags.get(2).toString()); + } + + } + + public void testInconsistencyInCodeAndLiteralTagsMarkdown4609_02() throws JavaModelException { + String source = """ + /// Performs: + /// + /// {@literal + /// for (String s : strings) { + /// if (s.equals(value)) { + /// return 0; + /// } + /// if (s.startsWith(value)) { + /// return 1; + /// } + /// return -1; + /// } + /// } + /// The general contract of `hashCode` is: + /// + /// - Whenever it is invoked on the same object more than once during + /// an execution of a Java application, the `hashCode` method + /// must consistently return the same integer, provided no information + /// used in `equals` comparisons on the object is modified. + /// This integer need not remain consistent from one execution of an + /// application to another execution of the same application. + /// - If two objects are equal according to the + /// [equals][#equals(Object)] method, then calling the + /// `hashCode` method on each of the two objects must produce the + /// same integer result. + /// - It is _not_ required that if two objects are unequal + /// according to the [equals][#equals(Object)] method, then + /// calling the `hashCode` method on each of the two objects + /// must produce distinct integer results. However, the programmer + /// should be aware that producing distinct integer results for + /// unequal objects may improve the performance of hash tables. + public class Markdown{} + """; + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + List tags = javadoc.tags(); + List frags = tags.get(0).fragments(); + + assertEquals("Incorrect Frags", 22, frags.size()); + assertEquals("Invalid element", ASTNode.TAG_ELEMENT, frags.get(1).getNodeType()); + assertEquals("Invalid Text element content", "The general contract of `hashCode` is:", frags.get(2).toString()); + } + } } diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java index b00dcc69034..b0fea54618e 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2025 IBM Corporation and others. + * Copyright (c) 2000, 2026 IBM Corporation and others. * * This program and the accompanying materials * 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) { ASTNode prev = fragments.get(0); for (int i = 1; i < fragments.size(); i++) { ASTNode cur = fragments.get(i); - if (cur.getStartPosition() <= prev.getStartPosition()) cur.setFlags(ASTNode.MALFORMED); + if (cur.getStartPosition() <= prev.getStartPosition()) + cur.setFlags(ASTNode.MALFORMED); + else if ((cur.getStartPosition() + cur.getLength()) == (prev.getStartPosition() + + prev.getLength())) + cur.setFlags(ASTNode.MALFORMED); prev = cur; } }