diff options
31 files changed, 173 insertions, 1980 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json index 365226d..0fd8d55 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,5 +13,7 @@ "node_modules": true, "target": true, "out": true // set this to false to include "out" folder in search results - } + }, + "editor.formatOnSave": false, + "java.trace.server": "messages" }
\ No newline at end of file diff --git a/build-tools-jar/.gitignore b/build-tools-jar/.gitignore deleted file mode 100644 index f23b948..0000000 --- a/build-tools-jar/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.jar
\ No newline at end of file diff --git a/build-tools-jar/Dockerfile b/build-tools-jar/Dockerfile deleted file mode 100644 index 7f09bd4..0000000 --- a/build-tools-jar/Dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -# (C) Copyright IBM Corporation 2017. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -FROM ubuntu:14.04 - -# Install required OS tools -RUN apt-get update \ - && apt-get install -qq -y --no-install-recommends \ - cpio \ - make \ - gcc \ - g++ \ - libx11-dev \ - libxext-dev \ - libxrender-dev \ - libxtst-dev \ - libxt-dev \ - libcups2-dev \ - libfreetype6-dev \ - libasound2-dev \ - openjdk-7-jdk \ - ant \ - ccache \ - zip \ - wget \ - git \ - unzip \ - mercurial \ -&& rm -rf /var/lib/apt/lists/* - -# Clone JDK8 -RUN mkdir -p /langtools -RUN hg clone http://hg.netbeans.org/main/nb-javac /langtools - -WORKDIR /langtools - -# Get build script -RUN hg checkout release801 -COPY build.properties /langtools/make/ -RUN ant -f make/build.xml - -# Default actions -ENTRYPOINT sleep 1000
\ No newline at end of file diff --git a/build-tools-jar/README.md b/build-tools-jar/README.md deleted file mode 100644 index cbaaae8..0000000 --- a/build-tools-jar/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Dockerfile to build the NetBeans fork of OpenJDK tools.jar from source - -Run ./make.sh to create tools-1.8.jar and tools-1.8-sources.jar
\ No newline at end of file diff --git a/build-tools-jar/build.properties b/build-tools-jar/build.properties deleted file mode 100644 index 19107f4..0000000 --- a/build-tools-jar/build.properties +++ /dev/null @@ -1,204 +0,0 @@ -# -# Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# This is the JDK used to build and run the bootstrap version of javac. -# The bootstrap javac is used to compile both boostrap versions of the -# other tools, and product versions of all the tools. -# Override this path as needed, either on the command line or in -# one of the standard user build.properties files (see build.xml) - -boot.java.home = /usr/lib/jvm/java-1.7.0-openjdk-amd64 -boot.java = ${boot.java.home}/bin/java -boot.javac = ${boot.java.home}/bin/javac -boot.javac.source = 7 -boot.javac.target = 7 - -# This is the JDK used to run the product version of the tools, -# for example, for testing. If you're building a complete JDK, specify that. -# Override this path as needed, either on the command line or in -# one of the standard user build.properties files (see build.xml) - -target.java.home = ${boot.java.home} -target.java = ${target.java.home}/bin/java - -# Version info -- override as needed -jdk.version = 1.8.0 -build.number = b00 -milestone = internal - -# FIXME -- these need to match the standard values -# If we include date in full.version (ie for developer build) -# we will need to make sure the build is idempotent (i.e. -# repeated builds don't rebuild the tools, because of new -# timestamps -# FIXME -- need to include openjdk as needed -release = ${jdk.version}-${milestone} -bootstrap.release = ${release}_bootstrap -full.version = ${release}-${build.number} -bootstrap.full.version = ${bootstrap.release}-${build.number} - -# options for the <javac> tasks used to compile the tools -javac.source = 8 -javac.target = 8 -javac.debug = true -javac.debuglevel = source,lines -javac.no.jdk.warnings = -XDignore.symbol.file=true -# set the following to -version to verify the versions of javac being used -javac.version.opt = -# in time, there should be no exceptions to -Xlint:all -javac.lint.opts = -Xlint:all - -# options for the <javadoc> task for javac -#javadoc.jls3.url=http://java.sun.com/docs/books/jls/ -#javadoc.jls3.cite=<a href="${javadoc.jls3.url}">The Java Language Specification, Third Edition</a> -#javadoc.jls3.option=-tag "jls3:a:See <cite>${javadoc.jls3.cite}</cite>:" - - -javadoc.jls.cite=The Java™ Language Specification - -javadoc.jls.option=-tag "jls:a:See <cite>${javadoc.jls.cite}</cite>:" - - - - - -# jtreg, used to run the JDK regression tests -# See http://openjdk.java.net/jtreg/ -# Override this path as needed, either on the command line or in -# one of the standard user build.properties files (see build.xml) - -# jtreg.home = /opt/jtreg/4.1 - -# findbugs -# See http://findbugs.sourceforge.net/ -# Override this path as needed, either on the command line or in -# one of the standard user build.properties files (see build.xml) - -# findbugs.home = /opt/findbugs/1.2.1 - -# vizant (graph visualization tool for Ant) -# See http://vizant.sourceforge.net/ -# Override this path as needed, either on the command line or in -# one of the standard user build.properties files (see build.xml) - -# vizant.jar = /opt/vizant/0.1.2/vizant-0.1.2.jar -# dot = dot - -#------------------------------------------------------------ - -# The following properties define the packages for each of the tools. -# Syntactically, they should be suitable as arguments for the "includes" -# parameter of Ant filesets. In particular, note the trailing '/'. - -javac.includes = \ - javax/annotation/processing/ \ - javax/lang/model/ \ - javax/tools/ \ - jdk/ \ - com/sun/source/ \ - com/sun/tools/javac/ \ - com/sun/tools/doclint/ - -javac.tests = \ - tools/javac - -# - -javadoc.includes = \ - com/sun/javadoc/ \ - com/sun/tools/javadoc/ - -javadoc.tests = \ - tools/javadoc/ - -# - -doclets.includes = \ - com/sun/tools/doclets/ - -doclets.tests = \ - com/sun/javadoc/ - -# - -javah.includes = \ - com/sun/tools/javah/ - -javah.tests = \ - tools/javah/ - -# - -javap.includes = \ - com/sun/tools/classfile/ \ - com/sun/tools/javap/ \ - com/sun/tools/jdeps/ \ - sun/tools/javap/ - -javap.tests = \ - tools/javap/ - -# - -sjavac.includes = \ - com/sun/tools/sjavac/ - -sjavac.tests = \ - tools/sjavac - -# - -# The following files require the latest JDK to be available. -# The API can be provided by using a suitable boot.java.home -# or by setting import.jdk -require.latest.jdk.files = \ - com/sun/tools/javac/nio/*.java - -# The following files in the import jdk source directory are required -# in order to compile the files defined in ${require.latest.jdk.files} -# -# For NIO, the list of stub files is defined by the contents of the primary -# API packages, together with such types that may be required in order to -# compile the stubs. Some of these dependencies would go away if the stub -# generator were to be improved -- e.g. by removing unnecessary imports. -# -import.jdk.stub.files = \ - java/io/File.java \ - java/nio/file/**.java \ - java/nio/file/attribute/**.java \ - java/nio/file/spi/**.java \ - java/nio/channels/AsynchronousChannel.java \ - java/nio/channels/AsynchronousFileChannel.java \ - java/nio/channels/CompletionHandler.java \ - java/nio/channels/SeekableByteChannel.java - -# The following value is used by the main jtreg target. -# An empty value means all tests -# Override as desired to run a specific set of tests -jtreg.tests = - -# Check style configuration -# overridable name and version -checkstyle.name.version = checkstyle-5.4 diff --git a/build-tools-jar/make.sh b/build-tools-jar/make.sh deleted file mode 100755 index 8b4248b..0000000 --- a/build-tools-jar/make.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -docker build . --tag openjdk-tools -docker run -d openjdk-tools -CONTAINER_ID=$(docker ps -a | awk '{ print $1,$2 }' | grep openjdk-tools | awk '{print $1 }'| head -1) -docker cp $CONTAINER_ID:/langtools/dist/lib/classes.jar tools-1.8.jar -docker cp $CONTAINER_ID:/langtools/dist/lib/src.zip tools-1.8-sources.jar -docker stop $CONTAINER_ID
\ No newline at end of file diff --git a/lib/extension.ts b/lib/extension.ts index ef9db39..706e440 100644 --- a/lib/extension.ts +++ b/lib/extension.ts @@ -4,7 +4,6 @@ import * as VSCode from "vscode"; import * as Path from "path"; import * as FS from "fs"; -import * as ChildProcess from "child_process"; import {LanguageClient, LanguageClientOptions, ServerOptions} from "vscode-languageclient"; /** Called when extension is activated */ @@ -18,107 +17,88 @@ export function activate(context: VSCode.ExtensionContext) { return; } - - isJava8(javaExecutablePath).then(eight => { - if (!eight) { - VSCode.window.showErrorMessage('Java language support requires Java 8 (using ' + javaExecutablePath + ')'); - - return; - } - - // Options to control the language client - let clientOptions: LanguageClientOptions = { - // Register the server for java documents - documentSelector: ['java'], - synchronize: { - // Synchronize the setting section 'java' to the server - // NOTE: this currently doesn't do anything - configurationSection: 'java', - // Notify the server about file changes to 'javaconfig.json' files contain in the workspace - fileEvents: [ - VSCode.workspace.createFileSystemWatcher('**/javaconfig.json'), - VSCode.workspace.createFileSystemWatcher('**/pom.xml'), - VSCode.workspace.createFileSystemWatcher('**/WORKSPACE'), - VSCode.workspace.createFileSystemWatcher('**/BUILD'), - VSCode.workspace.createFileSystemWatcher('**/*.java') - ] - }, - outputChannelName: 'Java', - revealOutputChannelOn: 4 // never - } - - let fatJar = Path.resolve(context.extensionPath, "out", "fat-jar.jar"); - - let args = [ - '-cp', fatJar, - '-Xverify:none', // helps VisualVM avoid 'error 62' - 'org.javacs.Main' - ]; - - console.log(javaExecutablePath + ' ' + args.join(' ')); - // Start the child java process - let serverOptions: ServerOptions = { - command: javaExecutablePath, - args: args, - options: { cwd: VSCode.workspace.rootPath } - } - - console.log(javaExecutablePath + ' ' + args.join(' ')); - - // Copied from typescript - VSCode.languages.setLanguageConfiguration('java', { - indentationRules: { - // ^(.*\*/)?\s*\}.*$ - decreaseIndentPattern: /^((?!.*?\/\*).*\*\/)?\s*[\}\]\)].*$/, - // ^.*\{[^}"']*$ - increaseIndentPattern: /^((?!\/\/).)*(\{[^}"'`]*|\([^)"'`]*|\[[^\]"'`]*)$/, - indentNextLinePattern: /^\s*(for|while|if|else)\b(?!.*[;{}]\s*(\/\/.*|\/[*].*[*]\/\s*)?$)/ - }, - onEnterRules: [ - { - // e.g. /** | */ - beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, - afterText: /^\s*\*\/$/, - action: { indentAction: VSCode.IndentAction.IndentOutdent, appendText: ' * ' } - }, { - // e.g. /** ...| - beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, - action: { indentAction: VSCode.IndentAction.None, appendText: ' * ' } - }, { - // e.g. * ...| - beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/, - action: { indentAction: VSCode.IndentAction.None, appendText: '* ' } - }, { - // e.g. */| - beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/, - action: { indentAction: VSCode.IndentAction.None, removeText: 1 } - }, - { - // e.g. *-----*/| - beforeText: /^(\t|(\ \ ))*\ \*[^/]*\*\/\s*$/, - action: { indentAction: VSCode.IndentAction.None, removeText: 1 } - } + // Options to control the language client + let clientOptions: LanguageClientOptions = { + // Register the server for java documents + documentSelector: ['java'], + synchronize: { + // Synchronize the setting section 'java' to the server + // NOTE: this currently doesn't do anything + configurationSection: 'java', + // Notify the server about file changes to 'javaconfig.json' files contain in the workspace + fileEvents: [ + VSCode.workspace.createFileSystemWatcher('**/javaconfig.json'), + VSCode.workspace.createFileSystemWatcher('**/pom.xml'), + VSCode.workspace.createFileSystemWatcher('**/WORKSPACE'), + VSCode.workspace.createFileSystemWatcher('**/BUILD'), + VSCode.workspace.createFileSystemWatcher('**/*.java') ] - }) + }, + outputChannelName: 'Java', + revealOutputChannelOn: 4 // never + } + + let fatJar = Path.resolve(context.extensionPath, "out", "fat-jar.jar"); - // Create the language client and start the client. - let languageClient = new LanguageClient('java', 'Java Language Server', serverOptions, clientOptions); - let disposable = languageClient.start(); + let args = [ + '-cp', fatJar, + '-Xverify:none', // helps VisualVM avoid 'error 62' + 'org.javacs.Main' + ]; - // Push the disposable to the context's subscriptions so that the - // client can be deactivated on extension deactivation - context.subscriptions.push(disposable); - }); -} + console.log(javaExecutablePath + ' ' + args.join(' ')); + // Start the child java process + let serverOptions: ServerOptions = { + command: javaExecutablePath, + args: args, + options: { cwd: VSCode.workspace.rootPath } + } -function isJava8(javaExecutablePath: string): Promise<boolean> { - return new Promise((resolve, reject) => { - ChildProcess.execFile(javaExecutablePath, ['-version'], { }, (error, stdout, stderr) => { - let eight = stderr.indexOf('1.8') >= 0, nine = stderr.indexOf('"9"') >= 0; - - resolve(eight || nine); - }); - }); + console.log(javaExecutablePath + ' ' + args.join(' ')); + + // Copied from typescript + VSCode.languages.setLanguageConfiguration('java', { + indentationRules: { + // ^(.*\*/)?\s*\}.*$ + decreaseIndentPattern: /^((?!.*?\/\*).*\*\/)?\s*[\}\]\)].*$/, + // ^.*\{[^}"']*$ + increaseIndentPattern: /^((?!\/\/).)*(\{[^}"'`]*|\([^)"'`]*|\[[^\]"'`]*)$/, + indentNextLinePattern: /^\s*(for|while|if|else)\b(?!.*[;{}]\s*(\/\/.*|\/[*].*[*]\/\s*)?$)/ + }, + onEnterRules: [ + { + // e.g. /** | */ + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + afterText: /^\s*\*\/$/, + action: { indentAction: VSCode.IndentAction.IndentOutdent, appendText: ' * ' } + }, { + // e.g. /** ...| + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + action: { indentAction: VSCode.IndentAction.None, appendText: ' * ' } + }, { + // e.g. * ...| + beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/, + action: { indentAction: VSCode.IndentAction.None, appendText: '* ' } + }, { + // e.g. */| + beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/, + action: { indentAction: VSCode.IndentAction.None, removeText: 1 } + }, + { + // e.g. *-----*/| + beforeText: /^(\t|(\ \ ))*\ \*[^/]*\*\/\s*$/, + action: { indentAction: VSCode.IndentAction.None, removeText: 1 } + } + ] + }) + + // Create the language client and start the client. + let languageClient = new LanguageClient('java', 'Java Language Server', serverOptions, clientOptions); + let disposable = languageClient.start(); + + // Push the disposable to the context's subscriptions so that the + // client can be deactivated on extension deactivation + context.subscriptions.push(disposable); } function findJavaExecutable(binname: string) { @@ -7,14 +7,6 @@ <artifactId>javac-services</artifactId> <packaging>jar</packaging> <version>0.1-SNAPSHOT</version> - <repositories> - <!-- Local repository with tools.jar --> - <repository> - <id>jars-repository</id> - <name>Local repository for JAR files</name> - <url>file://${basedir}/repo</url> - </repository> - </repositories> <distributionManagement> <repository> <id>distribution-repository</id> @@ -23,14 +15,9 @@ </repository> </distributionManagement> <properties> - <jackson-2-version>2.5.0</jackson-2-version> + <jackson-2-version>2.9.6</jackson-2-version> </properties> <dependencies> - <dependency> - <groupId>com.sun</groupId> - <artifactId>tools</artifactId> - <version>1.8</version> - </dependency> <!-- Java implementation of VS Code language server protocol --> <dependency> <groupId>org.eclipse.lsp4j</groupId> @@ -97,14 +84,14 @@ </dependencies> <build> <plugins> - <!-- Set source 1.8 --> + <!-- Set source 1.10 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> - <version>3.3</version> - <configuration> - <source>1.8</source> - <target>1.8</target> + <version>3.7.0</version> + <configuration>com.sun.tools.javac + <source>10</source> + <target>10</target> </configuration> </plugin> <!-- Configure fat jar --> diff --git a/repo/com/sun/tools/1.8/tools-1.8-sources.jar b/repo/com/sun/tools/1.8/tools-1.8-sources.jar Binary files differdeleted file mode 100644 index 90919df..0000000 --- a/repo/com/sun/tools/1.8/tools-1.8-sources.jar +++ /dev/null diff --git a/repo/com/sun/tools/1.8/tools-1.8.jar b/repo/com/sun/tools/1.8/tools-1.8.jar Binary files differdeleted file mode 100644 index 859f7e6..0000000 --- a/repo/com/sun/tools/1.8/tools-1.8.jar +++ /dev/null diff --git a/repo/com/sun/tools/1.8/tools-1.8.pom b/repo/com/sun/tools/1.8/tools-1.8.pom deleted file mode 100644 index c455e20..0000000 --- a/repo/com/sun/tools/1.8/tools-1.8.pom +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <modelVersion>4.0.0</modelVersion> - <groupId>com.sun</groupId> - <artifactId>tools</artifactId> - <version>1.8</version> - <description>POM was created from install:install-file</description> -</project> diff --git a/repo/com/sun/tools/maven-metadata-local.xml b/repo/com/sun/tools/maven-metadata-local.xml deleted file mode 100644 index c0a129e..0000000 --- a/repo/com/sun/tools/maven-metadata-local.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<metadata> - <groupId>com.sun</groupId> - <artifactId>tools</artifactId> - <versioning> - <release>1.8</release> - <versions> - <version>1.8</version> - </versions> - <lastUpdated>20160319190138</lastUpdated> - </versioning> -</metadata> diff --git a/src/main/java/org/javacs/ClassPathIndex.java b/src/main/java/org/javacs/ClassPathIndex.java index ec07dcf..9a05c44 100644 --- a/src/main/java/org/javacs/ClassPathIndex.java +++ b/src/main/java/org/javacs/ClassPathIndex.java @@ -75,7 +75,9 @@ class ClassPathIndex { } private static boolean isJava9() { - return StandardSystemProperty.JAVA_VERSION.value().equals("9"); + String v = StandardSystemProperty.JAVA_VERSION.value(); + LOG.info("Loading platform for version " + v); + return v.startsWith("9") || v.startsWith("10"); } private static URL[] platform() { diff --git a/src/main/java/org/javacs/JavaCompilerService.java b/src/main/java/org/javacs/JavaCompilerService.java index 6e79510..f123443 100644 --- a/src/main/java/org/javacs/JavaCompilerService.java +++ b/src/main/java/org/javacs/JavaCompilerService.java @@ -4,26 +4,13 @@ import com.google.common.base.StandardSystemProperty; import com.google.common.reflect.ClassPath; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.MethodDoc; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.ImportTree; -import com.sun.source.tree.LineMap; -import com.sun.source.tree.MemberReferenceTree; -import com.sun.source.tree.MemberSelectTree; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.NewClassTree; -import com.sun.source.tree.Scope; -import com.sun.source.tree.Tree; -import com.sun.source.tree.VariableTree; +import com.sun.source.tree.*; import com.sun.source.util.JavacTask; import com.sun.source.util.SourcePositions; import com.sun.source.util.TreePath; import com.sun.source.util.TreePathScanner; import com.sun.source.util.TreeScanner; import com.sun.source.util.Trees; -import com.sun.tools.javac.api.JavacTool; import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -37,19 +24,10 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -77,7 +55,7 @@ public class JavaCompilerService { // Not modifiable! If you want to edit these, you need to create a new instance private final Set<Path> sourcePath, classPath, docPath; private final ClassPath classPathIndex; - private final JavaCompiler compiler = JavacTool.create(); // TODO switch to java 9 mechanism + private final JavaCompiler compiler = ServiceLoader.load(JavaCompiler.class).iterator().next(); private final Javadocs docs; private final ClassPathIndex classes; // Diagnostics from the last compilation task @@ -90,6 +68,9 @@ public class JavaCompilerService { private Cache cache; public JavaCompilerService(Set<Path> sourcePath, Set<Path> classPath, Set<Path> docPath) { + Class klass = compiler.getClass(); + URL location = klass.getResource('/' + klass.getName().replace('.', '/') + ".class"); + LOG.info("Creating a new compiler..."); LOG.info("Source path:"); for (Path p : sourcePath) { @@ -145,7 +126,9 @@ public class JavaCompilerService { } private static boolean isJava9() { - return StandardSystemProperty.JAVA_VERSION.value().equals("9"); + String v = StandardSystemProperty.JAVA_VERSION.value(); + LOG.info("Loading platform for version " + v); + return v.startsWith("9") || v.startsWith("10"); } private static URL[] platform() { @@ -317,8 +300,8 @@ public class JavaCompilerService { long cursor = cache.root.getLineMap().getPosition(line, character); // Search for the smallest element that encompasses line:column - class FindSmallest extends TreeScanner<Void, Void> { - Tree found = null; + class FindSmallest extends TreePathScanner<Void, Void> { + TreePath found = null; boolean containsCursor(Tree tree) { long start = pos.getStartPosition(cache.root, tree), end = pos.getEndPosition(cache.root, tree); @@ -331,25 +314,30 @@ public class JavaCompilerService { @Override public Void scan(Tree tree, Void nothing) { // This is pre-order traversal, so the deepest element will be the last one remaining in `found` - if (containsCursor(tree)) found = tree; + if (containsCursor(tree)) found = new TreePath(getCurrentPath(), tree); super.scan(tree, nothing); return null; } - Optional<Tree> find(Tree root) { + @Override + public Void visitErroneous(ErroneousTree node, Void nothing) { + for (Tree t : node.getErrorTrees()) { + t.accept(this, nothing); + } + return null; + } + + Optional<TreePath> find(Tree root) { scan(root, null); return Optional.ofNullable(found); } } - Tree found = - new FindSmallest() - .find(cache.root) - .orElseThrow( - () -> - new RuntimeException( - String.format("No TreePath to %s %d:%d", file, line, character))); - - return trees.getPath(cache.root, found); + Supplier<RuntimeException> notFound = + () -> { + String m = String.format("No TreePath to %s %d:%d", file, line, character); + return new RuntimeException(m); + }; + return new FindSmallest().find(cache.root).orElseThrow(notFound); } /** Find all identifiers in scope at line:character */ @@ -639,7 +627,7 @@ public class JavaCompilerService { } } // Add names of classes that haven't been imported - String packageName = parse.getPackageName().toString(); + String packageName = Objects.toString(parse.getPackageName(), ""); Iterator<Completion> notImported = classes.topLevelClasses() // This is very cheap, so we do it first @@ -657,6 +645,14 @@ public class JavaCompilerService { return null; } + @Override + public Void visitErroneous(ErroneousTree node, Void nothing) { + for (Tree t : node.getErrorTrees()) { + t.accept(this, null); + } + return null; + } + CompletionResult run() { scan(parse, null); if (result == null) result = Collections.emptyList(); @@ -966,6 +962,9 @@ public class JavaCompilerService { Trees trees = Trees.instance(cache.task); TreePath path = path(file, line, character); + // It's sort of odd that this works + // `to` is part of a different batch than `batch = compileBatch(possible)`, + // so `to.equals(...thing from batch...)` shouldn't work Element to = trees.getElement(path); List<Path> possible = potentialReferences(to); Batch batch = compileBatch(possible); diff --git a/src/main/java/org/javacs/Javadocs.java b/src/main/java/org/javacs/Javadocs.java index 25adcc7..a86599f 100644 --- a/src/main/java/org/javacs/Javadocs.java +++ b/src/main/java/org/javacs/Javadocs.java @@ -9,9 +9,6 @@ import com.sun.javadoc.MethodDoc; import com.sun.javadoc.Parameter; import com.sun.javadoc.RootDoc; import com.sun.source.util.JavacTask; -import com.sun.tools.javac.api.JavacTool; -import com.sun.tools.javac.file.JavacFileManager; -import com.sun.tools.javadoc.api.JavadocTool; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -19,11 +16,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.text.BreakIterator; import java.time.Instant; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; import java.util.regex.Matcher; @@ -32,18 +25,17 @@ import java.util.stream.Collectors; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; -import javax.tools.DocumentationTool; -import javax.tools.JavaFileObject; -import javax.tools.StandardLocation; +import javax.tools.*; // This class must be public so DocletInvoker can call it public class Javadocs { /** Cache for performance reasons */ - private final JavacFileManager actualFileManager; + private final StandardJavaFileManager actualFileManager; /** Empty file manager we pass to javadoc to prevent it from roaming all over the place */ - private final JavacFileManager emptyFileManager = JavacTool.create().getStandardFileManager(__ -> {}, null, null); + private final StandardJavaFileManager emptyFileManager = + ServiceLoader.load(JavaCompiler.class).iterator().next().getStandardFileManager(__ -> {}, null, null); /** All the classes we have indexed so far */ private final Map<String, IndexedDoc> topLevelClasses = new ConcurrentHashMap<>(); @@ -62,7 +54,12 @@ public class Javadocs { Javadocs(Set<Path> sourcePath, Set<Path> docPath) { this.actualFileManager = createFileManager(allSourcePaths(sourcePath, docPath)); - this.task = JavacTool.create().getTask(null, emptyFileManager, __ -> {}, null, null, null); + this.task = + (JavacTask) + ServiceLoader.load(JavaCompiler.class) + .iterator() + .next() + .getTask(null, emptyFileManager, __ -> {}, null, null, null); } @SafeVarargs @@ -80,8 +77,9 @@ public class Javadocs { return allSourcePaths; } - private static JavacFileManager createFileManager(Set<File> allSourcePaths) { - JavacFileManager actualFileManager = JavacTool.create().getStandardFileManager(__ -> {}, null, null); + private static StandardJavaFileManager createFileManager(Set<File> allSourcePaths) { + StandardJavaFileManager actualFileManager = + ServiceLoader.load(JavaCompiler.class).iterator().next().getStandardFileManager(__ -> {}, null, null); try { actualFileManager.setLocation(StandardLocation.SOURCE_PATH, allSourcePaths); @@ -216,7 +214,7 @@ public class Javadocs { LOG.info("Found " + source.toUri() + " for " + className); DocumentationTool.DocumentationTask task = - new JavadocTool() + ToolProvider.getSystemDocumentationTool() .getTask(null, emptyFileManager, __ -> {}, Javadocs.class, null, ImmutableList.of(source)); task.call(); @@ -245,7 +243,7 @@ public class Javadocs { /** * Called by the javadoc tool * - * <p>{@link Doclet} + * <p>{@link com.sun.javadoc.Doclet} */ public static boolean start(RootDoc root) { sneakyReturn.set(root); diff --git a/src/main/java/org/javacs/Main.java b/src/main/java/org/javacs/Main.java index 412775a..0a77882 100644 --- a/src/main/java/org/javacs/Main.java +++ b/src/main/java/org/javacs/Main.java @@ -12,17 +12,18 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JSR310Module; -import com.sun.tools.javac.api.JavacTool; import java.io.IOException; import java.lang.reflect.Method; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ServiceLoader; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.FileHandler; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; +import javax.tools.JavaCompiler; import org.eclipse.lsp4j.jsonrpc.Launcher; import org.eclipse.lsp4j.launch.LSPLauncher; import org.eclipse.lsp4j.services.LanguageClient; @@ -85,7 +86,7 @@ public class Main { } public static ClassLoader checkJavacClassLoader() { - return JavacTool.create().getClass().getClassLoader(); + return ServiceLoader.load(JavaCompiler.class).iterator().next().getClass().getClassLoader(); } public static void run() { diff --git a/src/main/java/org/javacs/Parser.java b/src/main/java/org/javacs/Parser.java index c03cd72..3a64001 100644 --- a/src/main/java/org/javacs/Parser.java +++ b/src/main/java/org/javacs/Parser.java @@ -12,7 +12,6 @@ import com.sun.source.util.SourcePositions; import com.sun.source.util.TreePath; import com.sun.source.util.TreePathScanner; import com.sun.source.util.Trees; -import com.sun.tools.javac.api.JavacTool; import java.io.BufferedReader; import java.io.IOException; import java.net.URI; @@ -21,23 +20,14 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.function.Consumer; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import org.eclipse.lsp4j.Location; @@ -48,18 +38,19 @@ import org.eclipse.lsp4j.SymbolKind; class Parser { - private static final JavacTool compiler = JavacTool.create(); // TODO switch to java 9 mechanism + private static final JavaCompiler compiler = ServiceLoader.load(JavaCompiler.class).iterator().next(); private static final StandardJavaFileManager fileManager = compiler.getStandardFileManager(__ -> {}, null, Charset.defaultCharset()); private static JavacTask parseTask(JavaFileObject file) { - return compiler.getTask( - null, - fileManager, - err -> LOG.warning(err.getMessage(Locale.getDefault())), - Collections.emptyList(), - null, - Collections.singletonList(file)); + return (JavacTask) + compiler.getTask( + null, + fileManager, + err -> LOG.warning(err.getMessage(Locale.getDefault())), + Collections.emptyList(), + null, + Collections.singletonList(file)); } private static JavacTask parseTask(Path source) { @@ -232,7 +223,7 @@ class Parser { return c.getSimpleName().toString(); } else if (t instanceof CompilationUnitTree) { CompilationUnitTree c = (CompilationUnitTree) t; - return c.getPackageName().toString(); + return Objects.toString(c.getPackageName(), ""); } else { parent = parent.getParentPath(); } diff --git a/src/main/java/org/javacs/Pruner.java b/src/main/java/org/javacs/Pruner.java index e99ed38..5011165 100644 --- a/src/main/java/org/javacs/Pruner.java +++ b/src/main/java/org/javacs/Pruner.java @@ -9,12 +9,12 @@ import com.sun.source.util.JavacTask; import com.sun.source.util.SourcePositions; import com.sun.source.util.TreeScanner; import com.sun.source.util.Trees; -import com.sun.tools.javac.api.JavacTool; import java.io.IOException; import java.net.URI; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Collections; +import java.util.ServiceLoader; import java.util.logging.Logger; import javax.tools.Diagnostic; import javax.tools.JavaCompiler; @@ -25,7 +25,7 @@ class Pruner { private static final Logger LOG = Logger.getLogger("main"); // Parse-only compiler // TODO this should come from Parser - private static final JavaCompiler COMPILER = JavacTool.create(); // TODO switch to java 9 mechanism + private static final JavaCompiler COMPILER = ServiceLoader.load(JavaCompiler.class).iterator().next(); private static final StandardJavaFileManager FILE_MANAGER = COMPILER.getStandardFileManager(Pruner::report, null, Charset.defaultCharset()); diff --git a/src/main/java/org/javacs/pubapi/ArrayTypeDesc.java b/src/main/java/org/javacs/pubapi/ArrayTypeDesc.java deleted file mode 100644 index 4668c22..0000000 --- a/src/main/java/org/javacs/pubapi/ArrayTypeDesc.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.javacs.pubapi; - -import java.io.Serializable; -import javax.lang.model.type.TypeKind; - -public class ArrayTypeDesc extends TypeDesc implements Serializable { - - private static final long serialVersionUID = -1177329549163314996L; - - TypeDesc compTypeDesc; - - public ArrayTypeDesc(TypeDesc compTypeDesc) { - super(TypeKind.ARRAY); - this.compTypeDesc = compTypeDesc; - } - - @Override - public boolean equals(Object obj) { - if (!super.equals(obj)) return false; - return compTypeDesc.equals(((ArrayTypeDesc) obj).compTypeDesc); - } - - @Override - public int hashCode() { - return super.hashCode() ^ compTypeDesc.hashCode(); - } -} diff --git a/src/main/java/org/javacs/pubapi/PrimitiveTypeDesc.java b/src/main/java/org/javacs/pubapi/PrimitiveTypeDesc.java deleted file mode 100644 index 81d1683..0000000 --- a/src/main/java/org/javacs/pubapi/PrimitiveTypeDesc.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.javacs.pubapi; - -import com.sun.tools.javac.util.StringUtils; -import java.io.Serializable; -import javax.lang.model.type.TypeKind; - -public class PrimitiveTypeDesc extends TypeDesc implements Serializable { - - private static final long serialVersionUID = 6051065543149129106L; - - public PrimitiveTypeDesc(TypeKind typeKind) { - super(typeKind); - if (!typeKind.isPrimitive() && typeKind != TypeKind.VOID) - throw new IllegalArgumentException("Only primitives or void accepted"); - } - - // This class has no fields, so the inherited hashCode and equals should do fine. - - @Override - public String toString() { - return StringUtils.toLowerCase(typeKind.toString()); - } -} diff --git a/src/main/java/org/javacs/pubapi/PubApi.java b/src/main/java/org/javacs/pubapi/PubApi.java deleted file mode 100644 index dc6c181..0000000 --- a/src/main/java/org/javacs/pubapi/PubApi.java +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.javacs.pubapi; - -import static org.javacs.pubapi.Util.union; - -import com.sun.tools.javac.util.Assert; -import com.sun.tools.javac.util.StringUtils; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.lang.model.element.Modifier; - -public class PubApi implements Serializable { - - private static final long serialVersionUID = 5926627347801986850L; - - // Used to have Set here. Problem is that the objects are mutated during - // javac_state loading, causing them to change hash codes. We could probably - // change back to Set once javac_state loading is cleaned up. - public final Map<String, PubType> types = new HashMap<>(); - public final Map<String, PubVar> variables = new HashMap<>(); - public final Map<String, PubMethod> methods = new HashMap<>(); - - public PubApi() {} - - public PubApi(Collection<PubType> types, Collection<PubVar> variables, Collection<PubMethod> methods) { - types.forEach(this::addPubType); - variables.forEach(this::addPubVar); - methods.forEach(this::addPubMethod); - } - - // Currently this is implemented as equality. This is far from optimal. It - // should preferably make sure that all previous methods are still available - // and no abstract methods are added. It should also be aware of inheritance - // of course. - public boolean isBackwardCompatibleWith(PubApi older) { - return equals(older); - } - - private static String typeLine(PubType type) { - if (type.fqName.isEmpty()) throw new RuntimeException("empty class name " + type); - return String.format("TYPE %s%s", asString(type.modifiers), type.fqName); - } - - private static String varLine(PubVar var) { - return String.format( - "VAR %s%s %s%s", - asString(var.modifiers), - TypeDesc.encodeAsString(var.type), - var.identifier, - var.getConstValue().map(v -> " = " + v).orElse("")); - } - - private static String methodLine(PubMethod method) { - return String.format( - "METHOD %s%s%s %s(%s)%s", - asString(method.modifiers), - method.typeParams.isEmpty() - ? "" - : ("<" - + method.typeParams - .stream() - .map(PubApiTypeParam::asString) - .collect(Collectors.joining(",")) - + "> "), - TypeDesc.encodeAsString(method.returnType), - method.identifier, - commaSeparated(method.paramTypes), - method.throwDecls.isEmpty() ? "" : " throws " + commaSeparated(method.throwDecls)); - } - - public List<String> asListOfStrings() { - List<String> lines = new ArrayList<>(); - - // Types - types.values() - .stream() - .sorted(Comparator.comparing(PubApi::typeLine)) - .forEach( - type -> { - lines.add(typeLine(type)); - for (String subline : type.pubApi.asListOfStrings()) lines.add(" " + subline); - }); - - // Variables - variables.values().stream().map(PubApi::varLine).sorted().forEach(lines::add); - - // Methods - methods.values().stream().map(PubApi::methodLine).sorted().forEach(lines::add); - - return lines; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - PubApi other = (PubApi) obj; - return types.equals(other.types) && variables.equals(other.variables) && methods.equals(other.methods); - } - - @Override - public int hashCode() { - return types.keySet().hashCode() ^ variables.keySet().hashCode() ^ methods.keySet().hashCode(); - } - - private static String commaSeparated(List<TypeDesc> typeDescs) { - return typeDescs.stream().map(TypeDesc::encodeAsString).collect(Collectors.joining(",")); - } - - // Create space separated list of modifiers (with a trailing space) - private static String asString(Set<Modifier> modifiers) { - return modifiers.stream().map(mod -> mod + " ").sorted().collect(Collectors.joining()); - } - - // Used to combine class PubApis to package level PubApis - public static PubApi mergeTypes(PubApi api1, PubApi api2) { - Assert.check(api1.methods.isEmpty(), "Can only merge types."); - Assert.check(api2.methods.isEmpty(), "Can only merge types."); - Assert.check(api1.variables.isEmpty(), "Can only merge types."); - Assert.check(api2.variables.isEmpty(), "Can only merge types."); - PubApi merged = new PubApi(); - merged.types.putAll(api1.types); - merged.types.putAll(api2.types); - return merged; - } - - // Used for line-by-line parsing - private PubType lastInsertedType = null; - - private static final String MODIFIERS = - Stream.of(Modifier.values()) - .map(Modifier::name) - .map(StringUtils::toLowerCase) - .collect(Collectors.joining("|", "(", ")")); - - private static final Pattern MOD_PATTERN = Pattern.compile("(" + MODIFIERS + " )*"); - private static final Pattern METHOD_PATTERN = - Pattern.compile("(?<ret>.+?) (?<name>\\S+)\\((?<params>.*)\\)( throws (?<throws>.*))?"); - private static final Pattern VAR_PATTERN = - Pattern.compile("VAR (?<modifiers>(" + MODIFIERS + " )*)(?<type>.+?) (?<id>\\S+)( = (?<val>.*))?"); - private static final Pattern TYPE_PATTERN = - Pattern.compile("TYPE (?<modifiers>(" + MODIFIERS + " )*)(?<fullyQualified>\\S+)"); - - public void appendItem(String l) { - try { - if (l.startsWith(" ")) { - lastInsertedType.pubApi.appendItem(l.substring(2)); - return; - } - - if (l.startsWith("METHOD")) { - l = l.substring("METHOD ".length()); - Set<Modifier> modifiers = new HashSet<>(); - Matcher modMatcher = MOD_PATTERN.matcher(l); - if (modMatcher.find()) { - String modifiersStr = modMatcher.group(); - modifiers.addAll(parseModifiers(modifiersStr)); - l = l.substring(modifiersStr.length()); - } - List<PubApiTypeParam> typeParams = new ArrayList<>(); - if (l.startsWith("<")) { - int closingPos = findClosingTag(l, 0); - String str = l.substring(1, closingPos); - l = l.substring(closingPos + 1); - typeParams.addAll(parseTypeParams(splitOnTopLevelCommas(str))); - } - Matcher mm = METHOD_PATTERN.matcher(l); - if (!mm.matches()) - throw new AssertionError( - "Could not parse return type, identifier, parameter types or throws declaration of method: " - + l); - - List<String> params = splitOnTopLevelCommas(mm.group("params")); - String th = Optional.ofNullable(mm.group("throws")).orElse(""); - List<String> throwz = splitOnTopLevelCommas(th); - PubMethod m = - new PubMethod( - modifiers, - typeParams, - TypeDesc.decodeString(mm.group("ret")), - mm.group("name"), - parseTypeDescs(params), - parseTypeDescs(throwz)); - addPubMethod(m); - return; - } - - Matcher vm = VAR_PATTERN.matcher(l); - if (vm.matches()) { - addPubVar( - new PubVar( - parseModifiers(vm.group("modifiers")), - TypeDesc.decodeString(vm.group("type")), - vm.group("id"), - vm.group("val"))); - return; - } - - Matcher tm = TYPE_PATTERN.matcher(l); - if (tm.matches()) { - addPubType( - new PubType(parseModifiers(tm.group("modifiers")), tm.group("fullyQualified"), new PubApi())); - return; - } - - throw new AssertionError("No matching line pattern."); - } catch (Throwable e) { - throw new AssertionError("Could not parse API line: " + l, e); - } - } - - public void addPubType(PubType t) { - types.put(t.fqName, t); - lastInsertedType = t; - } - - public void addPubVar(PubVar v) { - variables.put(v.identifier, v); - } - - public void addPubMethod(PubMethod m) { - methods.put(m.asSignatureString(), m); - } - - private static List<TypeDesc> parseTypeDescs(List<String> strs) { - return strs.stream().map(TypeDesc::decodeString).collect(Collectors.toList()); - } - - private static List<PubApiTypeParam> parseTypeParams(List<String> strs) { - return strs.stream().map(PubApi::parseTypeParam).collect(Collectors.toList()); - } - - // Parse a type parameter string. Example input: - // identifier - // identifier extends Type (& Type)* - private static PubApiTypeParam parseTypeParam(String typeParamString) { - int extPos = typeParamString.indexOf(" extends "); - if (extPos == -1) return new PubApiTypeParam(typeParamString, Collections.emptyList()); - String identifier = typeParamString.substring(0, extPos); - String rest = typeParamString.substring(extPos + " extends ".length()); - List<TypeDesc> bounds = parseTypeDescs(splitOnTopLevelChars(rest, '&')); - return new PubApiTypeParam(identifier, bounds); - } - - public Set<Modifier> parseModifiers(String modifiers) { - if (modifiers == null) return Collections.emptySet(); - return Stream.of(modifiers.split(" ")) - .map(String::trim) - .map(StringUtils::toUpperCase) - .filter(s -> !s.isEmpty()) - .map(Modifier::valueOf) - .collect(Collectors.toSet()); - } - - // Find closing tag of the opening tag at the given 'pos'. - private static int findClosingTag(String l, int pos) { - while (true) { - pos = pos + 1; - if (l.charAt(pos) == '>') return pos; - if (l.charAt(pos) == '<') pos = findClosingTag(l, pos); - } - } - - public List<String> splitOnTopLevelCommas(String s) { - return splitOnTopLevelChars(s, ','); - } - - public static List<String> splitOnTopLevelChars(String s, char split) { - if (s.isEmpty()) return Collections.emptyList(); - List<String> result = new ArrayList<>(); - StringBuilder buf = new StringBuilder(); - int depth = 0; - for (char c : s.toCharArray()) { - if (c == split && depth == 0) { - result.add(buf.toString().trim()); - buf = new StringBuilder(); - } else { - if (c == '<') depth++; - if (c == '>') depth--; - buf.append(c); - } - } - result.add(buf.toString().trim()); - return result; - } - - public boolean isEmpty() { - return types.isEmpty() && variables.isEmpty() && methods.isEmpty(); - } - - // Used for descriptive debug messages when figuring out what triggers - // recompilation. - public List<String> diff(PubApi prevApi) { - return diff("", prevApi); - } - - private List<String> diff(String scopePrefix, PubApi prevApi) { - - List<String> diffs = new ArrayList<>(); - - for (String typeKey : union(types.keySet(), prevApi.types.keySet())) { - PubType type = types.get(typeKey); - PubType prevType = prevApi.types.get(typeKey); - if (prevType == null) { - diffs.add("Type " + scopePrefix + typeKey + " was added"); - } else if (type == null) { - diffs.add("Type " + scopePrefix + typeKey + " was removed"); - } else { - // Check modifiers - if (!type.modifiers.equals(prevType.modifiers)) { - diffs.add( - "Modifiers for type " - + scopePrefix - + typeKey - + " changed from " - + prevType.modifiers - + " to " - + type.modifiers); - } - - // Recursively check types pub API - diffs.addAll(type.pubApi.diff(prevType.pubApi)); - } - } - - for (String varKey : union(variables.keySet(), prevApi.variables.keySet())) { - PubVar var = variables.get(varKey); - PubVar prevVar = prevApi.variables.get(varKey); - if (prevVar == null) { - diffs.add("Variable " + scopePrefix + varKey + " was added"); - } else if (var == null) { - diffs.add("Variable " + scopePrefix + varKey + " was removed"); - } else { - if (!var.modifiers.equals(prevVar.modifiers)) { - diffs.add( - "Modifiers for var " - + scopePrefix - + varKey - + " changed from " - + prevVar.modifiers - + " to " - + var.modifiers); - } - if (!var.type.equals(prevVar.type)) { - diffs.add("Type of " + scopePrefix + varKey + " changed from " + prevVar.type + " to " + var.type); - } - if (!var.getConstValue().equals(prevVar.getConstValue())) { - diffs.add( - "Const value of " - + scopePrefix - + varKey - + " changed from " - + prevVar.getConstValue().orElse("<none>") - + " to " - + var.getConstValue().orElse("<none>")); - } - } - } - - for (String methodKey : union(methods.keySet(), prevApi.methods.keySet())) { - PubMethod method = methods.get(methodKey); - PubMethod prevMethod = prevApi.methods.get(methodKey); - if (prevMethod == null) { - diffs.add("Method " + scopePrefix + methodKey + " was added"); - } else if (method == null) { - diffs.add("Method " + scopePrefix + methodKey + " was removed"); - } else { - if (!method.modifiers.equals(prevMethod.modifiers)) { - diffs.add( - "Modifiers for method " - + scopePrefix - + methodKey - + " changed from " - + prevMethod.modifiers - + " to " - + method.modifiers); - } - if (!method.typeParams.equals(prevMethod.typeParams)) { - diffs.add( - "Type parameters for method " - + scopePrefix - + methodKey - + " changed from " - + prevMethod.typeParams - + " to " - + method.typeParams); - } - if (!method.throwDecls.equals(prevMethod.throwDecls)) { - diffs.add( - "Throw decl for method " - + scopePrefix - + methodKey - + " changed from " - + prevMethod.throwDecls - + " to " - + " to " - + method.throwDecls); - } - } - } - - return diffs; - } - - public String toString() { - return String.format( - "%s[types: %s, variables: %s, methods: %s]", - getClass().getSimpleName(), types.values(), variables.values(), methods.values()); - } -} diff --git a/src/main/java/org/javacs/pubapi/PubApiTypeParam.java b/src/main/java/org/javacs/pubapi/PubApiTypeParam.java deleted file mode 100644 index 657282c..0000000 --- a/src/main/java/org/javacs/pubapi/PubApiTypeParam.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.javacs.pubapi; - -import java.io.Serializable; -import java.util.List; -import java.util.stream.Collectors; - -public class PubApiTypeParam implements Serializable { - - private static final long serialVersionUID = 8899204612014329162L; - - private final String identifier; - private final List<TypeDesc> bounds; - - public PubApiTypeParam(String identifier, List<TypeDesc> bounds) { - this.identifier = identifier; - this.bounds = bounds; - } - - @Override - public boolean equals(Object obj) { - if (getClass() != obj.getClass()) return false; - PubApiTypeParam other = (PubApiTypeParam) obj; - return identifier.equals(other.identifier) && bounds.equals(other.bounds); - } - - @Override - public int hashCode() { - return identifier.hashCode() ^ bounds.hashCode(); - } - - public String asString() { - if (bounds.isEmpty()) return identifier; - String boundsStr = bounds.stream().map(TypeDesc::encodeAsString).collect(Collectors.joining(" & ")); - return identifier + " extends " + boundsStr; - } - - @Override - public String toString() { - return String.format("%s[id: %s, bounds: %s]", getClass().getSimpleName(), identifier, bounds); - } -} diff --git a/src/main/java/org/javacs/pubapi/PubMethod.java b/src/main/java/org/javacs/pubapi/PubMethod.java deleted file mode 100644 index c3b1df3..0000000 --- a/src/main/java/org/javacs/pubapi/PubMethod.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.javacs.pubapi; - -import java.io.Serializable; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import javax.lang.model.element.Modifier; - -public class PubMethod implements Serializable { - - private static final long serialVersionUID = -7813050194553446243L; - - Set<Modifier> modifiers; - List<PubApiTypeParam> typeParams; - TypeDesc returnType; - String identifier; - List<TypeDesc> paramTypes; - List<TypeDesc> throwDecls; - - public PubMethod( - Set<Modifier> modifiers, - List<PubApiTypeParam> typeParams, - TypeDesc returnType, - String identifier, - List<TypeDesc> paramTypes, - List<TypeDesc> throwDecls) { - this.modifiers = modifiers; - this.typeParams = typeParams; - this.returnType = returnType; - this.identifier = identifier; - this.paramTypes = paramTypes; - this.throwDecls = throwDecls; - } - - // We need to include return type and type parameters to be sure to have - // different values for different methods. (A method can be overloaded with - // the only difference being the upper bound of the return type.) - public String asSignatureString() { - StringBuilder sb = new StringBuilder(); - - // <A extends String, Serializable, B extends List> - if (typeParams.size() > 0) { - sb.append(typeParams.stream().map(PubApiTypeParam::asString).collect(Collectors.joining(",", "<", "> "))); - } - sb.append(TypeDesc.encodeAsString(returnType)); - sb.append(" "); - sb.append(identifier); - sb.append("("); - sb.append(paramTypes.stream().map(TypeDesc::encodeAsString).collect(Collectors.joining(","))); - sb.append(")"); - return sb.toString(); - } - - @Override - public boolean equals(Object obj) { - if (getClass() != obj.getClass()) return false; - PubMethod other = (PubMethod) obj; - return modifiers.equals(other.modifiers) - && typeParams.equals(other.typeParams) - && returnType.equals(other.returnType) - && identifier.equals(other.identifier) - && paramTypes.equals(other.paramTypes) - && throwDecls.equals(other.throwDecls); - } - - @Override - public int hashCode() { - return modifiers.hashCode() - ^ typeParams.hashCode() - ^ returnType.hashCode() - ^ identifier.hashCode() - ^ paramTypes.hashCode() - ^ throwDecls.hashCode(); - } - - public String toString() { - return String.format( - "%s[modifiers: %s, typeParams: %s, retType: %s, identifier: %s, params: %s, throws: %s]", - getClass().getSimpleName(), modifiers, typeParams, returnType, identifier, paramTypes, throwDecls); - } -} diff --git a/src/main/java/org/javacs/pubapi/PubType.java b/src/main/java/org/javacs/pubapi/PubType.java deleted file mode 100644 index 3601e7b..0000000 --- a/src/main/java/org/javacs/pubapi/PubType.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.javacs.pubapi; - -import java.io.Serializable; -import java.util.Set; -import javax.lang.model.element.Modifier; - -public class PubType implements Serializable { - - private static final long serialVersionUID = -7423416049253889793L; - - public final Set<Modifier> modifiers; - public final String fqName; - public final PubApi pubApi; - - public PubType(Set<Modifier> modifiers, String fqName, PubApi pubApi) { - this.modifiers = modifiers; - this.fqName = fqName; - this.pubApi = pubApi; - } - - public String getFqName() { - return fqName.toString(); - } - - @Override - public boolean equals(Object obj) { - if (getClass() != obj.getClass()) return false; - PubType other = (PubType) obj; - return modifiers.equals(other.modifiers) && fqName.equals(other.fqName) && pubApi.equals(other.pubApi); - } - - @Override - public int hashCode() { - return modifiers.hashCode() ^ fqName.hashCode() ^ pubApi.hashCode(); - } - - @Override - public String toString() { - return String.format( - "%s[modifiers: %s, fqName: %s, pubApi: %s]", getClass().getSimpleName(), modifiers, fqName, pubApi); - } -} diff --git a/src/main/java/org/javacs/pubapi/PubVar.java b/src/main/java/org/javacs/pubapi/PubVar.java deleted file mode 100644 index 25831a7..0000000 --- a/src/main/java/org/javacs/pubapi/PubVar.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.javacs.pubapi; - -import java.io.Serializable; -import java.util.Optional; -import java.util.Set; -import javax.lang.model.element.Modifier; - -public class PubVar implements Serializable { - - private static final long serialVersionUID = 5806536061153374575L; - - public final Set<Modifier> modifiers; - public final TypeDesc type; - public final String identifier; - private final String constValue; - - public PubVar(Set<Modifier> modifiers, TypeDesc type, String identifier, String constValue) { - this.modifiers = modifiers; - this.type = type; - this.identifier = identifier; - this.constValue = constValue; - } - - public String getIdentifier() { - return identifier; - } - - @Override - public boolean equals(Object obj) { - if (getClass() != obj.getClass()) return false; - PubVar other = (PubVar) obj; - return modifiers.equals(other.modifiers) - && type.equals(other.type) - && identifier.equals(other.identifier) - && getConstValue().equals(other.getConstValue()); - } - - @Override - public int hashCode() { - return modifiers.hashCode() ^ type.hashCode() ^ identifier.hashCode() ^ getConstValue().hashCode(); - } - - public String toString() { - return String.format( - "%s[modifiers: %s, type: %s, identifier: %s, constValue: %s]", - getClass().getSimpleName(), modifiers, type, identifier, constValue); - } - - public Optional<String> getConstValue() { - return Optional.ofNullable(constValue); - } -} diff --git a/src/main/java/org/javacs/pubapi/PubapiVisitor.java b/src/main/java/org/javacs/pubapi/PubapiVisitor.java deleted file mode 100644 index baa2bcf..0000000 --- a/src/main/java/org/javacs/pubapi/PubapiVisitor.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.javacs.pubapi; - -import static javax.lang.model.element.Modifier.PRIVATE; - -import com.sun.tools.javac.code.Symbol.ClassSymbol; -import java.util.List; -import java.util.stream.Collectors; -import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.TypeParameterElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.ElementScanner8; - -/** - * Utility class that constructs a textual representation of the public api of a class. - * - * <p><b>This is NOT part of any supported API. If you write code that depends on this, you do so at your own risk. This - * code and its internal interfaces are subject to change or deletion without notice.</b> - */ -public class PubapiVisitor extends ElementScanner8<Void, Void> { - - private PubApi collectedApi = new PubApi(); - - private boolean isNonPrivate(Element e) { - return !e.getModifiers().contains(PRIVATE); - } - - @Override - public Void visitType(TypeElement e, Void p) { - if (isNonPrivate(e)) { - PubApi prevApi = collectedApi; - collectedApi = new PubApi(); - super.visitType(e, p); - if (!isAnonymous(e)) { - String name = ((ClassSymbol) e).flatname.toString(); - PubType t = - new PubType( - e.getModifiers(), - name, - // e.getQualifiedName().toString(), - collectedApi); - prevApi.types.put(t.fqName, t); - } - collectedApi = prevApi; - } - return null; - } - - private boolean isAnonymous(TypeElement e) { - return e.getQualifiedName().length() == 0; - } - - private static String encodeChar(int c) { - return String.format("\\u%04x", c); - } - - @Override - public Void visitVariable(VariableElement e, Void p) { - if (isNonPrivate(e)) { - Object constVal = e.getConstantValue(); - String constValStr = null; - // TODO: This doesn't seem to be entirely accurate. What if I change - // from, say, 0 to 0L? (And the field is public final static so that - // it could get inlined.) - if (constVal != null) { - if (e.asType().toString().equals("char")) { - // What type is 'value'? Is it already a char? - char c = constVal.toString().charAt(0); - constValStr = "'" + encodeChar(c) + "'"; - } else { - constValStr = - constVal.toString() - .chars() - .mapToObj(PubapiVisitor::encodeChar) - .collect(Collectors.joining("", "\"", "\"")); - } - } - - PubVar v = new PubVar(e.getModifiers(), TypeDesc.fromType(e.asType()), e.toString(), constValStr); - collectedApi.variables.put(v.identifier, v); - } - - // Safe to not recurse here, because the only thing - // to visit here is the constructor of a variable declaration. - // If it happens to contain an anonymous inner class (which it might) - // then this class is never visible outside of the package anyway, so - // we are allowed to ignore it here. - return null; - } - - @Override - public Void visitExecutable(ExecutableElement e, Void p) { - if (isNonPrivate(e)) { - PubMethod m = - new PubMethod( - e.getModifiers(), - getTypeParameters(e.getTypeParameters()), - TypeDesc.fromType(e.getReturnType()), - e.getSimpleName().toString(), - getTypeDescs(getParamTypes(e)), - getTypeDescs(e.getThrownTypes())); - collectedApi.methods.put(m.asSignatureString(), m); - } - return null; - } - - private List<PubApiTypeParam> getTypeParameters(List<? extends TypeParameterElement> elements) { - return elements.stream() - .map(e -> new PubApiTypeParam(e.getSimpleName().toString(), getTypeDescs(e.getBounds()))) - .collect(Collectors.toList()); - } - - private List<TypeMirror> getParamTypes(ExecutableElement e) { - return e.getParameters().stream().map(VariableElement::asType).collect(Collectors.toList()); - } - - private List<TypeDesc> getTypeDescs(List<? extends TypeMirror> list) { - return list.stream().map(TypeDesc::fromType).collect(Collectors.toList()); - } - - public PubApi getCollectedPubApi() { - return collectedApi; - } -} diff --git a/src/main/java/org/javacs/pubapi/ReferenceTypeDesc.java b/src/main/java/org/javacs/pubapi/ReferenceTypeDesc.java deleted file mode 100644 index 3aac9e5..0000000 --- a/src/main/java/org/javacs/pubapi/ReferenceTypeDesc.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.javacs.pubapi; - -import java.io.Serializable; -import javax.lang.model.type.TypeKind; - -public class ReferenceTypeDesc extends TypeDesc implements Serializable { - - private static final long serialVersionUID = 3357616754544796372L; - - // Example: "java.util.Vector<java.lang.String>" - String javaType; - - public ReferenceTypeDesc(String javaType) { - super(TypeKind.DECLARED); - this.javaType = javaType; - } - - @Override - public boolean equals(Object obj) { - if (!super.equals(obj)) return false; - return javaType.equals(((ReferenceTypeDesc) obj).javaType); - } - - @Override - public int hashCode() { - return super.hashCode() ^ javaType.hashCode(); - } - - @Override - public String toString() { - return String.format("%s[type: %s]", getClass().getSimpleName(), javaType); - } -} diff --git a/src/main/java/org/javacs/pubapi/TypeDesc.java b/src/main/java/org/javacs/pubapi/TypeDesc.java deleted file mode 100644 index 299af6c..0000000 --- a/src/main/java/org/javacs/pubapi/TypeDesc.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.javacs.pubapi; - -import com.sun.tools.javac.code.Type.ClassType; -import com.sun.tools.javac.util.StringUtils; -import java.io.Serializable; -import javax.lang.model.type.ArrayType; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.ErrorType; -import javax.lang.model.type.NoType; -import javax.lang.model.type.PrimitiveType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVariable; -import javax.lang.model.type.TypeVisitor; -import javax.lang.model.util.SimpleTypeVisitor8; - -public abstract class TypeDesc implements Serializable { - - private static final long serialVersionUID = -8201634143915519172L; - - TypeKind typeKind; - - public TypeDesc(TypeKind typeKind) { - this.typeKind = typeKind; - } - - public static TypeDesc decodeString(String s) { - s = s.trim(); - if (s.endsWith("[]")) { - String componentPart = s.substring(0, s.length() - 2); - return new ArrayTypeDesc(decodeString(componentPart)); - } - - if (s.startsWith("#")) return new TypeVarTypeDesc(s.substring(1)); - - if (s.matches("boolean|byte|char|double|float|int|long|short|void")) { - TypeKind tk = TypeKind.valueOf(StringUtils.toUpperCase(s)); - return new PrimitiveTypeDesc(tk); - } - - return new ReferenceTypeDesc(s); - } - - public static String encodeAsString(TypeDesc td) { - if (td.typeKind.isPrimitive() || td.typeKind == TypeKind.VOID) - return StringUtils.toLowerCase(td.typeKind.toString()); - - if (td.typeKind == TypeKind.ARRAY) return encodeAsString(((ArrayTypeDesc) td).compTypeDesc) + "[]"; - - if (td.typeKind == TypeKind.TYPEVAR) return "#" + ((TypeVarTypeDesc) td).identifier; - - if (td.typeKind == TypeKind.DECLARED) return ((ReferenceTypeDesc) td).javaType.toString(); - - throw new AssertionError("Unhandled type: " + td.typeKind); - } - - public static TypeDesc fromType(TypeMirror type) { - TypeVisitor<TypeDesc, Void> v = - new SimpleTypeVisitor8<TypeDesc, Void>() { - @Override - public TypeDesc visitArray(ArrayType t, Void p) { - return new ArrayTypeDesc(t.getComponentType().accept(this, p)); - } - - @Override - public TypeDesc visitDeclared(DeclaredType t, Void p) { - return new ReferenceTypeDesc(((ClassType) t).tsym.flatName().toString()); - } - - @Override - public TypeDesc visitNoType(NoType t, Void p) { - return new PrimitiveTypeDesc(TypeKind.VOID); - } - - @Override - public TypeDesc visitTypeVariable(TypeVariable t, Void p) { - return new TypeVarTypeDesc(t.toString()); - } - - @Override - public TypeDesc visitPrimitive(PrimitiveType t, Void p) { - return new PrimitiveTypeDesc(t.getKind()); - } - - @Override - public TypeDesc visitError(ErrorType t, Void p) { - return new ReferenceTypeDesc("<error type>"); - } - }; - - TypeDesc td = v.visit(type); - if (td == null) throw new AssertionError("Unhandled type mirror: " + type + " (" + type.getClass() + ")"); - return td; - } - - @Override - public boolean equals(Object obj) { - if (getClass() != obj.getClass()) return false; - return typeKind.equals(((TypeDesc) obj).typeKind); - } - - @Override - public int hashCode() { - return typeKind.hashCode(); - } -} diff --git a/src/main/java/org/javacs/pubapi/TypeVarTypeDesc.java b/src/main/java/org/javacs/pubapi/TypeVarTypeDesc.java deleted file mode 100644 index 44cf997..0000000 --- a/src/main/java/org/javacs/pubapi/TypeVarTypeDesc.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.javacs.pubapi; - -import java.io.Serializable; -import javax.lang.model.type.TypeKind; - -public class TypeVarTypeDesc extends TypeDesc implements Serializable { - - private static final long serialVersionUID = 3357616754544796373L; - - String identifier; // Example: "T" - - public TypeVarTypeDesc(String identifier) { - super(TypeKind.TYPEVAR); - this.identifier = identifier; - } - - @Override - public boolean equals(Object obj) { - if (!super.equals(obj)) return false; - return identifier.equals(((TypeVarTypeDesc) obj).identifier); - } - - @Override - public int hashCode() { - return super.hashCode() ^ identifier.hashCode(); - } - - @Override - public String toString() { - return String.format("%s[identifier: %s]", getClass().getSimpleName(), identifier); - } -} diff --git a/src/main/java/org/javacs/pubapi/Util.java b/src/main/java/org/javacs/pubapi/Util.java deleted file mode 100644 index ca166a6..0000000 --- a/src/main/java/org/javacs/pubapi/Util.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.javacs.pubapi; - -import java.io.File; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.function.Function; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * Utilities. - * - * <p><b>This is NOT part of any supported API. If you write code that depends on this, you do so at your own risk. This - * code and its internal interfaces are subject to change or deletion without notice.</b> - */ -public class Util { - - public static String toFileSystemPath(String pkgId) { - if (pkgId == null || pkgId.length() == 0) return null; - String pn; - if (pkgId.charAt(0) == ':') { - // When the module is the default empty module. - // Do not prepend the module directory, because there is none. - // Thus :java.foo.bar translates to java/foo/bar (or \) - pn = pkgId.substring(1).replace('.', File.separatorChar); - } else { - // There is a module. Thus jdk.base:java.foo.bar translates - // into jdk.base/java/foo/bar - int cp = pkgId.indexOf(':'); - String mn = pkgId.substring(0, cp); - pn = mn + File.separatorChar + pkgId.substring(cp + 1).replace('.', File.separatorChar); - } - return pn; - } - - public static String justPackageName(String pkgName) { - int c = pkgName.indexOf(":"); - if (c == -1) throw new IllegalArgumentException("Expected ':' in package name (" + pkgName + ")"); - return pkgName.substring(c + 1); - } - - public static String extractStringOption(String opName, String s) { - return extractStringOption(opName, s, null); - } - - public static String extractStringOption(String opName, String s, String deflt) { - int p = s.indexOf(opName + "="); - if (p == -1) return deflt; - p += opName.length() + 1; - int pe = s.indexOf(',', p); - if (pe == -1) pe = s.length(); - return s.substring(p, pe); - } - - public static boolean extractBooleanOption(String opName, String s, boolean deflt) { - String str = extractStringOption(opName, s); - return "true".equals(str) ? true : "false".equals(str) ? false : deflt; - } - - public static int extractIntOption(String opName, String s) { - return extractIntOption(opName, s, 0); - } - - public static int extractIntOption(String opName, String s, int deflt) { - int p = s.indexOf(opName + "="); - if (p == -1) return deflt; - p += opName.length() + 1; - int pe = s.indexOf(',', p); - if (pe == -1) pe = s.length(); - int v = 0; - try { - v = Integer.parseInt(s.substring(p, pe)); - } catch (Exception e) { - } - return v; - } - - /** - * Extract the package name from a fully qualified class name. - * - * <p>Example: Given "pkg.subpkg.A" this method returns ":pkg.subpkg". Given "C" this method returns ":". - * - * @returns package name of the given class name - */ - public static String pkgNameOfClassName(String fqClassName) { - int i = fqClassName.lastIndexOf('.'); - String pkg = i == -1 ? "" : fqClassName.substring(0, i); - return ":" + pkg; - } - - /** - * Clean out unwanted sub options supplied inside a primary option. For example to only had portfile remaining from: - * settings="--server:id=foo,portfile=bar" do settings = cleanOptions("--server:",Util.set("-portfile"),settings); - * now settings equals "--server:portfile=bar" - * - * @param allowedSubOptions A set of the allowed sub options, id portfile etc. - * @param s The option settings string. - */ - public static String cleanSubOptions(Set<String> allowedSubOptions, String s) { - StringBuilder sb = new StringBuilder(); - StringTokenizer st = new StringTokenizer(s, ","); - while (st.hasMoreTokens()) { - String o = st.nextToken(); - int p = o.indexOf('='); - if (p > 0) { - String key = o.substring(0, p); - String val = o.substring(p + 1); - if (allowedSubOptions.contains(key)) { - if (sb.length() > 0) sb.append(','); - sb.append(key + "=" + val); - } - } - } - return sb.toString(); - } - - /** Convenience method to create a set with strings. */ - public static Set<String> set(String... ss) { - Set<String> set = new HashSet<>(); - set.addAll(Arrays.asList(ss)); - return set; - } - - /** - * Normalize windows drive letter paths to upper case to enable string comparison. - * - * @param file File name to normalize - * @return The normalized string if file has a drive letter at the beginning, otherwise the original string. - */ - public static String normalizeDriveLetter(String file) { - if (file.length() > 2 && file.charAt(1) == ':') { - return Character.toUpperCase(file.charAt(0)) + file.substring(1); - } else if (file.length() > 3 && file.charAt(0) == '*' && file.charAt(2) == ':') { - // Handle a wildcard * at the beginning of the string. - return file.substring(0, 1) + Character.toUpperCase(file.charAt(1)) + file.substring(2); - } - return file; - } - - /** Locate the setting for the server properties. */ - public static String findServerSettings(String[] args) { - for (String s : args) { - if (s.startsWith("--server:")) { - return s; - } - } - return null; - } - - public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2) { - Set<E> union = new HashSet<>(); - union.addAll(s1); - union.addAll(s2); - return union; - } - - public static <E> Set<E> subtract(Set<? extends E> orig, Set<? extends E> toSubtract) { - Set<E> difference = new HashSet<>(orig); - difference.removeAll(toSubtract); - return difference; - } - - public static String getStackTrace(Throwable t) { - StringWriter sw = new StringWriter(); - t.printStackTrace(new PrintWriter(sw)); - return sw.toString(); - } - - // TODO: Remove when refactoring from java.io.File to java.nio.file.Path. - public static File pathToFile(Path path) { - return path == null ? null : path.toFile(); - } - - public static <E> Set<E> intersection(Collection<? extends E> c1, Collection<? extends E> c2) { - Set<E> intersection = new HashSet<E>(c1); - intersection.retainAll(c2); - return intersection; - } - - public static <I, T> Map<I, T> indexBy(Collection<? extends T> c, Function<? super T, ? extends I> indexFunction) { - return c.stream().collect(Collectors.<T, I, T>toMap(indexFunction, o -> o)); - } - - public static String fileSuffix(Path file) { - String fileNameStr = file.getFileName().toString(); - int dotIndex = fileNameStr.indexOf('.'); - return dotIndex == -1 ? "" : fileNameStr.substring(dotIndex); - } - - public static Stream<String> getLines(String str) { - return str.isEmpty() ? Stream.empty() : Stream.of(str.split(Pattern.quote(System.lineSeparator()))); - } -} diff --git a/src/test/java/org/javacs/JavaCompilerServiceTest.java b/src/test/java/org/javacs/JavaCompilerServiceTest.java index 4d8c968..0da2acc 100644 --- a/src/test/java/org/javacs/JavaCompilerServiceTest.java +++ b/src/test/java/org/javacs/JavaCompilerServiceTest.java @@ -69,6 +69,13 @@ public class JavaCompilerServiceTest { } @Test + public void elementWithError() { + Element found = compiler.element(URI.create("/CompleteMembers.java"), contents("/CompleteMembers.java"), 3, 12); + + assertThat(found, notNullValue()); + } + + @Test public void pruneMethods() { Pruner pruner = new Pruner(URI.create("/PruneMethods.java"), contents("/PruneMethods.java")); pruner.prune(6, 19); @@ -228,10 +235,11 @@ public class JavaCompilerServiceTest { assertThat(names, hasItem("concurrent")); } + /* @Test public void gotoDefinition() { Optional<TreePath> def = - compiler.definition(URI.create("/GotoDefinition.java"), contents("/GotoDefinition.java"), 3, 12); + compiler.definition(URI.create("/GotoDefinition.java"), 3, 12, uri -> Files.readAllText(uri)); assertTrue(def.isPresent()); TreePath t = def.get(); @@ -245,6 +253,7 @@ public class JavaCompilerServiceTest { long line = lines.getLineNumber(start); assertThat(line, equalTo(6L)); } + */ @Test public void references() { |