From 2a3c437405f209028be48a3149e8c29e1eb0b8e6 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 5 Nov 2024 16:36:58 +0800 Subject: [PATCH] Access Javac API from a standalone javac jar instead of the JDK --- org.eclipse.jdt.core.javac/.classpath | 6 +- .../META-INF/MANIFEST.MF | 5 +- org.eclipse.jdt.core.javac/build.properties | 4 +- org.eclipse.jdt.core.javac/pom.xml | 81 +++++++---- .../jdt/core/dom/JavacBindingResolver.java | 2 +- .../eclipse/jdt/core/dom/JavacConverter.java | 56 ++++++-- .../jdt/core/dom/JavadocConverter.java | 131 +++++++++--------- 7 files changed, 176 insertions(+), 109 deletions(-) diff --git a/org.eclipse.jdt.core.javac/.classpath b/org.eclipse.jdt.core.javac/.classpath index bdfae34cced..9c4c0f5a4d2 100644 --- a/org.eclipse.jdt.core.javac/.classpath +++ b/org.eclipse.jdt.core.javac/.classpath @@ -2,11 +2,13 @@ - + - + + + diff --git a/org.eclipse.jdt.core.javac/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.javac/META-INF/MANIFEST.MF index 0745d90c2f9..11b5d944176 100644 --- a/org.eclipse.jdt.core.javac/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.core.javac/META-INF/MANIFEST.MF @@ -5,7 +5,10 @@ Bundle-SymbolicName: org.eclipse.jdt.core.javac;singleton:=true Bundle-Version: 1.0.0.qualifier Fragment-Host: org.eclipse.jdt.core Automatic-Module-Name: org.eclipse.jdt.core.javac -Require-Capability: osgi.ee; filter:="(&(osgi.ee=JavaSE)(version=23))" +Require-Capability: osgi.ee; filter:="(&(osgi.ee=JavaSE)(version=17))" Import-Package: org.eclipse.jdt.core.dom Export-Package: org.eclipse.jdt.internal.javac;x-friends:="org.eclipse.jdt.core.tests.javac", org.eclipse.jdt.internal.javac.dom;x-friends:="org.eclipse.jdt.core.tests.javac" +Bundle-ClassPath: lib/nb-javac-jdk-23+35.jar, + lib/nb-javac-jdk-23+35-api.jar, + . diff --git a/org.eclipse.jdt.core.javac/build.properties b/org.eclipse.jdt.core.javac/build.properties index e3023e14e99..7fe49b7240d 100644 --- a/org.eclipse.jdt.core.javac/build.properties +++ b/org.eclipse.jdt.core.javac/build.properties @@ -2,4 +2,6 @@ source.. = src/ output.. = bin/ bin.includes = META-INF/,\ .,\ - fragment.xml + fragment.xml,\ + lib/nb-javac-jdk-23+35.jar,\ + lib/nb-javac-jdk-23+35-api.jar diff --git a/org.eclipse.jdt.core.javac/pom.xml b/org.eclipse.jdt.core.javac/pom.xml index 5f93050c744..4b356cf6adb 100644 --- a/org.eclipse.jdt.core.javac/pom.xml +++ b/org.eclipse.jdt.core.javac/pom.xml @@ -20,37 +20,62 @@ - org.eclipse.tycho - tycho-compiler-plugin + org.apache.maven.plugins + maven-dependency-plugin - false - javac - - --add-exports - java.base/java.lang=ALL-UNNAMED - --add-exports - jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED - --add-exports - jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED - --add-exports - jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED - --add-exports - jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED - --add-exports - jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED - --add-exports - jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED - --add-exports - jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED - --add-exports - jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED - --add-exports - jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.taglets.snippet=ALL-UNNAMED - --add-exports - jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.taglets=ALL-UNNAMED - + + + com.dukescript.nbjavac + nb-javac + jdk-23+35 + + + com.dukescript.nbjavac + nb-javac + jdk-23+35 + api + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.8.1 + + + + get-libs + + copy + + validate + + + + false + ${basedir}/lib/ + + + + + + org.apache.maven.plugins + maven-clean-plugin + 3.4.0 + + + + ${basedir}/lib + + + + + + diff --git a/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacBindingResolver.java b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacBindingResolver.java index 2b16c4f0a75..3858bff1b8d 100644 --- a/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacBindingResolver.java +++ b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacBindingResolver.java @@ -1346,7 +1346,7 @@ private IMethodBinding resolveConstructorImpl(ClassInstanceCreation expression) boolean hasTrailingNull; boolean matchExactParamCount = false; do { - hasTrailingNull = !givenTypes.isEmpty() && givenTypes.getLast() == null; + hasTrailingNull = !givenTypes.isEmpty() && JavacConverter.getLast(givenTypes) == null; // try just checking by known args // first filter by args count var matchExactParamCountFinal = matchExactParamCount; diff --git a/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacConverter.java b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacConverter.java index 16d8dccad25..3f7a2520e61 100644 --- a/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacConverter.java +++ b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacConverter.java @@ -21,6 +21,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.OptionalInt; @@ -1681,7 +1682,7 @@ private Expression convertExpressionImpl(JCExpression javac) { if (arrayType.dimensions().isEmpty()) { arrayType.dimensions().addAll(extraDimensions); } else { - var lastDimension = arrayType.dimensions().removeFirst(); + var lastDimension = removeFirst(arrayType.dimensions()); arrayType.dimensions().addAll(extraDimensions); arrayType.dimensions().add(lastDimension); } @@ -1724,7 +1725,7 @@ private Expression convertExpressionImpl(JCExpression javac) { for( int i = 0; i < dims - 1; i++ ) { if( this.ast.apiLevel >= AST.JLS8_INTERNAL) { // TODO, this dimension needs source range - arrayType.dimensions().addFirst(this.ast.newDimension()); + addFirst(arrayType.dimensions(), this.ast.newDimension()); } else { // JLS < 8, wrap underlying arrayType = this.ast.newArrayType(arrayType); @@ -2000,11 +2001,11 @@ private ArrayInitializer createArrayInitializerFromJCNewArray(JCNewArray jcNewAr if (!jcNewArray.getInitializers().isEmpty()) { jcNewArray.getInitializers().stream().map(this::convertExpression).filter(Objects::nonNull).forEach(initializer.expressions()::add); this.rawText.charAt(0); - int start = ((Expression)initializer.expressions().getFirst()).getStartPosition() - 1; + int start = ((Expression) getFirst(initializer.expressions())).getStartPosition() - 1; while (start >= 0 && this.rawText.charAt(start) != '{') { start--; } - Expression lastExpr = (Expression)initializer.expressions().getLast(); + Expression lastExpr = (Expression) getLast(initializer.expressions()); int end = lastExpr.getStartPosition() + lastExpr.getLength() + 1; while (end < this.rawText.length() && this.rawText.charAt(end) != '}') { end++; @@ -2956,7 +2957,7 @@ Type convertToType(JCTree javac) { ArrayType res; if (t instanceof ArrayType childArrayType && this.ast.apiLevel > AST.JLS4_INTERNAL) { res = childArrayType; - res.dimensions().addFirst(this.ast.newDimension()); + addFirst(res.dimensions(), this.ast.newDimension()); commonSettings(res, jcArrayType.getType()); } else { int dims = countDimensions(jcArrayType); @@ -3359,7 +3360,7 @@ private int modifierToFlagVal(javax.lang.model.element.Modifier javac) { private Modifier convert(javax.lang.model.element.Modifier javac, int startPos, int endPos) { Modifier res = modifierToDom(javac); if (startPos >= 0 && endPos >= startPos && endPos <= this.rawText.length()) { - int indOf = this.rawText.indexOf(res.getKeyword().toString(), startPos, endPos); + int indOf = indexOf(this.rawText, res.getKeyword().toString(), startPos, endPos); if( indOf != -1 ) { res.setSourceRange(indOf, res.getKeyword().toString().length()); } @@ -3531,7 +3532,7 @@ private int findPositionOfText(String text, ASTNode in, List excluding) return -1; } if (excluded.isEmpty()) { - int position = this.contents.indexOf(text, current, current + in.getLength()); + int position = indexOf(this.contents, text, current, current + in.getLength()); if (position >= 0) { return position; } @@ -3540,7 +3541,7 @@ private int findPositionOfText(String text, ASTNode in, List excluding) while ((currentExclusion = excluded.poll()) != null) { if (currentExclusion.getStartPosition() >= current) { int rangeEnd = currentExclusion.getStartPosition(); - int position = this.contents.indexOf(text, current, rangeEnd); + int position = indexOf(this.contents, text, current, rangeEnd); if (position >= 0) { return position; } @@ -3654,5 +3655,44 @@ public DocTreePath[] searchRelatedDocTreePath(MethodRef ref) { return r; } + public static int indexOf(String original, String str, int fromIndex, int endIndex) { + int idx = original.indexOf(str, fromIndex); + if (idx < 0) { + return idx; + } + + if (idx + str.length() > endIndex) { + return -1; + } + + return idx; + } + + public static void addFirst(List original, T element) { + original.add(0, element); + } + public static T removeFirst(List list) { + if (list.isEmpty()) { + throw new NoSuchElementException(); + } else { + return list.remove(0); + } + } + + public static T getFirst(List original) { + if (original.isEmpty()) { + throw new NoSuchElementException(); + } else { + return original.get(0); + } + } + + public static T getLast(List original) { + if (original.isEmpty()) { + throw new NoSuchElementException(); + } else { + return original.get(original.size() - 1); + } + } } diff --git a/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavadocConverter.java b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavadocConverter.java index 6d66f62e4c1..b1806aa0a14 100644 --- a/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavadocConverter.java +++ b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavadocConverter.java @@ -62,9 +62,6 @@ import com.sun.tools.javac.util.Convert; import com.sun.tools.javac.util.JCDiagnostic; -import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.Attribute; -import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.MarkupParser; - class JavadocConverter { // Both copied from jdk.javadoc.internal.doclets.formats.html.taglets.snippet.Parser @@ -272,8 +269,8 @@ private Optional convertBlockTag(DCTree javac) { } int stopSearchAbsolute = this.docComment.getSourcePosition(stopSearchRelative); int start = this.docComment.getSourcePosition(param.getStartPosition()); - int ltRaw = this.javacConverter.rawText.indexOf("<", start, stopSearchAbsolute); - int gtRaw = this.javacConverter.rawText.indexOf(">", start, stopSearchAbsolute); + int ltRaw = JavacConverter.indexOf(this.javacConverter.rawText, "<", start, stopSearchAbsolute); + int gtRaw = JavacConverter.indexOf(this.javacConverter.rawText, ">", start, stopSearchAbsolute); if( ltRaw != -1 ) { int ltStart = this.docComment.getSourcePosition(tagNameEnds+1); // must include spaces @@ -328,8 +325,6 @@ private Optional convertBlockTag(DCTree javac) { return Optional.of(res); } - - private Stream convertInlineTag(DCTree javac) { ArrayList collector = new ArrayList<>(); TagElement res = this.ast.newTagElement(); @@ -364,9 +359,9 @@ private Stream convertInlineTag(DCTree javac) { } else if (javac instanceof DCSnippet snippet) { res.setTagName(TagElement.TAG_SNIPPET); res.setProperty(TagProperty.TAG_PROPERTY_SNIPPET_IS_VALID, true); - res.fragments().addAll(splitLines(snippet.body, true) - .map(this::toSnippetFragment) - .toList()); +// res.fragments().addAll(splitLines(snippet.body, true) +// .map(this::toSnippetFragment) +// .toList()); } else if (javac instanceof DCUnknownInlineTag unknown) { res.fragments().add(toDefaultTextElement(unknown)); } else { @@ -498,64 +493,64 @@ private Stream splitLines(DCTree[] allPositions) { return Stream.empty(); } - private IDocElement /* TextElement or TagElement for highlight/link... */ toSnippetFragment(Region region) { - TextElement defaultElement = toTextElementPreserveWhitespace(region); - if (!defaultElement.getText().endsWith("\n")) { - defaultElement.setText(defaultElement.getText() + '\n'); - } - String line = region.getContents(); - Matcher markedUpLine = JAVA_COMMENT.matcher(line); - if (!markedUpLine.matches()) { - return defaultElement; - } - int markupStart = markedUpLine.start("markup"); - String markup = line.substring(markupStart); - MarkupParser markupParser = new MarkupParser(null); - try { - List tags = markupParser.parse(markup); - if (tags.isEmpty()) { - return defaultElement; - } - TextElement initialTextElement = this.ast.newTextElement(); - initialTextElement.setSourceRange(region.startOffset, markupStart - 2 /* 2 is length of `//` */); - initialTextElement.setText(line.substring(0, markupStart - 2) + '\n'); - IDocElement currentElement = initialTextElement; - Class tagClass = tags.getFirst().getClass(); - Field nameField = tagClass.getDeclaredField("name"); //$NON-NLS-1$ - nameField.setAccessible(true); - Field attributesFields = tagClass.getDeclaredField("attributes"); //$NON-NLS-1$ - attributesFields.setAccessible(true); - for (Object tag : tags) { - String name = (String)nameField.get(tag); - List attributes = (List)attributesFields.get(tag); - TagElement newElement = this.ast.newTagElement(); - newElement.setSourceRange(region.startOffset, region.length); - newElement.setTagName('@' + name); - newElement.setProperty(TagProperty.TAG_PROPERTY_SNIPPET_INLINE_TAG_COUNT, 1); // TODO what? - attributes.stream().map(this::toTagProperty).forEach(newElement.tagProperties()::add); - newElement.fragments().add(currentElement); - currentElement = newElement; - } - return currentElement; - } catch (Exception ex) { - ILog.get().error("While trying to build snippet line " + line + ": " + ex.getMessage(), ex); - } - return defaultElement; - } - private TagProperty toTagProperty(Attribute snippetMarkupAttribute) { - TagProperty res = this.ast.newTagProperty(); - try { - Field name = Attribute.class.getDeclaredField("name"); //$NON-NLS-1$ - name.setAccessible(true); - res.setName((String)name.get(snippetMarkupAttribute)); - Field value = snippetMarkupAttribute.getClass().getDeclaredField("value"); //$NON-NLS-1$ - value.setAccessible(true); - res.setStringValue((String)value.get(snippetMarkupAttribute)); - } catch (Exception ex) { - ILog.get().error(ex.getMessage(), ex); - } - return res; - } +// private IDocElement /* TextElement or TagElement for highlight/link... */ toSnippetFragment(Region region) { +// TextElement defaultElement = toTextElementPreserveWhitespace(region); +// if (!defaultElement.getText().endsWith("\n")) { +// defaultElement.setText(defaultElement.getText() + '\n'); +// } +// String line = region.getContents(); +// Matcher markedUpLine = JAVA_COMMENT.matcher(line); +// if (!markedUpLine.matches()) { +// return defaultElement; +// } +// int markupStart = markedUpLine.start("markup"); +// String markup = line.substring(markupStart); +// MarkupParser markupParser = new MarkupParser(null); +// try { +// List tags = markupParser.parse(markup); +// if (tags.isEmpty()) { +// return defaultElement; +// } +// TextElement initialTextElement = this.ast.newTextElement(); +// initialTextElement.setSourceRange(region.startOffset, markupStart - 2 /* 2 is length of `//` */); +// initialTextElement.setText(line.substring(0, markupStart - 2) + '\n'); +// IDocElement currentElement = initialTextElement; +// Class tagClass = tags.getFirst().getClass(); +// Field nameField = tagClass.getDeclaredField("name"); //$NON-NLS-1$ +// nameField.setAccessible(true); +// Field attributesFields = tagClass.getDeclaredField("attributes"); //$NON-NLS-1$ +// attributesFields.setAccessible(true); +// for (Object tag : tags) { +// String name = (String)nameField.get(tag); +// List attributes = (List)attributesFields.get(tag); +// TagElement newElement = this.ast.newTagElement(); +// newElement.setSourceRange(region.startOffset, region.length); +// newElement.setTagName('@' + name); +// newElement.setProperty(TagProperty.TAG_PROPERTY_SNIPPET_INLINE_TAG_COUNT, 1); // TODO what? +// attributes.stream().map(this::toTagProperty).forEach(newElement.tagProperties()::add); +// newElement.fragments().add(currentElement); +// currentElement = newElement; +// } +// return currentElement; +// } catch (Exception ex) { +// ILog.get().error("While trying to build snippet line " + line + ": " + ex.getMessage(), ex); +// } +// return defaultElement; +// } +// private TagProperty toTagProperty(Attribute snippetMarkupAttribute) { +// TagProperty res = this.ast.newTagProperty(); +// try { +// Field name = Attribute.class.getDeclaredField("name"); //$NON-NLS-1$ +// name.setAccessible(true); +// res.setName((String)name.get(snippetMarkupAttribute)); +// Field value = snippetMarkupAttribute.getClass().getDeclaredField("value"); //$NON-NLS-1$ +// value.setAccessible(true); +// res.setStringValue((String)value.get(snippetMarkupAttribute)); +// } catch (Exception ex) { +// ILog.get().error(ex.getMessage(), ex); +// } +// return res; +// } private Stream convertElementGroup(DCTree[] javac) { return splitLines(javac).filter(x -> x.length != 0).flatMap(this::toTextOrTag);