Skip to content

Commit fd543c9

Browse files
Markdown Javadoc links not interpreted properly
Markdown links [description](url) syntax not interpreting properly Fix: #4531
1 parent 962ceca commit fd543c9

File tree

4 files changed

+342
-43
lines changed

4 files changed

+342
-43
lines changed

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,6 +1398,40 @@ protected boolean parseReference() throws InvalidInputException {
13981398
return parseReference(false);
13991399
}
14001400

1401+
// Parses a complete URL reference starting from current position
1402+
protected boolean parseURLReference(int pos, boolean advanceEndPos) throws InvalidInputException {
1403+
char[]fullURL = null;
1404+
int firstTokenStartPos;
1405+
StringBuilder urlBuilder = new StringBuilder();
1406+
char c;
1407+
firstTokenStartPos = pos;
1408+
while (pos < this.source.length) {
1409+
c = this.source[pos];
1410+
if (c == '[') // invalid syntax for url
1411+
return false;
1412+
if (c == '(' || c == ' ') {
1413+
pos++;
1414+
continue;
1415+
}
1416+
if (c == '\n' || c == '\r' || c == ')') {
1417+
break;
1418+
}
1419+
urlBuilder.append(c);
1420+
pos++;
1421+
}
1422+
if (advanceEndPos)
1423+
this.index = pos;
1424+
fullURL = urlBuilder.toString().toCharArray();
1425+
1426+
this.identifierPtr = 0;
1427+
this.identifierStack[this.identifierPtr] = fullURL;
1428+
this.identifierPositionStack[this.identifierPtr] = (((long) firstTokenStartPos) << 32) + (pos - 1);
1429+
this.identifierLengthStack[this.identifierLengthPtr] = 1;
1430+
Object typeRef = createTypeReference(TerminalToken.TokenNameInvalid, true);
1431+
pushSeeRef(typeRef);
1432+
return true;
1433+
}
1434+
14011435
/*
14021436
* Parse a reference in @see tag
14031437
*/
@@ -3617,6 +3651,7 @@ protected boolean verifySpaceOrEndComment() {
36173651
// Whitespace or inline tag closing brace
36183652
char ch = peekChar();
36193653
switch (ch) {
3654+
case ')':
36203655
case ']':
36213656
// TODO: Check if we need to exclude escaped ]
36223657
if (this.markdown)

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,8 @@ protected boolean parseMarkdownLinks(int previousPosition) throws InvalidInputEx
581581
// move it past '['
582582
currentChar = readChar();
583583
start = this.index;
584+
} else if (peekChar() == '(') {
585+
valid = parseURLReference(this.index, true);
584586
} else {
585587
break loop;
586588
}
@@ -602,7 +604,8 @@ protected boolean parseMarkdownLinks(int previousPosition) throws InvalidInputEx
602604
int eofBkup = this.scanner.eofPosition;
603605
this.scanner.resetTo(start, Math.max(this.javadocEnd, this.index));
604606
this.tagValue = TAG_LINK_VALUE;
605-
valid = parseReference(true);
607+
if (!valid)
608+
valid = parseReference(true);
606609
this.tagValue = NO_TAG_VALUE;
607610
this.scanner.eofPosition = eofBkup;
608611
this.markdownHelper.resetLineStart();

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

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,4 +1931,250 @@ public class Markdown() {}
19311931
assertEquals("Incorrect TextElement value", "Where is my **bold text**???", textElement.getText());
19321932
}
19331933
}
1934+
public void testMarkdownURLs4531_01() throws JavaModelException {
1935+
String source = """
1936+
/// @see [Ex Si](ex.com)
1937+
public class Markdown() {}
1938+
""";
1939+
this.workingCopies = new ICompilationUnit[1];
1940+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null);
1941+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
1942+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
1943+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
1944+
Javadoc javadoc = typedeclaration.getJavadoc();
1945+
TagElement tags = (TagElement) javadoc.tags().get(0);
1946+
assertEquals("fragments count does not match", 2, tags.fragments().size());
1947+
TagElement tagElement = (TagElement) tags.fragments().get(1);
1948+
List<?> tagFragments = tagElement.fragments();
1949+
assertTrue(tagFragments.get(0) instanceof TextElement);
1950+
assertTrue(tagFragments.get(1) instanceof SimpleName);
1951+
}
1952+
}
1953+
1954+
public void testMarkdownURLs4531_02() throws JavaModelException {
1955+
String source = """
1956+
/// @see [Ex Si](http://ex.com)
1957+
public class Markdown() {}
1958+
""";
1959+
this.workingCopies = new ICompilationUnit[1];
1960+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null);
1961+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
1962+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
1963+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
1964+
Javadoc javadoc = typedeclaration.getJavadoc();
1965+
TagElement tags = (TagElement) javadoc.tags().get(0);
1966+
assertEquals("fragments count does not match", 2, tags.fragments().size());
1967+
TagElement tagElement = (TagElement) tags.fragments().get(1);
1968+
List<?> tagFragments = tagElement.fragments();
1969+
assertTrue(tagFragments.get(0) instanceof TextElement);
1970+
assertTrue(tagFragments.get(1) instanceof SimpleName);
1971+
}
1972+
}
1973+
1974+
public void testMarkdownURLs4531_03() throws JavaModelException {
1975+
String source = """
1976+
/// @see [Ex Si](https://ex.com/a)
1977+
public class Markdown() {}
1978+
""";
1979+
this.workingCopies = new ICompilationUnit[1];
1980+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null);
1981+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
1982+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
1983+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
1984+
Javadoc javadoc = typedeclaration.getJavadoc();
1985+
TagElement tags = (TagElement) javadoc.tags().get(0);
1986+
assertEquals("fragments count does not match", 2, tags.fragments().size());
1987+
TagElement tagElement = (TagElement) tags.fragments().get(1);
1988+
List<?> tagFragments = tagElement.fragments();
1989+
assertTrue(tagFragments.get(0) instanceof TextElement);
1990+
assertTrue(tagFragments.get(1) instanceof SimpleName);
1991+
}
1992+
}
1993+
1994+
public void testMarkdownURLs4531_04() throws JavaModelException {
1995+
String source = """
1996+
/// @see [Ex Si](https://www.ex.net/a)
1997+
public class Markdown() {}
1998+
""";
1999+
this.workingCopies = new ICompilationUnit[1];
2000+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null);
2001+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
2002+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
2003+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
2004+
Javadoc javadoc = typedeclaration.getJavadoc();
2005+
TagElement tags = (TagElement) javadoc.tags().get(0);
2006+
assertEquals("fragments count does not match", 2, tags.fragments().size());
2007+
TagElement tagElement = (TagElement) tags.fragments().get(1);
2008+
List<?> tagFragments = tagElement.fragments();
2009+
assertTrue(tagFragments.get(0) instanceof TextElement);
2010+
assertTrue(tagFragments.get(1) instanceof SimpleName);
2011+
}
2012+
}
2013+
2014+
// invalid syntax
2015+
public void testMarkdownURLs4531_05() throws JavaModelException {
2016+
String source = """
2017+
/// @see [Ex Si][http://ex.com]
2018+
public class Markdown() {}
2019+
""";
2020+
this.workingCopies = new ICompilationUnit[1];
2021+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null);
2022+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
2023+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
2024+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
2025+
Javadoc javadoc = typedeclaration.getJavadoc();
2026+
TagElement tags = (TagElement) javadoc.tags().get(0);
2027+
assertEquals("fragments count does not match", 3, tags.fragments().size());
2028+
assertTrue(tags.fragments().get(0) instanceof TextElement);
2029+
assertTrue(tags.fragments().get(1) instanceof TextElement);
2030+
assertTrue(tags.fragments().get(2) instanceof TextElement);
2031+
}
2032+
}
2033+
2034+
// [)[) - invalid condition
2035+
public void testMarkdownURLs4531_06() throws JavaModelException {
2036+
String source = """
2037+
/// @see [Ex Si)[http://ex.com)
2038+
public class Markdown() {}
2039+
""";
2040+
this.workingCopies = new ICompilationUnit[1];
2041+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null);
2042+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
2043+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
2044+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
2045+
Javadoc javadoc = typedeclaration.getJavadoc();
2046+
assertEquals("Tags count does not match", 1, javadoc.tags().size());
2047+
TagElement tags = (TagElement) javadoc.tags().get(0);
2048+
assertTrue(tags.fragments().get(0) instanceof TextElement);
2049+
assertTrue(tags.fragments().get(1) instanceof TextElement);
2050+
}
2051+
}
2052+
2053+
// (](] - invalid condition
2054+
public void testMarkdownURLs4531_07() throws JavaModelException {
2055+
String source = """
2056+
/// @see (Ex Si](http://ex.com]
2057+
public class Markdown() {}
2058+
""";
2059+
this.workingCopies = new ICompilationUnit[1];
2060+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null);
2061+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
2062+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
2063+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
2064+
Javadoc javadoc = typedeclaration.getJavadoc();
2065+
TagElement tags = (TagElement) javadoc.tags().get(0);
2066+
assertEquals("fragments count does not match", 1, tags.fragments().size());
2067+
assertTrue(tags.fragments().get(0) instanceof TextElement);
2068+
}
2069+
}
2070+
2071+
// ()[] - invalid condition
2072+
public void testMarkdownURLs4531_08() throws JavaModelException {
2073+
String source = """
2074+
/// @see (Ex Si)[http://ex.com]
2075+
public class Markdown() {}
2076+
""";
2077+
this.workingCopies = new ICompilationUnit[1];
2078+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null);
2079+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
2080+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
2081+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
2082+
Javadoc javadoc = typedeclaration.getJavadoc();
2083+
TagElement tags = (TagElement) javadoc.tags().get(0);
2084+
assertEquals("fragments count does not match", 2, tags.fragments().size());
2085+
assertTrue(tags.fragments().get(0) instanceof TextElement);
2086+
assertTrue(tags.fragments().get(1) instanceof TextElement);
2087+
}
2088+
}
2089+
2090+
public void testMarkdownURLs4531_09() throws JavaModelException {
2091+
String source = """
2092+
/// @see [Ex Si]( http://ex.com)
2093+
public class Markdown() {}
2094+
""";
2095+
this.workingCopies = new ICompilationUnit[1];
2096+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null);
2097+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
2098+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
2099+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
2100+
Javadoc javadoc = typedeclaration.getJavadoc();
2101+
TagElement tags = (TagElement) javadoc.tags().get(0);
2102+
assertEquals("fragments count does not match", 2, tags.fragments().size());
2103+
assertTrue(tags.fragments().get(0) instanceof TextElement);
2104+
assertTrue(tags.fragments().get(1) instanceof TagElement);
2105+
TagElement fragTag = (TagElement) tags.fragments().get(1);
2106+
assertTrue(fragTag.fragments().get(0) instanceof TextElement);
2107+
assertTrue(fragTag.fragments().get(1) instanceof SimpleName);
2108+
}
2109+
}
2110+
2111+
public void testMarkdownURLs4531_10() throws JavaModelException {
2112+
String source = """
2113+
/// @see [Ex Si][java.lang.String]
2114+
public class Markdown() {}
2115+
""";
2116+
2117+
this.workingCopies = new ICompilationUnit[1];
2118+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null);
2119+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
2120+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
2121+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
2122+
Javadoc javadoc = typedeclaration.getJavadoc();
2123+
TagElement tags = (TagElement) javadoc.tags().get(0);
2124+
assertEquals("fragments count does not match", 2, tags.fragments().size());
2125+
assertTrue(tags.fragments().get(0) instanceof TextElement);
2126+
assertTrue(tags.fragments().get(1) instanceof TagElement);
2127+
TagElement fragTag = (TagElement) tags.fragments().get(1);
2128+
assertTrue(fragTag.fragments().get(0) instanceof TextElement);
2129+
assertTrue(fragTag.fragments().get(1) instanceof QualifiedName);
2130+
}
2131+
}
2132+
2133+
public void testMarkdownURLs4531_11() throws JavaModelException {
2134+
String source = """
2135+
/// @see [Ex Si][ java.lang.String]
2136+
public class Markdown() {}
2137+
""";
2138+
2139+
this.workingCopies = new ICompilationUnit[1];
2140+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null);
2141+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
2142+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
2143+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
2144+
Javadoc javadoc = typedeclaration.getJavadoc();
2145+
TagElement tags = (TagElement) javadoc.tags().get(0);
2146+
assertEquals("fragments count does not match", 2, tags.fragments().size());
2147+
assertTrue(tags.fragments().get(0) instanceof TextElement);
2148+
assertTrue(tags.fragments().get(1) instanceof TagElement);
2149+
TagElement fragTag = (TagElement) tags.fragments().get(1);
2150+
assertTrue(fragTag.fragments().get(0) instanceof TextElement);
2151+
assertTrue(fragTag.fragments().get(1) instanceof QualifiedName);
2152+
}
2153+
}
2154+
2155+
public void testMarkdownURLs4531_12() throws JavaModelException {
2156+
String source = """
2157+
/// @see [Ex Si](http://ex.com ) [Ex Si]( https://www.ex.com)
2158+
public class Markdown() {}
2159+
""";
2160+
this.workingCopies = new ICompilationUnit[1];
2161+
this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null);
2162+
if (this.docCommentSupport.equals(JavaCore.ENABLED)) {
2163+
CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true);
2164+
TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0);
2165+
Javadoc javadoc = typedeclaration.getJavadoc();
2166+
TagElement tags = (TagElement) javadoc.tags().get(0);
2167+
assertEquals("fragments count does not match", 4, tags.fragments().size());
2168+
assertTrue(tags.fragments().get(0) instanceof TextElement);
2169+
assertTrue(tags.fragments().get(1) instanceof TagElement);
2170+
TagElement tagFrag1 = (TagElement) tags.fragments().get(1);
2171+
SimpleName simplName1 = (SimpleName) tagFrag1.fragments().get(1);
2172+
assertEquals("SimpleName1 value not match", "http://ex.com", simplName1.getIdentifier());
2173+
assertTrue(tags.fragments().get(0) instanceof TextElement);
2174+
assertTrue(tags.fragments().get(1) instanceof TagElement);
2175+
TagElement tagFrag2 = (TagElement) tags.fragments().get(3);
2176+
SimpleName simplName2 = (SimpleName) tagFrag2.fragments().get(1);
2177+
assertEquals("SimpleName2 value not match", "https://www.ex.com", simplName2.getIdentifier());
2178+
}
2179+
}
19342180
}

0 commit comments

Comments
 (0)