mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Merge branch 'idea-plugin'
This commit is contained in:
commit
87e1ae6fb8
|
@ -4,6 +4,9 @@
|
|||
<root url="jar://$PROJECT_DIR$/tools/idea/jps-plugin/lib/teavm-all.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
<SOURCES>
|
||||
<root url="file://$PROJECT_DIR$/core/src/main/java" />
|
||||
<root url="file://$PROJECT_DIR$/tools/core/src/main/java" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
|
@ -329,11 +329,11 @@ class JSClassProcessor {
|
|||
}
|
||||
|
||||
if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) {
|
||||
MethodReader overriden = getOverridenMethod(method);
|
||||
if (overriden != null) {
|
||||
MethodReader overridden = getOverridenMethod(method);
|
||||
if (overridden != null) {
|
||||
diagnostics.error(callLocation, "JS final method {{m0}} overrides {{m1}}. "
|
||||
+ "Overriding final method of overlay types is prohibited.",
|
||||
method.getReference(), overriden.getReference());
|
||||
method.getReference(), overridden.getReference());
|
||||
}
|
||||
if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) {
|
||||
invoke.setMethod(new MethodReference(method.getOwnerName(), method.getName() + "$static",
|
||||
|
@ -545,7 +545,7 @@ class JSClassProcessor {
|
|||
int jsParamCount = bodyAnnot.getValue("params").getList().size();
|
||||
if (methodToProcess.parameterCount() != jsParamCount) {
|
||||
diagnostics.error(location, "JSBody method {{m0}} declares " + methodToProcess.parameterCount()
|
||||
+ " parameters, but annotation specifies " + jsParamCount, methodToProcess);
|
||||
+ " parameters, but annotation specifies " + jsParamCount, methodToProcess.getReference());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -554,11 +554,8 @@ class JSClassProcessor {
|
|||
if (!isStatic) {
|
||||
++paramCount;
|
||||
}
|
||||
ValueType[] paramTypes = new ValueType[paramCount];
|
||||
int offset = 0;
|
||||
if (!isStatic) {
|
||||
ValueType paramType = ValueType.object(methodToProcess.getOwnerName());
|
||||
paramTypes[offset++] = paramType;
|
||||
if (!typeHelper.isSupportedType(paramType)) {
|
||||
diagnostics.error(location, "Non-static JSBody method {{m0}} is owned by non-JS class {{c1}}",
|
||||
methodToProcess.getReference(), methodToProcess.getOwnerName());
|
||||
|
@ -571,9 +568,6 @@ class JSClassProcessor {
|
|||
}
|
||||
|
||||
// generate parameter types for proxy method
|
||||
for (int i = 0; i < methodToProcess.parameterCount(); ++i) {
|
||||
paramTypes[offset++] = methodToProcess.parameterType(i);
|
||||
}
|
||||
ValueType[] proxyParamTypes = new ValueType[paramCount + 1];
|
||||
for (int i = 0; i < paramCount; ++i) {
|
||||
proxyParamTypes[i] = ValueType.parse(JSObject.class);
|
||||
|
@ -587,7 +581,7 @@ class JSClassProcessor {
|
|||
methodToProcess.getName() + "$js_body$_" + methodIndexGenerator++, proxyParamTypes);
|
||||
String script = bodyAnnot.getValue("script").getString();
|
||||
String[] parameterNames = bodyAnnot.getValue("params").getList().stream()
|
||||
.map(ann -> ann.getString())
|
||||
.map(AnnotationValue::getString)
|
||||
.toArray(String[]::new);
|
||||
|
||||
// Parse JS script
|
||||
|
@ -598,15 +592,13 @@ class JSClassProcessor {
|
|||
env.setLanguageVersion(Context.VERSION_1_8);
|
||||
env.setIdeMode(true);
|
||||
JSParser parser = new JSParser(env, errorReporter);
|
||||
//parser.enterFunction();
|
||||
AstRoot rootNode;
|
||||
try {
|
||||
rootNode = parser.parse(new StringReader("function(){" + script + "}"), null, 0);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("IO Error occured", e);
|
||||
throw new RuntimeException("IO Error occurred", e);
|
||||
}
|
||||
AstNode body = ((FunctionNode) rootNode.getFirstChild()).getBody();
|
||||
//parser.exitFunction();
|
||||
|
||||
repository.methodMap.put(methodToProcess.getReference(), proxyMethod);
|
||||
if (errorReporter.hasErrors()) {
|
||||
|
|
|
@ -0,0 +1,423 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.teavm.idea.jps;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.ModuleBuildTarget;
|
||||
import org.jetbrains.jps.incremental.messages.BuildMessage;
|
||||
import org.jetbrains.jps.incremental.messages.CompilerMessage;
|
||||
import org.jetbrains.jps.incremental.messages.ProgressMessage;
|
||||
import org.jetbrains.jps.model.JpsProject;
|
||||
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
|
||||
import org.jetbrains.jps.model.library.JpsLibrary;
|
||||
import org.jetbrains.jps.model.library.JpsLibraryRoot;
|
||||
import org.jetbrains.jps.model.library.JpsOrderRootType;
|
||||
import org.jetbrains.jps.model.module.JpsDependencyElement;
|
||||
import org.jetbrains.jps.model.module.JpsLibraryDependency;
|
||||
import org.jetbrains.jps.model.module.JpsModule;
|
||||
import org.jetbrains.jps.model.module.JpsModuleDependency;
|
||||
import org.jetbrains.jps.model.module.JpsModuleSourceRoot;
|
||||
import org.teavm.common.IntegerArray;
|
||||
import org.teavm.diagnostics.DefaultProblemTextConsumer;
|
||||
import org.teavm.diagnostics.Problem;
|
||||
import org.teavm.diagnostics.ProblemProvider;
|
||||
import org.teavm.idea.jps.model.TeaVMJpsConfiguration;
|
||||
import org.teavm.idea.jps.remote.TeaVMBuilderAssistant;
|
||||
import org.teavm.idea.jps.remote.TeaVMElementLocation;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.InstructionLocation;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.tooling.EmptyTeaVMToolLog;
|
||||
import org.teavm.tooling.TeaVMTool;
|
||||
import org.teavm.tooling.TeaVMToolException;
|
||||
import org.teavm.tooling.sources.DirectorySourceFileProvider;
|
||||
import org.teavm.tooling.sources.JarSourceFileProvider;
|
||||
import org.teavm.tooling.sources.SourceFileProvider;
|
||||
import org.teavm.vm.TeaVMPhase;
|
||||
import org.teavm.vm.TeaVMProgressFeedback;
|
||||
import org.teavm.vm.TeaVMProgressListener;
|
||||
|
||||
public class TeaVMBuild {
|
||||
private final CompileContext context;
|
||||
private final TeaVMStorageProvider storageProvider = new TeaVMStorageProvider();
|
||||
private final List<String> classPathEntries = new ArrayList<>();
|
||||
private List<String> directoryClassPathEntries;
|
||||
private TeaVMStorage storage;
|
||||
private final TeaVMBuilderAssistant assistant;
|
||||
private final Map<String, File> sourceFileCache = new HashMap<>();
|
||||
private final Map<File, int[]> fileLineCache = new HashMap<>();
|
||||
private final List<SourceFileProvider> sourceFileProviders = new ArrayList<>();
|
||||
|
||||
public TeaVMBuild(CompileContext context, TeaVMBuilderAssistant assistant) {
|
||||
this.context = context;
|
||||
this.assistant = assistant;
|
||||
}
|
||||
|
||||
public boolean perform(JpsModule module, ModuleBuildTarget target) throws IOException {
|
||||
storage = context.getProjectDescriptor().dataManager.getStorage(target, storageProvider);
|
||||
|
||||
TeaVMJpsConfiguration config = TeaVMJpsConfiguration.get(module);
|
||||
if (config == null || !config.isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
classPathEntries.clear();
|
||||
buildClassPath(module, new HashSet<>());
|
||||
directoryClassPathEntries = classPathEntries.stream().filter(name -> new File(name).isDirectory())
|
||||
.collect(toList());
|
||||
|
||||
if (!hasChanges(target)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TeaVMTool tool = new TeaVMTool();
|
||||
tool.setProgressListener(createProgressListener(context));
|
||||
tool.setLog(new EmptyTeaVMToolLog());
|
||||
tool.setMainClass(config.getMainClass());
|
||||
tool.setSourceMapsFileGenerated(config.isSourceMapsFileGenerated());
|
||||
tool.setTargetDirectory(new File(config.getTargetDirectory()));
|
||||
tool.setClassLoader(buildClassLoader());
|
||||
tool.setSourceFilesCopied(config.isSourceFilesCopied());
|
||||
tool.setMinifying(config.isMinifying());
|
||||
for (SourceFileProvider fileProvider : sourceFileProviders) {
|
||||
tool.addSourceFileProvider(fileProvider);
|
||||
}
|
||||
|
||||
boolean errorOccurred = false;
|
||||
try {
|
||||
tool.generate();
|
||||
} catch (TeaVMToolException | RuntimeException | Error e) {
|
||||
e.printStackTrace(System.err);
|
||||
context.processMessage(new CompilerMessage("TeaVM", e));
|
||||
errorOccurred = true;
|
||||
}
|
||||
|
||||
if (!errorOccurred && tool.getProblemProvider().getSevereProblems().isEmpty()) {
|
||||
updateStorage(tool);
|
||||
}
|
||||
|
||||
reportProblems(tool.getProblemProvider());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void reportProblems(ProblemProvider problemProvider) {
|
||||
for (Problem problem : problemProvider.getProblems()) {
|
||||
BuildMessage.Kind kind;
|
||||
switch (problem.getSeverity()) {
|
||||
case ERROR:
|
||||
kind = BuildMessage.Kind.ERROR;
|
||||
break;
|
||||
case WARNING:
|
||||
kind = BuildMessage.Kind.WARNING;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
String path = null;
|
||||
File file = null;
|
||||
int line = -1;
|
||||
long startOffset = -1;
|
||||
long endOffset = -1;
|
||||
|
||||
if (problem.getLocation() != null) {
|
||||
CallLocation callLocation = problem.getLocation();
|
||||
InstructionLocation insnLocation = problem.getLocation().getSourceLocation();
|
||||
if (insnLocation != null) {
|
||||
path = insnLocation.getFileName();
|
||||
line = insnLocation.getLine();
|
||||
}
|
||||
|
||||
if (line <= 0 && assistant != null && callLocation != null && callLocation.getMethod() != null) {
|
||||
MethodReference method = callLocation.getMethod();
|
||||
try {
|
||||
TeaVMElementLocation location = assistant.getMethodLocation(method.getClassName(),
|
||||
method.getName(), ValueType.methodTypeToString(method.getSignature()));
|
||||
line = location.getLine();
|
||||
startOffset = location.getStartOffset();
|
||||
endOffset = location.getEndOffset();
|
||||
file = new File(location.getPath());
|
||||
|
||||
if (line <= 0) {
|
||||
int[] lines = getLineOffsets(file);
|
||||
if (lines != null) {
|
||||
line = Arrays.binarySearch(lines, (int) startOffset + 1);
|
||||
if (line < 0) {
|
||||
line = -line - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// just don't fill location fields
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DefaultProblemTextConsumer textConsumer = new DefaultProblemTextConsumer();
|
||||
problem.render(textConsumer);
|
||||
|
||||
if (file == null) {
|
||||
if (path != null) {
|
||||
file = lookupSource(path);
|
||||
path = file != null ? file.getPath() : null;
|
||||
}
|
||||
} else {
|
||||
path = file.getPath();
|
||||
}
|
||||
|
||||
if (startOffset < 0 && file != null && line > 0) {
|
||||
int[] lines = getLineOffsets(file);
|
||||
if (lines != null && line < lines.length) {
|
||||
startOffset = lines[line - 1];
|
||||
endOffset = lines[line] - 1;
|
||||
}
|
||||
}
|
||||
|
||||
context.processMessage(new CompilerMessage("TeaVM", kind, textConsumer.getText(), path,
|
||||
startOffset, endOffset, startOffset, line, 0));
|
||||
}
|
||||
}
|
||||
|
||||
private File lookupSource(String relativePath) {
|
||||
return sourceFileCache.computeIfAbsent(relativePath, this::lookupSourceCacheMiss);
|
||||
}
|
||||
|
||||
private File lookupSourceCacheMiss(String relativePath) {
|
||||
JpsProject project = context.getProjectDescriptor().getModel().getProject();
|
||||
for (JpsModule module : project.getModules()) {
|
||||
for (JpsModuleSourceRoot sourceRoot : module.getSourceRoots()) {
|
||||
File fullPath = new File(sourceRoot.getFile(), relativePath);
|
||||
if (fullPath.exists()) {
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int[] getLineOffsets(File file) {
|
||||
return fileLineCache.computeIfAbsent(file, this::getLineOffsetsCacheMiss);
|
||||
}
|
||||
|
||||
private int[] getLineOffsetsCacheMiss(File file) {
|
||||
IntegerArray lines = new IntegerArray(50);
|
||||
try (Reader reader = new InputStreamReader(new FileInputStream(file), "UTF-8")) {
|
||||
int offset = 0;
|
||||
lines.add(0);
|
||||
|
||||
boolean expectingLf = false;
|
||||
while (true) {
|
||||
int c = reader.read();
|
||||
if (c == -1) {
|
||||
break;
|
||||
}
|
||||
if (c == '\n') {
|
||||
expectingLf = false;
|
||||
lines.add(offset + 1);
|
||||
} else {
|
||||
if (expectingLf) {
|
||||
expectingLf = false;
|
||||
lines.add(offset);
|
||||
}
|
||||
if (c == '\r') {
|
||||
lines.add(offset + 1);
|
||||
expectingLf = true;
|
||||
}
|
||||
}
|
||||
++offset;
|
||||
}
|
||||
|
||||
if (expectingLf) {
|
||||
lines.add(offset);
|
||||
}
|
||||
lines.add(offset + 1);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
return lines.getAll();
|
||||
}
|
||||
|
||||
private boolean hasChanges(ModuleBuildTarget target) {
|
||||
if (!context.getScope().isBuildIncrementally(target.getTargetType())
|
||||
|| context.getScope().isBuildForced(target)) {
|
||||
return true;
|
||||
}
|
||||
List<TeaVMStorage.Entry> filesToWatch = storage.getParticipatingFiles();
|
||||
if (filesToWatch == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (TeaVMStorage.Entry fileToWatch : filesToWatch) {
|
||||
Long actualTimestamp = getTimestamp(fileToWatch.path);
|
||||
if (actualTimestamp == null || actualTimestamp > fileToWatch.timestamp) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updateStorage(TeaVMTool tool) {
|
||||
Set<String> resources = Stream.concat(tool.getClasses().stream().map(cls -> cls.replace('.', '/') + ".class"),
|
||||
tool.getUsedResources().stream())
|
||||
.sorted()
|
||||
.collect(toSet());
|
||||
List<TeaVMStorage.Entry> participatingFiles = resources.stream()
|
||||
.map(path -> {
|
||||
Long timestamp = getTimestamp(path);
|
||||
return timestamp != null ? new TeaVMStorage.Entry(path, timestamp) : null;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(toList());
|
||||
storage.setParticipatingFiles(participatingFiles);
|
||||
}
|
||||
|
||||
private Long getTimestamp(String path) {
|
||||
for (String classPathEntry : directoryClassPathEntries) {
|
||||
File file = new File(classPathEntry, path);
|
||||
if (file.exists()) {
|
||||
return file.lastModified();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private TeaVMProgressListener createProgressListener(CompileContext context) {
|
||||
return new TeaVMProgressListener() {
|
||||
private TeaVMPhase currentPhase;
|
||||
int expectedCount;
|
||||
|
||||
@Override
|
||||
public TeaVMProgressFeedback phaseStarted(TeaVMPhase phase, int count) {
|
||||
expectedCount = count;
|
||||
context.processMessage(new ProgressMessage(phaseName(phase), 0));
|
||||
currentPhase = phase;
|
||||
return context.getCancelStatus().isCanceled() ? TeaVMProgressFeedback.CANCEL
|
||||
: TeaVMProgressFeedback.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeaVMProgressFeedback progressReached(int progress) {
|
||||
context.processMessage(new ProgressMessage(phaseName(currentPhase), (float) progress / expectedCount));
|
||||
return context.getCancelStatus().isCanceled() ? TeaVMProgressFeedback.CANCEL
|
||||
: TeaVMProgressFeedback.CONTINUE;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static String phaseName(TeaVMPhase phase) {
|
||||
switch (phase) {
|
||||
case DEPENDENCY_CHECKING:
|
||||
return "Discovering classes to compile";
|
||||
case LINKING:
|
||||
return "Resolving method invocations";
|
||||
case DEVIRTUALIZATION:
|
||||
return "Eliminating virtual calls";
|
||||
case DECOMPILATION:
|
||||
return "Compiling classes";
|
||||
case RENDERING:
|
||||
return "Building JS file";
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private ClassLoader buildClassLoader() {
|
||||
URL[] urls = classPathEntries.stream().map(entry -> {
|
||||
try {
|
||||
return new File(entry).toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(entry);
|
||||
}
|
||||
}).toArray(URL[]::new);
|
||||
|
||||
return new URLClassLoader(urls, TeaVMBuilder.class.getClassLoader());
|
||||
}
|
||||
|
||||
private void buildClassPath(JpsModule module, Set<JpsModule> visited) {
|
||||
if (!visited.add(module)) {
|
||||
return;
|
||||
}
|
||||
File output = JpsJavaExtensionService.getInstance().getOutputDirectory(module, false);
|
||||
if (output != null) {
|
||||
classPathEntries.add(output.getPath());
|
||||
}
|
||||
|
||||
sourceFileProviders.addAll(module.getSourceRoots().stream()
|
||||
.map(sourceRoot -> new DirectorySourceFileProvider(sourceRoot.getFile()))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
for (JpsDependencyElement dependency : module.getDependenciesList().getDependencies()) {
|
||||
if (dependency instanceof JpsModuleDependency) {
|
||||
JpsModuleDependency moduleDependency = (JpsModuleDependency) dependency;
|
||||
buildClassPath(moduleDependency.getModule(), visited);
|
||||
} else if (dependency instanceof JpsLibraryDependency) {
|
||||
JpsLibrary library = ((JpsLibraryDependency) dependency).getLibrary();
|
||||
if (library == null) {
|
||||
continue;
|
||||
}
|
||||
classPathEntries.addAll(library.getFiles(JpsOrderRootType.COMPILED).stream().map(File::getPath)
|
||||
.collect(toList()));
|
||||
|
||||
for (JpsLibraryRoot libraryRoot : library.getRoots(JpsOrderRootType.SOURCES)) {
|
||||
File file = getFileFromUrl(libraryRoot.getUrl());
|
||||
if (file != null) {
|
||||
if (file.isDirectory()) {
|
||||
sourceFileProviders.add(new DirectorySourceFileProvider(file));
|
||||
} else {
|
||||
sourceFileProviders.add(new JarSourceFileProvider(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private File getFileFromUrl(String url) {
|
||||
if (url.startsWith("file://")) {
|
||||
return new File(url.substring("file://".length()));
|
||||
} else if (url.startsWith("jar://")) {
|
||||
int index = url.indexOf('!');
|
||||
return new File(url.substring("file://".length(), index));
|
||||
} else if (url.startsWith("jar:file://")) {
|
||||
int index = url.indexOf('!');
|
||||
return new File(url.substring("jar:file://".length(), index));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,14 +15,11 @@
|
|||
*/
|
||||
package org.teavm.idea.jps;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.rmi.NotBoundException;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import java.rmi.registry.Registry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.ModuleChunk;
|
||||
import org.jetbrains.jps.builders.DirtyFilesHolder;
|
||||
|
@ -34,34 +31,41 @@ import org.jetbrains.jps.incremental.ModuleLevelBuilder;
|
|||
import org.jetbrains.jps.incremental.ProjectBuildException;
|
||||
import org.jetbrains.jps.incremental.messages.BuildMessage;
|
||||
import org.jetbrains.jps.incremental.messages.CompilerMessage;
|
||||
import org.jetbrains.jps.incremental.messages.ProgressMessage;
|
||||
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
|
||||
import org.jetbrains.jps.model.library.JpsLibrary;
|
||||
import org.jetbrains.jps.model.library.JpsOrderRootType;
|
||||
import org.jetbrains.jps.model.module.JpsDependencyElement;
|
||||
import org.jetbrains.jps.model.module.JpsLibraryDependency;
|
||||
import org.jetbrains.jps.model.module.JpsModule;
|
||||
import org.jetbrains.jps.model.module.JpsModuleDependency;
|
||||
import org.teavm.idea.jps.model.TeaVMJpsConfiguration;
|
||||
import org.teavm.tooling.TeaVMTool;
|
||||
import org.teavm.tooling.TeaVMToolException;
|
||||
import org.teavm.tooling.TeaVMToolLog;
|
||||
import org.teavm.vm.TeaVMPhase;
|
||||
import org.teavm.vm.TeaVMProgressFeedback;
|
||||
import org.teavm.vm.TeaVMProgressListener;
|
||||
import org.teavm.idea.jps.remote.TeaVMBuilderAssistant;
|
||||
|
||||
public class TeaVMBuilder extends ModuleLevelBuilder {
|
||||
public static final String REMOTE_PORT = "teavm.jps.remote-port";
|
||||
private static TeaVMBuilderAssistant assistant;
|
||||
|
||||
public TeaVMBuilder() {
|
||||
super(BuilderCategory.CLASS_POST_PROCESSOR);
|
||||
|
||||
String portString = System.getProperty(REMOTE_PORT);
|
||||
if (portString != null) {
|
||||
try {
|
||||
Registry registry = LocateRegistry.getRegistry(Integer.parseInt(portString));
|
||||
assistant = (TeaVMBuilderAssistant) registry.lookup(TeaVMBuilderAssistant.ID);
|
||||
} catch (NumberFormatException | RemoteException | NotBoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitCode build(CompileContext context, ModuleChunk chunk,
|
||||
DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder,
|
||||
OutputConsumer outputConsumer) throws ProjectBuildException, IOException {
|
||||
if (assistant == null) {
|
||||
context.processMessage(new CompilerMessage("TeaVM", BuildMessage.Kind.WARNING,
|
||||
"No TeaVM builder assistant available. Diagnostic messages will be less informative"));
|
||||
}
|
||||
|
||||
boolean doneSomething = false;
|
||||
|
||||
TeaVMBuild build = new TeaVMBuild(context, assistant);
|
||||
for (JpsModule module : chunk.getModules()) {
|
||||
doneSomething |= buildModule(module, context);
|
||||
doneSomething |= build.perform(module, chunk.representativeTarget());
|
||||
if (context.getCancelStatus().isCanceled()) {
|
||||
return ExitCode.ABORT;
|
||||
}
|
||||
|
@ -70,155 +74,6 @@ public class TeaVMBuilder extends ModuleLevelBuilder {
|
|||
return doneSomething ? ExitCode.OK : ExitCode.NOTHING_DONE;
|
||||
}
|
||||
|
||||
private boolean buildModule(JpsModule module, CompileContext context) {
|
||||
TeaVMJpsConfiguration config = TeaVMJpsConfiguration.get(module);
|
||||
if (config == null || !config.isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TeaVMTool tool = new TeaVMTool();
|
||||
tool.setProgressListener(createProgressListener(context));
|
||||
tool.setLog(createLog(context));
|
||||
tool.setMainClass(config.getMainClass());
|
||||
tool.setSourceMapsFileGenerated(true);
|
||||
tool.setTargetDirectory(new File(config.getTargetDirectory()));
|
||||
tool.setClassLoader(buildClassLoader(module));
|
||||
tool.setMinifying(false);
|
||||
|
||||
try {
|
||||
tool.generate();
|
||||
} catch (TeaVMToolException | RuntimeException | Error e) {
|
||||
e.printStackTrace(System.err);
|
||||
context.processMessage(new CompilerMessage("TeaVM", e));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private TeaVMToolLog createLog(CompileContext context) {
|
||||
return new TeaVMToolLog() {
|
||||
@Override
|
||||
public void info(String text) {
|
||||
context.processMessage(new CompilerMessage("TeaVM", BuildMessage.Kind.INFO, text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String text) {
|
||||
context.processMessage(new CompilerMessage("TeaVM", BuildMessage.Kind.INFO, text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(String text) {
|
||||
context.processMessage(new CompilerMessage("TeaVM", BuildMessage.Kind.WARNING, text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String text) {
|
||||
context.processMessage(new CompilerMessage("TeaVM", BuildMessage.Kind.ERROR, text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String text, Throwable e) {
|
||||
context.processMessage(new CompilerMessage("TeaVM", BuildMessage.Kind.INFO, text + "\n"
|
||||
+ CompilerMessage.getTextFromThrowable(e)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String text, Throwable e) {
|
||||
context.processMessage(new CompilerMessage("TeaVM", BuildMessage.Kind.INFO, text + "\n"
|
||||
+ CompilerMessage.getTextFromThrowable(e)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(String text, Throwable e) {
|
||||
context.processMessage(new CompilerMessage("TeaVM", BuildMessage.Kind.WARNING, text + "\n"
|
||||
+ CompilerMessage.getTextFromThrowable(e)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String text, Throwable e) {
|
||||
context.processMessage(new CompilerMessage("TeaVM", BuildMessage.Kind.ERROR, text + "\n"
|
||||
+ CompilerMessage.getTextFromThrowable(e)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private TeaVMProgressListener createProgressListener(CompileContext context) {
|
||||
return new TeaVMProgressListener() {
|
||||
private TeaVMPhase currentPhase;
|
||||
int expectedCount;
|
||||
|
||||
@Override
|
||||
public TeaVMProgressFeedback phaseStarted(TeaVMPhase phase, int count) {
|
||||
expectedCount = count;
|
||||
context.processMessage(new ProgressMessage(phaseName(phase), 0));
|
||||
currentPhase = phase;
|
||||
return context.getCancelStatus().isCanceled() ? TeaVMProgressFeedback.CANCEL
|
||||
: TeaVMProgressFeedback.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeaVMProgressFeedback progressReached(int progress) {
|
||||
context.processMessage(new ProgressMessage(phaseName(currentPhase), (float) progress / expectedCount));
|
||||
return context.getCancelStatus().isCanceled() ? TeaVMProgressFeedback.CANCEL
|
||||
: TeaVMProgressFeedback.CONTINUE;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static String phaseName(TeaVMPhase phase) {
|
||||
switch (phase) {
|
||||
case DEPENDENCY_CHECKING:
|
||||
return "Discovering classes to compile";
|
||||
case LINKING:
|
||||
return "Resolving method invocations";
|
||||
case DEVIRTUALIZATION:
|
||||
return "Eliminating virtual calls";
|
||||
case DECOMPILATION:
|
||||
return "Compiling classes";
|
||||
case RENDERING:
|
||||
return "Building JS file";
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private ClassLoader buildClassLoader(JpsModule module) {
|
||||
Set<String> classPathEntries = new HashSet<>();
|
||||
buildClassPath(module, new HashSet<>(), classPathEntries);
|
||||
|
||||
URL[] urls = classPathEntries.stream().map(entry -> {
|
||||
try {
|
||||
return new File(entry).toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(entry);
|
||||
}
|
||||
}).toArray(URL[]::new);
|
||||
|
||||
return new URLClassLoader(urls, TeaVMBuilder.class.getClassLoader());
|
||||
}
|
||||
|
||||
private void buildClassPath(JpsModule module, Set<JpsModule> visited, Set<String> classPathEntries) {
|
||||
if (!visited.add(module)) {
|
||||
return;
|
||||
}
|
||||
File output = JpsJavaExtensionService.getInstance().getOutputDirectory(module, false);
|
||||
if (output != null) {
|
||||
classPathEntries.add(output.getPath());
|
||||
}
|
||||
for (JpsDependencyElement dependency : module.getDependenciesList().getDependencies()) {
|
||||
if (dependency instanceof JpsModuleDependency) {
|
||||
buildClassPath(((JpsModuleDependency) dependency).getModule(), visited, classPathEntries);
|
||||
} else if (dependency instanceof JpsLibraryDependency) {
|
||||
JpsLibrary library = ((JpsLibraryDependency) dependency).getLibrary();
|
||||
if (library == null) {
|
||||
continue;
|
||||
}
|
||||
classPathEntries.addAll(library.getFiles(JpsOrderRootType.COMPILED).stream().map(File::getPath)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.teavm.idea.jps;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.jetbrains.jps.incremental.storage.StorageOwner;
|
||||
|
||||
public class TeaVMStorage implements StorageOwner {
|
||||
private File file;
|
||||
private List<Entry> participatingFiles;
|
||||
private boolean dirty;
|
||||
|
||||
TeaVMStorage(File file) throws IOException {
|
||||
file = new File(file, "teavm.storage");
|
||||
this.file = file;
|
||||
if (file.exists()) {
|
||||
participatingFiles = new ArrayList<>();
|
||||
try (Reader innerReader = new InputStreamReader(new FileInputStream(file), "UTF-8");
|
||||
BufferedReader reader = new BufferedReader(innerReader)) {
|
||||
while (true) {
|
||||
String line = reader.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
line = line.trim();
|
||||
if (line.isEmpty() || line.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int index = line.lastIndexOf(':');
|
||||
if (index < 0) {
|
||||
participatingFiles = null;
|
||||
file.delete();
|
||||
break;
|
||||
}
|
||||
participatingFiles.add(new Entry(line.substring(0, index),
|
||||
Long.parseLong(line.substring(index + 1))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setParticipatingFiles(List<Entry> participatingFiles) {
|
||||
if (participatingFiles == null) {
|
||||
this.participatingFiles = null;
|
||||
} else {
|
||||
this.participatingFiles = new ArrayList<>(participatingFiles);
|
||||
}
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
public List<Entry> getParticipatingFiles() {
|
||||
return participatingFiles != null ? new ArrayList<>(participatingFiles) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush(boolean b) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clean() throws IOException {
|
||||
file.delete();
|
||||
participatingFiles = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (dirty) {
|
||||
if (participatingFiles == null) {
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
} else {
|
||||
try (Writer innerWriter = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
|
||||
BufferedWriter writer = new BufferedWriter(innerWriter)) {
|
||||
for (Entry participatingFile : participatingFiles) {
|
||||
writer.append(participatingFile.path + ":" + participatingFile.timestamp);
|
||||
writer.newLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean causesBuild(String file) {
|
||||
return participatingFiles == null || participatingFiles.contains(file);
|
||||
}
|
||||
|
||||
public static class Entry {
|
||||
public final String path;
|
||||
public final long timestamp;
|
||||
|
||||
public Entry(String path, long timestamp) {
|
||||
this.path = path;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.teavm.idea.jps;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.builders.storage.StorageProvider;
|
||||
|
||||
public class TeaVMStorageProvider extends StorageProvider<TeaVMStorage> {
|
||||
@NotNull
|
||||
@Override
|
||||
public TeaVMStorage createStorage(File file) throws IOException {
|
||||
return new TeaVMStorage(file);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.teavm.idea.jps.remote;
|
||||
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
public interface TeaVMBuilderAssistant extends Remote {
|
||||
String ID = "TeaVM-JPS-Assistant";
|
||||
|
||||
TeaVMElementLocation getMethodLocation(String className, String methodName, String methodDesc)
|
||||
throws RemoteException;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.teavm.idea.jps.remote;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class TeaVMElementLocation implements Serializable {
|
||||
private int startOffset;
|
||||
private int endOffset;
|
||||
private int line;
|
||||
private int column;
|
||||
private String path;
|
||||
|
||||
public TeaVMElementLocation(int startOffset, int endOffset, int line, int column, String path) {
|
||||
this.startOffset = startOffset;
|
||||
this.endOffset = endOffset;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public int getStartOffset() {
|
||||
return startOffset;
|
||||
}
|
||||
|
||||
public int getEndOffset() {
|
||||
return endOffset;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public int getColumn() {
|
||||
return column;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ import com.intellij.openapi.components.Storage;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
import org.teavm.idea.jps.model.TeaVMJpsConfiguration;
|
||||
|
||||
@State(name = "teavm", storages = @Storage(id = "other", file = "$MODULE_FILE$"))
|
||||
@State(name = "teavm", storages = @Storage(id = "other", file = "$MODULE_FILE$"))
|
||||
public class TeaVMConfigurationStorage implements PersistentStateComponent<TeaVMJpsConfiguration> {
|
||||
private TeaVMJpsConfiguration state = new TeaVMJpsConfiguration();
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.teavm.idea;
|
||||
|
||||
import com.intellij.compiler.server.BuildProcessParametersProvider;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.teavm.idea.jps.TeaVMBuilder;
|
||||
|
||||
public class TeaVMJPSConfigurator extends BuildProcessParametersProvider {
|
||||
private TeaVMJPSRemoteService remoteService;
|
||||
|
||||
public TeaVMJPSConfigurator(TeaVMJPSRemoteService remoteService) {
|
||||
this.remoteService = remoteService;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getVMArguments() {
|
||||
return Collections.singletonList("-D" + TeaVMBuilder.REMOTE_PORT + "=" + remoteService.getPort());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.teavm.idea;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.ApplicationComponent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiParameter;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.siyeh.ig.fixes.MemberSignature;
|
||||
import java.rmi.AlreadyBoundException;
|
||||
import java.rmi.NotBoundException;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.rmi.server.UnicastRemoteObject;
|
||||
import java.util.Random;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.teavm.idea.jps.remote.TeaVMBuilderAssistant;
|
||||
import org.teavm.idea.jps.remote.TeaVMElementLocation;
|
||||
|
||||
public class TeaVMJPSRemoteService extends UnicastRemoteObject implements ApplicationComponent, TeaVMBuilderAssistant {
|
||||
private static final int MIN_PORT = 10000;
|
||||
private static final int MAX_PORT = 1 << 16;
|
||||
private final ProjectManager projectManager = ProjectManager.getInstance();
|
||||
private int port;
|
||||
private Registry registry;
|
||||
|
||||
public TeaVMJPSRemoteService() throws RemoteException {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initComponent() {
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
port = random.nextInt(MAX_PORT - MIN_PORT) + MIN_PORT;
|
||||
try {
|
||||
registry = LocateRegistry.createRegistry(port);
|
||||
} catch (RemoteException e) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
registry.bind(TeaVMBuilderAssistant.ID, this);
|
||||
} catch (RemoteException | AlreadyBoundException e) {
|
||||
throw new IllegalStateException("Could not bind remote build assistant service", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("Could not create RMI registry");
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeComponent() {
|
||||
try {
|
||||
registry.unbind(TeaVMBuilderAssistant.ID);
|
||||
UnicastRemoteObject.unexportObject(registry, true);
|
||||
} catch (RemoteException | NotBoundException e) {
|
||||
throw new IllegalStateException("Could not clean-up RMI server", e);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getComponentName() {
|
||||
return "TeaVM JPS service";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeaVMElementLocation getMethodLocation(String className, String methodName, String methodDesc)
|
||||
throws RemoteException {
|
||||
TeaVMElementLocation[] resultHolder = new TeaVMElementLocation[1];
|
||||
|
||||
ApplicationManager.getApplication().runReadAction(() -> {
|
||||
for (Project project : projectManager.getOpenProjects()) {
|
||||
JavaPsiFacade psi = JavaPsiFacade.getInstance(project);
|
||||
PsiClass cls = psi.findClass(className, GlobalSearchScope.allScope(project));
|
||||
if (cls == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (PsiMethod method : cls.getAllMethods()) {
|
||||
if (!method.getName().equals(methodName) || !getMethodSignature(method).equals(methodDesc)) {
|
||||
continue;
|
||||
}
|
||||
resultHolder[0] = getMethodLocation(method);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return resultHolder[0];
|
||||
}
|
||||
|
||||
private String getMethodSignature(PsiMethod method) {
|
||||
StringBuilder sb = new StringBuilder("(");
|
||||
for (PsiParameter parameter : method.getParameterList().getParameters()) {
|
||||
sb.append(MemberSignature.createTypeSignature(parameter.getType()));
|
||||
}
|
||||
sb.append(")");
|
||||
|
||||
PsiType returnType = method.getReturnType();
|
||||
sb.append(MemberSignature.createTypeSignature(returnType != null ? returnType : PsiType.VOID));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private TeaVMElementLocation getMethodLocation(PsiMethod method) {
|
||||
return new TeaVMElementLocation(method.getTextOffset(), method.getTextOffset() + method.getTextLength(),
|
||||
-1, -1, method.getContainingFile().getVirtualFile().getPath());
|
||||
}
|
||||
}
|
|
@ -17,10 +17,17 @@
|
|||
|
||||
<idea-version since-build="141.0"/>
|
||||
|
||||
<application-components>
|
||||
<component>
|
||||
<implementation-class>org.teavm.idea.TeaVMJPSRemoteService</implementation-class>
|
||||
</component>
|
||||
</application-components>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<moduleConfigurable instance="org.teavm.idea.ui.TeaVMConfigurable"/>
|
||||
<moduleService serviceInterface="org.teavm.idea.TeaVMConfigurationStorage"
|
||||
serviceImplementation="org.teavm.idea.TeaVMConfigurationStorage"/>
|
||||
<compileServer.plugin classpath="jps/teavm-jps-plugin.jar;teavm-all.jar"/>
|
||||
<buildProcess.parametersProvider implementation="org.teavm.idea.TeaVMJPSConfigurator"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
Loading…
Reference in New Issue
Block a user