Refactor cli: all the jvm stuff goes under org.jetbrains.jet.cli.jvm, common stuff under org.jetbrains.jet.cli.common

This commit is contained in:
pTalanov
2012-04-25 20:19:15 +04:00
parent b1b9446f13
commit d0d5b147f2
67 changed files with 113 additions and 4056 deletions
+1 -1
View File
@@ -95,4 +95,4 @@ CPSELECT="-cp "
$JAVA_OPTS \
"${java_args[@]}" \
${CPSELECT}${TOOL_CLASSPATH} \
org.jetbrains.jet.cli.KotlinCompiler "$@"
org.jetbrains.jet.cli.jvm.K2JVMCompiler "$@"
+1 -1
View File
@@ -27,7 +27,7 @@ if "%_TOOL_CLASSPATH%"=="" (
for /d %%f in ("%_KOTLIN_HOME%\lib\*") do call :add_cpath "%%f"
)
"%_JAVACMD%" %_JAVA_OPTS% -cp "%_TOOL_CLASSPATH%" org.jetbrains.jet.cli.KotlinCompiler %*
"%_JAVACMD%" %_JAVA_OPTS% -cp "%_TOOL_CLASSPATH%" org.jetbrains.jet.cli.jvm.K2JVMCompiler %*
goto end
rem ##########################################################################
@@ -1,165 +0,0 @@
/**
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.jetbrains.jet.cli;
import com.sampullara.cli.Argument;
import org.jetbrains.jet.compiler.CompilerPlugin;
import java.util.ArrayList;
import java.util.List;
/**
* Command line arguments for the {@link KotlinCompiler}
*/
public class CompilerArguments {
private List<CompilerPlugin> compilerPlugins = new ArrayList<CompilerPlugin>();
// TODO ideally we'd unify this with 'src' to just having a single field that supports multiple files/dirs
private List<String> sourceDirs;
public List<String> getSourceDirs() {
return sourceDirs;
}
public void setSourceDirs(List<String> sourceDirs) {
this.sourceDirs = sourceDirs;
}
@Argument(value = "output", description = "output directory")
public String outputDir;
@Argument(value = "jar", description = "jar file name")
public String jar;
@Argument(value = "src", description = "source file or directory")
public String src;
@Argument(value = "module", description = "module to compile")
public String module;
@Argument(value = "classpath", description = "classpath to use when compiling")
public String classpath;
@Argument(value = "includeRuntime", description = "include Kotlin runtime in to resulting jar")
public boolean includeRuntime;
@Argument(value = "stdlib", description = "Path to the stdlib.jar")
public String stdlib;
@Argument(value = "jdkHeaders", description = "Path to the kotlin-jdk-headers.jar")
public String jdkHeaders;
@Argument(value = "help", alias = "h", description = "show help")
public boolean help;
@Argument(value = "mode", description = "Special compiler modes: stubs or jdkHeaders")
public String mode;
@Argument(value = "tags", description = "Demarcate each compilation message (error, warning, etc) with an open and close tag")
public boolean tags;
@Argument(value = "verbose", description = "Enable verbose logging output")
public boolean verbose;
@Argument(value = "version", description = "Display compiler version")
public boolean version;
public String getClasspath() {
return classpath;
}
public void setClasspath(String classpath) {
this.classpath = classpath;
}
public boolean isHelp() {
return help;
}
public void setHelp(boolean help) {
this.help = help;
}
public boolean isIncludeRuntime() {
return includeRuntime;
}
public void setIncludeRuntime(boolean includeRuntime) {
this.includeRuntime = includeRuntime;
}
public String getJar() {
return jar;
}
public void setJar(String jar) {
this.jar = jar;
}
public String getModule() {
return module;
}
public void setModule(String module) {
this.module = module;
}
public String getOutputDir() {
return outputDir;
}
public void setOutputDir(String outputDir) {
this.outputDir = outputDir;
}
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
public String getStdlib() {
return stdlib;
}
public void setStdlib(String stdlib) {
this.stdlib = stdlib;
}
public boolean isTags() {
return tags;
}
public void setTags(boolean tags) {
this.tags = tags;
}
public List<CompilerPlugin> getCompilerPlugins() {
return compilerPlugins;
}
/**
* Sets the compiler plugins to be used when working with the {@link KotlinCompiler}
*/
public void setCompilerPlugins(List<CompilerPlugin> compilerPlugins) {
this.compilerPlugins = compilerPlugins;
}
}
@@ -1,26 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.cli;
/**
* @author abreslav
*/
public class CompilerVersion {
// The value of this constant is generated by the build script
// DON'T MODIFY IT
public static final String VERSION = "@snapshot@";
}
@@ -1,313 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.cli;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.sampullara.cli.Args;
import jet.modules.Module;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.codegen.CompilationException;
import org.jetbrains.jet.compiler.*;
import org.jetbrains.jet.compiler.messages.*;
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode;
import org.jetbrains.jet.utils.PathUtil;
import java.io.File;
import java.io.PrintStream;
import java.util.Collection;
import java.util.List;
import static org.jetbrains.jet.cli.KotlinCompiler.ExitCode.*;
/**
* @author yole
* @author alex.tkachman
*/
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public class KotlinCompiler {
public enum ExitCode {
OK(0),
COMPILATION_ERROR(1),
INTERNAL_ERROR(2);
private final int code;
private ExitCode(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
public static void main(String... args) {
doMain(new KotlinCompiler(), args);
}
/**
* Useful main for derived command line tools
*/
public static void doMain(KotlinCompiler compiler, String[] args) {
try {
ExitCode rc = compiler.exec(System.out, args);
if (rc != OK) {
System.err.println("exec() finished with " + rc + " return code");
System.exit(rc.getCode());
}
}
catch (CompileEnvironmentException e) {
System.err.println(e.getMessage());
System.exit(INTERNAL_ERROR.getCode());
}
}
public ExitCode exec(PrintStream errStream, String... args) {
CompilerArguments arguments = createArguments();
if (!parseArguments(errStream, arguments, args)) {
return INTERNAL_ERROR;
}
return exec(errStream, arguments);
}
/**
* Executes the compiler on the parsed arguments
*/
public ExitCode exec(final PrintStream errStream, CompilerArguments arguments) {
if (arguments.help) {
usage(errStream);
return OK;
}
System.setProperty("java.awt.headless", "true");
final MessageRenderer messageRenderer = arguments.tags ? MessageRenderer.TAGS : MessageRenderer.PLAIN;
errStream.print(messageRenderer.renderPreamble());
try {
if (arguments.version) {
errStream.println(messageRenderer.render(CompilerMessageSeverity.INFO, "Kotlin Compiler version " + CompilerVersion.VERSION, CompilerMessageLocation.NO_LOCATION));
}
CompilerSpecialMode mode = parseCompilerSpecialMode(arguments);
File jdkHeadersJar;
if (mode.includeJdkHeaders()) {
if (arguments.jdkHeaders != null) {
jdkHeadersJar = new File(arguments.jdkHeaders);
}
else {
jdkHeadersJar = PathUtil.getAltHeadersPath();
}
}
else {
jdkHeadersJar = null;
}
File runtimeJar;
if (mode.includeKotlinRuntime()) {
if (arguments.stdlib != null) {
runtimeJar = new File(arguments.stdlib);
}
else {
runtimeJar = PathUtil.getDefaultRuntimePath();
}
}
else {
runtimeJar = null;
}
CompilerDependencies dependencies = new CompilerDependencies(mode, CompilerDependencies.findRtJar(), jdkHeadersJar, runtimeJar);
PrintingMessageCollector messageCollector = new PrintingMessageCollector(errStream, messageRenderer, arguments.verbose);
Disposable rootDisposable = CompileEnvironmentUtil.createMockDisposable();
JetCoreEnvironment environment = new JetCoreEnvironment(rootDisposable, dependencies);
CompileEnvironmentConfiguration configuration = new CompileEnvironmentConfiguration(environment, dependencies, messageCollector);
messageCollector.report(CompilerMessageSeverity.LOGGING, "Configuring the compilation environment",
CompilerMessageLocation.NO_LOCATION);
try {
configureEnvironment(configuration, arguments);
boolean noErrors;
if (arguments.module != null) {
List<Module> modules = CompileEnvironmentUtil.loadModuleScript(arguments.module, new PrintingMessageCollector(errStream, messageRenderer, false));
File directory = new File(arguments.module).getParentFile();
noErrors = KotlinToJVMBytecodeCompiler.compileModules(configuration, modules,
directory, arguments.jar, arguments.outputDir,
arguments.includeRuntime);
}
else {
// TODO ideally we'd unify to just having a single field that supports multiple files/dirs
if (arguments.getSourceDirs() != null) {
noErrors = KotlinToJVMBytecodeCompiler.compileBunchOfSourceDirectories(configuration,
arguments.getSourceDirs(), arguments.jar, arguments.outputDir, arguments.includeRuntime);
}
else {
noErrors = KotlinToJVMBytecodeCompiler.compileBunchOfSources(configuration,
arguments.src, arguments.jar, arguments.outputDir, arguments.includeRuntime);
}
}
return noErrors ? OK : COMPILATION_ERROR;
}
catch (CompilationException e) {
messageCollector.report(CompilerMessageSeverity.EXCEPTION, MessageRenderer.PLAIN.renderException(e),
MessageUtil.psiElementToMessageLocation(e.getElement()));
return INTERNAL_ERROR;
}
catch (Throwable t) {
messageCollector.report(CompilerMessageSeverity.EXCEPTION, MessageRenderer.PLAIN.renderException(t), CompilerMessageLocation.NO_LOCATION);
return INTERNAL_ERROR;
}
finally {
Disposer.dispose(rootDisposable);
messageCollector.printToErrStream();
}
}
finally {
errStream.print(messageRenderer.renderConclusion());
}
}
@NotNull
private CompilerSpecialMode parseCompilerSpecialMode(@NotNull CompilerArguments arguments) {
if (arguments.mode == null) {
return CompilerSpecialMode.REGULAR;
}
else {
for (CompilerSpecialMode variant : CompilerSpecialMode.values()) {
if (arguments.mode.equalsIgnoreCase(variant.name().replaceAll("_", ""))) {
return variant;
}
}
}
// TODO: report properly
throw new IllegalArgumentException("unknown compiler mode: " + arguments.mode);
}
/**
* Returns true if the arguments can be parsed correctly
*/
protected boolean parseArguments(PrintStream errStream, CompilerArguments arguments, String[] args) {
try {
Args.parse(arguments, args);
return true;
}
catch (IllegalArgumentException e) {
usage(errStream);
}
catch (Throwable t) {
// Always use tags
errStream.println(MessageRenderer.TAGS.renderException(t));
}
return false;
}
protected void usage(PrintStream target) {
// We should say something like
// Args.usage(target, CompilerArguments.class);
// but currently cli-parser we are using does not support that
// a corresponding patch has been sent to the authors
// For now, we are using this:
PrintStream oldErr = System.err;
System.setErr(target);
try {
// TODO: use proper argv0
Args.usage(new CompilerArguments());
} finally {
System.setErr(oldErr);
}
}
/**
* Allow derived classes to add additional command line arguments
*/
protected CompilerArguments createArguments() {
return new CompilerArguments();
}
/**
* Strategy method to configure the environment, allowing compiler
* based tools to customise their own plugins
*/
protected void configureEnvironment(CompileEnvironmentConfiguration configuration, CompilerArguments arguments) {
// install any compiler plugins
List<CompilerPlugin> plugins = arguments.getCompilerPlugins();
if (plugins != null) {
configuration.getCompilerPlugins().addAll(plugins);
}
if (configuration.getCompilerDependencies().getRuntimeJar() != null) {
CompileEnvironmentUtil.addToClasspath(configuration.getEnvironment(), configuration.getCompilerDependencies().getRuntimeJar());
}
if (arguments.classpath != null) {
final Iterable<String> classpath = Splitter.on(File.pathSeparatorChar).split(arguments.classpath);
CompileEnvironmentUtil.addToClasspath(configuration.getEnvironment(), Iterables.toArray(classpath, String.class));
}
}
private static class PrintingMessageCollector implements MessageCollector {
private final boolean verbose;
private final PrintStream errStream;
private final MessageRenderer messageRenderer;
// File path (nullable) -> error message
private final Multimap<String, String> groupedMessages = LinkedHashMultimap.create();
public PrintingMessageCollector(PrintStream errStream,
MessageRenderer messageRenderer,
boolean verbose) {
this.verbose = verbose;
this.errStream = errStream;
this.messageRenderer = messageRenderer;
}
@Override
public void report(@NotNull CompilerMessageSeverity severity,
@NotNull String message,
@NotNull CompilerMessageLocation location) {
String text = messageRenderer.render(severity, message, location);
if (severity == CompilerMessageSeverity.LOGGING) {
if (!verbose) {
return;
}
errStream.println(text);
}
groupedMessages.put(location.getPath(), text);
}
public void printToErrStream() {
if (!groupedMessages.isEmpty()) {
for (String path : groupedMessages.keySet()) {
Collection<String> messageTexts = groupedMessages.get(path);
for (String text : messageTexts) {
errStream.println(text);
}
}
}
}
}
}
@@ -1,60 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.
*/
/*
* @author max
*/
package org.jetbrains.jet.compiler;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.Function;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.JetFilesProvider;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class CliJetFilesProvider extends JetFilesProvider {
private final JetCoreEnvironment environment;
private Function<JetFile,Collection<JetFile>> all_files = new Function<JetFile, Collection<JetFile>>() {
@Override
public Collection<JetFile> fun(JetFile file) {
return environment.getSourceFiles();
}
};
public CliJetFilesProvider(JetCoreEnvironment environment) {
this.environment = environment;
}
@Override
public Function<JetFile, Collection<JetFile>> sampleToAllFilesInModule() {
return all_files;
}
@Override
public List<JetFile> allInScope(GlobalSearchScope scope) {
List<JetFile> answer = new ArrayList<JetFile>();
for (JetFile file : environment.getSourceFiles()) {
if (scope.contains(file.getVirtualFile())) {
answer.add(file);
}
}
return answer;
}
}
@@ -1,65 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.Disposer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.compiler.messages.MessageCollector;
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
import java.util.List;
/**
* @author abreslav
*/
public class CompileEnvironmentConfiguration {
private final JetCoreEnvironment environment;
private final CompilerDependencies compilerDependencies;
private final MessageCollector messageCollector;
private List<CompilerPlugin> compilerPlugins = Lists.newArrayList();
/**
* NOTE: It's very important to call dispose for every object of this class or there will be memory leaks.
* @see Disposer
*/
public CompileEnvironmentConfiguration(@NotNull JetCoreEnvironment environment,
@NotNull CompilerDependencies compilerDependencies, @NotNull MessageCollector messageCollector) {
this.messageCollector = messageCollector;
this.compilerDependencies = compilerDependencies;
this.environment = environment;
}
public JetCoreEnvironment getEnvironment() {
return environment;
}
@NotNull
public CompilerDependencies getCompilerDependencies() {
return compilerDependencies;
}
@NotNull
public MessageCollector getMessageCollector() {
return messageCollector;
}
public List<CompilerPlugin> getCompilerPlugins() {
return compilerPlugins;
}
}
@@ -1,34 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler;
/**
* @author yole
*/
public class CompileEnvironmentException extends RuntimeException {
public CompileEnvironmentException(String message) {
super(message);
}
public CompileEnvironmentException(Throwable cause) {
super(cause);
}
public CompileEnvironmentException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -1,294 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.Processor;
import jet.modules.AllModules;
import jet.modules.Module;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.GeneratedClassLoader;
import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.compiler.messages.MessageCollector;
import org.jetbrains.jet.lang.resolve.FqName;
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.utils.PathUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.*;
/**
* @author abreslav
*/
public class CompileEnvironmentUtil {
public static Disposable createMockDisposable() {
return new Disposable() {
@Override
public void dispose() {
}
};
}
@Nullable
public static File getUnpackedRuntimePath() {
URL url = CompileEnvironmentConfiguration.class.getClassLoader().getResource("jet/JetObject.class");
if (url != null && url.getProtocol().equals("file")) {
return new File(url.getPath()).getParentFile().getParentFile();
}
return null;
}
@Nullable
public static File getRuntimeJarPath() {
URL url = CompileEnvironmentConfiguration.class.getClassLoader().getResource("jet/JetObject.class");
if (url != null && url.getProtocol().equals("jar")) {
String path = url.getPath();
return new File(path.substring(path.indexOf(":") + 1, path.indexOf("!/")));
}
return null;
}
public static void ensureKotlinRuntime(JetCoreEnvironment env) {
if (JavaPsiFacade.getInstance(env.getProject()).findClass("jet.JetObject", GlobalSearchScope.allScope(env.getProject())) == null) {
// TODO: prepend
File kotlin = PathUtil.getDefaultRuntimePath();
if (kotlin == null || !kotlin.exists()) {
kotlin = getUnpackedRuntimePath();
if (kotlin == null) kotlin = getRuntimeJarPath();
}
if (kotlin == null) {
throw new IllegalStateException("kotlin runtime not found");
}
env.addToClasspath(kotlin);
}
}
public static void ensureRuntime(JetCoreEnvironment environment, CompilerDependencies compilerDependencies) {
if (compilerDependencies.getCompilerSpecialMode() == CompilerSpecialMode.REGULAR) {
ensureKotlinRuntime(environment);
}
else if (compilerDependencies.getCompilerSpecialMode() == CompilerSpecialMode.JDK_HEADERS) {
}
else if (compilerDependencies.getCompilerSpecialMode() == CompilerSpecialMode.STDLIB) {
}
else if (compilerDependencies.getCompilerSpecialMode() == CompilerSpecialMode.BUILTINS) {
// nop
}
else {
throw new IllegalStateException("unknown mode: " + compilerDependencies.getCompilerSpecialMode());
}
}
public static List<Module> loadModuleScript(String moduleScriptFile, MessageCollector messageCollector) {
Disposable disposable = new Disposable() {
@Override
public void dispose() {
}
};
CompilerDependencies dependencies = CompilerDependencies.compilerDependenciesForProduction(CompilerSpecialMode.REGULAR);
JetCoreEnvironment scriptEnvironment = new JetCoreEnvironment(disposable, dependencies);
ensureRuntime(scriptEnvironment, dependencies);
scriptEnvironment.addSources(moduleScriptFile);
GenerationState generationState = KotlinToJVMBytecodeCompiler
.analyzeAndGenerate(new CompileEnvironmentConfiguration(scriptEnvironment, dependencies, messageCollector), false);
if (generationState == null) {
return null;
}
List<Module> modules = runDefineModules(dependencies, moduleScriptFile, generationState.getFactory());
Disposer.dispose(disposable);
if (modules == null) {
throw new CompileEnvironmentException("Module script " + moduleScriptFile + " compilation failed");
}
if (modules.isEmpty()) {
throw new CompileEnvironmentException("No modules where defined by " + moduleScriptFile);
}
return modules;
}
private static List<Module> runDefineModules(CompilerDependencies compilerDependencies, String moduleFile, ClassFileFactory factory) {
File stdlibJar = compilerDependencies.getRuntimeJar();
GeneratedClassLoader loader;
if (stdlibJar != null) {
try {
loader = new GeneratedClassLoader(factory, new URLClassLoader(new URL[]{stdlibJar.toURI().toURL()}, AllModules.class.getClassLoader()));
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
else {
loader = new GeneratedClassLoader(factory, CompileEnvironmentConfiguration.class.getClassLoader());
}
try {
Class namespaceClass = loader.loadClass(JvmAbi.PACKAGE_CLASS);
final Method method = namespaceClass.getDeclaredMethod("project");
if (method == null) {
throw new CompileEnvironmentException("Module script " + moduleFile + " must define project() function");
}
method.setAccessible(true);
method.invoke(null);
ArrayList<Module> answer = new ArrayList<Module>(AllModules.modules.get());
AllModules.modules.get().clear();
return answer;
}
catch (Exception e) {
throw new ModuleExecutionException(e);
}
finally {
loader.dispose();
}
}
public static void writeToJar(ClassFileFactory factory, final OutputStream fos, @Nullable FqName mainClass, boolean includeRuntime) {
try {
Manifest manifest = new Manifest();
final Attributes mainAttributes = manifest.getMainAttributes();
mainAttributes.putValue("Manifest-Version", "1.0");
mainAttributes.putValue("Created-By", "JetBrains Kotlin");
if (mainClass != null) {
mainAttributes.putValue("Main-Class", mainClass.getFqName());
}
JarOutputStream stream = new JarOutputStream(fos, manifest);
try {
for (String file : factory.files()) {
stream.putNextEntry(new JarEntry(file));
stream.write(factory.asBytes(file));
}
if (includeRuntime) {
writeRuntimeToJar(stream);
}
}
finally {
stream.close();
fos.close();
}
} catch (IOException e) {
throw new CompileEnvironmentException("Failed to generate jar file", e);
}
}
private static void writeRuntimeToJar(final JarOutputStream stream) throws IOException {
final File unpackedRuntimePath = getUnpackedRuntimePath();
if (unpackedRuntimePath != null) {
FileUtil.processFilesRecursively(unpackedRuntimePath, new Processor<File>() {
@Override
public boolean process(File file) {
if (file.isDirectory()) return true;
final String relativePath = FileUtil.getRelativePath(unpackedRuntimePath, file);
try {
stream.putNextEntry(new JarEntry(FileUtil.toSystemIndependentName(relativePath)));
FileInputStream fis = new FileInputStream(file);
try {
FileUtil.copy(fis, stream);
}
finally {
fis.close();
}
}
catch (IOException e) {
throw new RuntimeException(e);
}
return true;
}
});
}
else {
File runtimeJarPath = getRuntimeJarPath();
if (runtimeJarPath != null) {
JarInputStream jis = new JarInputStream(new FileInputStream(runtimeJarPath));
try {
while (true) {
JarEntry e = jis.getNextJarEntry();
if (e == null) {
break;
}
if (FileUtil.getExtension(e.getName()).equals("class")) {
stream.putNextEntry(e);
FileUtil.copy(jis, stream);
}
}
} finally {
jis.close();
}
}
else {
throw new CompileEnvironmentException("Couldn't find runtime library");
}
}
}
public static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) {
List<String> files = factory.files();
for (String file : files) {
File target = new File(outputDir, file);
try {
FileUtil.writeToFile(target, factory.asBytes(file));
} catch (IOException e) {
throw new CompileEnvironmentException(e);
}
}
}
/**
* Add path specified to the compilation environment.
* @param environment compilation environment to add to
* @param paths paths to add
*/
public static void addToClasspath(JetCoreEnvironment environment, File ... paths) {
for (File path : paths) {
if (!path.exists()) {
throw new CompileEnvironmentException("'" + path + "' does not exist");
}
environment.addToClasspath(path);
}
}
/**
* Add path specified to the compilation environment.
* @param environment compilation environment to add to
* @param paths paths to add
*/
public static void addToClasspath(JetCoreEnvironment environment, String ... paths) {
for (String path : paths) {
addToClasspath(environment, new File(path));
}
}
}
@@ -1,25 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler;
/**
* A simple interface for compiler plugins to run after the compiler has finished such as for things like
* generating documentation or code generation etc
*/
public interface CompilerPlugin {
void processFiles(CompilerPluginContext context);
}
@@ -1,51 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler;
import com.intellij.openapi.project.Project;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import java.util.List;
/**
* Represents the context of available state in which a {@link CompilerPlugin} runs such as
* the {@link Project}, the {@link BindingContext} and the underlying {@link JetFile} files.
*/
public class CompilerPluginContext {
private final Project project;
private final BindingContext context;
private final List<JetFile> files;
public CompilerPluginContext(Project project, BindingContext context, List<JetFile> files) {
this.project = project;
this.context = context;
this.files = files;
}
public BindingContext getContext() {
return context;
}
public List<JetFile> getFiles() {
return files;
}
public Project getProject() {
return project;
}
}
@@ -1,155 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler;
import com.intellij.core.JavaCoreEnvironment;
import com.intellij.lang.java.JavaParserDefinition;
import com.intellij.mock.MockApplication;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElementFinder;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.asJava.JavaElementFinder;
import org.jetbrains.jet.lang.parsing.JetParserDefinition;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode;
import org.jetbrains.jet.lang.resolve.java.JetFilesProvider;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.jet.plugin.JetFileType;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
/**
* @author yole
*/
public class JetCoreEnvironment extends JavaCoreEnvironment {
private final List<JetFile> sourceFiles = new ArrayList<JetFile>();
public JetCoreEnvironment(Disposable parentDisposable, @NotNull CompilerDependencies compilerDependencies) {
super(parentDisposable);
registerFileType(JetFileType.INSTANCE, "kt");
registerFileType(JetFileType.INSTANCE, "kts");
registerFileType(JetFileType.INSTANCE, "ktm");
registerFileType(JetFileType.INSTANCE, "jet");
registerParserDefinition(new JavaParserDefinition());
registerParserDefinition(new JetParserDefinition());
myProject.registerService(JetFilesProvider.class, new CliJetFilesProvider(this));
Extensions.getArea(myProject)
.getExtensionPoint(PsiElementFinder.EP_NAME)
.registerExtension(new JavaElementFinder(myProject));
CompilerSpecialMode compilerSpecialMode = compilerDependencies.getCompilerSpecialMode();
addToClasspath(compilerDependencies.getJdkJar());
if (compilerSpecialMode.includeJdkHeaders()) {
for (VirtualFile root : compilerDependencies.getJdkHeaderRoots()) {
addLibraryRoot(root);
}
}
if (compilerSpecialMode.includeKotlinRuntime()) {
for (VirtualFile root : compilerDependencies.getRuntimeRoots()) {
addLibraryRoot(root);
}
}
JetStandardLibrary.initialize(getProject());
}
public MockApplication getApplication() {
return myApplication;
}
private void addSources(File file) {
if(file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (File child : files) {
addSources(child);
}
}
}
else {
VirtualFile fileByPath = getLocalFileSystem().findFileByPath(file.getAbsolutePath());
if (fileByPath != null) {
PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(fileByPath);
if(psiFile instanceof JetFile) {
sourceFiles.add((JetFile)psiFile);
}
}
}
}
public void addSources(VirtualFile vFile) {
if (vFile.isDirectory()) {
for (VirtualFile virtualFile : vFile.getChildren()) {
addSources(virtualFile);
}
}
else {
if (vFile.getFileType() == JetFileType.INSTANCE) {
PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(vFile);
if (psiFile instanceof JetFile) {
sourceFiles.add((JetFile)psiFile);
}
}
}
}
public void addSources(String path) {
if(path == null)
return;
VirtualFile vFile = getLocalFileSystem().findFileByPath(path);
if (vFile == null) {
throw new CompileEnvironmentException("File/directory not found: " + path);
}
if (!vFile.isDirectory() && vFile.getFileType() != JetFileType.INSTANCE) {
throw new CompileEnvironmentException("Not a Kotlin file: " + path);
}
addSources(new File(path));
}
public List<JetFile> getSourceFiles() {
return sourceFiles;
}
public void addToClasspathFromClassLoader(ClassLoader loader) {
ClassLoader parent = loader.getParent();
if(parent != null)
addToClasspathFromClassLoader(parent);
if(loader instanceof URLClassLoader) {
for (URL url : ((URLClassLoader) loader).getURLs()) {
File file = new File(url.getPath());
if(file.exists() && (!file.isFile() || file.getPath().endsWith(".jar")))
addToClasspath(file);
}
}
}
}
@@ -1,280 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.LocalTimeCounter;
import jet.Function0;
import jet.modules.Module;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.codegen.*;
import org.jetbrains.jet.compiler.messages.AnalyzerWithCompilerReport;
import org.jetbrains.jet.compiler.messages.CompilerMessageLocation;
import org.jetbrains.jet.compiler.messages.CompilerMessageSeverity;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.resolve.FqName;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.plugin.JetLanguage;
import org.jetbrains.jet.plugin.JetMainDetector;
import org.jetbrains.jet.utils.Progress;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.List;
/**
* @author yole
* @author abreslav
*/
public class KotlinToJVMBytecodeCompiler {
private KotlinToJVMBytecodeCompiler() {
}
@Nullable
public static ClassFileFactory compileModule(
CompileEnvironmentConfiguration configuration,
Module moduleBuilder,
File directory
) {
if (moduleBuilder.getSourceFiles().isEmpty()) {
throw new CompileEnvironmentException("No source files where defined");
}
for (String sourceFile : moduleBuilder.getSourceFiles()) {
File source = new File(sourceFile);
if (!source.isAbsolute()) {
source = new File(directory, sourceFile);
}
if (!source.exists()) {
throw new CompileEnvironmentException("'" + source + "' does not exist");
}
configuration.getEnvironment().addSources(source.getPath());
}
for (String classpathRoot : moduleBuilder.getClasspathRoots()) {
configuration.getEnvironment().addToClasspath(new File(classpathRoot));
}
CompileEnvironmentUtil.ensureRuntime(configuration.getEnvironment(), configuration.getCompilerDependencies());
GenerationState generationState = analyzeAndGenerate(configuration);
if (generationState == null) {
return null;
}
return generationState.getFactory();
}
public static boolean compileModules(
CompileEnvironmentConfiguration configuration,
@NotNull List<Module> modules,
@NotNull File directory,
@Nullable String jarPath,
@Nullable String outputDir,
boolean jarRuntime) {
for (Module moduleBuilder : modules) {
// TODO: this should be done only once for the environment
if (configuration.getCompilerDependencies().getRuntimeJar() != null) {
CompileEnvironmentUtil
.addToClasspath(configuration.getEnvironment(), configuration.getCompilerDependencies().getRuntimeJar());
}
ClassFileFactory moduleFactory = compileModule(configuration, moduleBuilder, directory);
if (moduleFactory == null) {
return false;
}
if (outputDir != null) {
CompileEnvironmentUtil.writeToOutputDirectory(moduleFactory, outputDir);
}
else {
String path = jarPath != null ? jarPath : new File(directory, moduleBuilder.getModuleName() + ".jar").getPath();
try {
CompileEnvironmentUtil.writeToJar(moduleFactory, new FileOutputStream(path), null, jarRuntime);
}
catch (FileNotFoundException e) {
throw new CompileEnvironmentException("Invalid jar path " + path, e);
}
}
}
return true;
}
private static boolean compileBunchOfSources(
CompileEnvironmentConfiguration configuration,
String jar,
String outputDir,
boolean includeRuntime
) {
FqName mainClass = null;
for (JetFile file : configuration.getEnvironment().getSourceFiles()) {
if (JetMainDetector.hasMain(file.getDeclarations())) {
FqName fqName = JetPsiUtil.getFQName(file);
mainClass = fqName.child(JvmAbi.PACKAGE_CLASS);
break;
}
}
CompileEnvironmentUtil.ensureRuntime(configuration.getEnvironment(), configuration.getCompilerDependencies());
GenerationState generationState = analyzeAndGenerate(configuration);
if (generationState == null) {
return false;
}
try {
ClassFileFactory factory = generationState.getFactory();
if (jar != null) {
try {
CompileEnvironmentUtil.writeToJar(factory, new FileOutputStream(jar), mainClass, includeRuntime);
}
catch (FileNotFoundException e) {
throw new CompileEnvironmentException("Invalid jar path " + jar, e);
}
}
else if (outputDir != null) {
CompileEnvironmentUtil.writeToOutputDirectory(factory, outputDir);
}
else {
throw new CompileEnvironmentException("Output directory or jar file is not specified - no files will be saved to the disk");
}
return true;
}
finally {
generationState.destroy();
}
}
public static boolean compileBunchOfSources(
CompileEnvironmentConfiguration configuration,
String sourceFileOrDir, String jar, String outputDir, boolean includeRuntime) {
configuration.getEnvironment().addSources(sourceFileOrDir);
return compileBunchOfSources(configuration, jar, outputDir, includeRuntime);
}
public static boolean compileBunchOfSourceDirectories(
CompileEnvironmentConfiguration configuration,
List<String> sources, String jar, String outputDir, boolean includeRuntime) {
for (String source : sources) {
configuration.getEnvironment().addSources(source);
}
return compileBunchOfSources(configuration, jar, outputDir, includeRuntime);
}
@Nullable
public static ClassLoader compileText(
CompileEnvironmentConfiguration configuration,
String code) {
configuration.getEnvironment()
.addSources(new LightVirtualFile("script" + LocalTimeCounter.currentTime() + ".kt", JetLanguage.INSTANCE, code));
GenerationState generationState = analyzeAndGenerate(configuration);
if (generationState == null) {
return null;
}
return new GeneratedClassLoader(generationState.getFactory());
}
@Nullable
public static GenerationState analyzeAndGenerate(CompileEnvironmentConfiguration configuration) {
return analyzeAndGenerate(configuration, configuration.getCompilerDependencies().getCompilerSpecialMode().isStubs());
}
@Nullable
public static GenerationState analyzeAndGenerate(
CompileEnvironmentConfiguration configuration,
boolean stubs
) {
AnalyzeExhaust exhaust = analyze(configuration, stubs);
if (exhaust == null) {
return null;
}
exhaust.throwIfError();
return generate(configuration, exhaust, stubs);
}
@Nullable
private static AnalyzeExhaust analyze(
final CompileEnvironmentConfiguration configuration,
boolean stubs) {
final JetCoreEnvironment environment = configuration.getEnvironment();
AnalyzerWithCompilerReport analyzerWithCompilerReport = new AnalyzerWithCompilerReport(configuration.getMessageCollector());
final Predicate<PsiFile> filesToAnalyzeCompletely =
stubs ? Predicates.<PsiFile>alwaysFalse() : Predicates.<PsiFile>alwaysTrue();
analyzerWithCompilerReport.analyzeAndReport(
new Function0<AnalyzeExhaust>() {
@NotNull
@Override
public AnalyzeExhaust invoke() {
return AnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
environment.getProject(), environment.getSourceFiles(), filesToAnalyzeCompletely,
JetControlFlowDataTraceFactory.EMPTY,
configuration.getCompilerDependencies());
}
}, environment.getSourceFiles()
);
return analyzerWithCompilerReport.hasErrors() ? null : analyzerWithCompilerReport.getAnalyzeExhaust();
}
@NotNull
private static GenerationState generate(
final CompileEnvironmentConfiguration configuration,
AnalyzeExhaust exhaust,
boolean stubs) {
JetCoreEnvironment environment = configuration.getEnvironment();
Project project = environment.getProject();
Progress backendProgress = new Progress() {
@Override
public void log(String message) {
configuration.getMessageCollector().report(CompilerMessageSeverity.LOGGING, message, CompilerMessageLocation.NO_LOCATION);
}
};
GenerationState generationState = new GenerationState(project, ClassBuilderFactories.binaries(stubs), backendProgress,
exhaust, environment.getSourceFiles(),
configuration.getCompilerDependencies().getCompilerSpecialMode());
generationState.compileCorrectFiles(CompilationErrorHandler.THROW_EXCEPTION);
List<CompilerPlugin> plugins = configuration.getCompilerPlugins();
if (plugins != null) {
CompilerPluginContext context = new CompilerPluginContext(project, exhaust.getBindingContext(), environment.getSourceFiles());
for (CompilerPlugin plugin : plugins) {
plugin.processFiles(context);
}
}
return generationState;
}
}
@@ -1,34 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler;
/**
* @author yole
*/
public class ModuleExecutionException extends RuntimeException {
public ModuleExecutionException(String message) {
super(message);
}
public ModuleExecutionException(Throwable cause) {
super(cause);
}
public ModuleExecutionException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -1,151 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler.messages;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
import jet.Function0;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.diagnostics.*;
import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import java.util.Collection;
/**
* @author Pavel Talanov
*/
public final class AnalyzerWithCompilerReport {
@NotNull
private static CompilerMessageSeverity convertSeverity(@NotNull Severity severity) {
switch (severity) {
case INFO:
return CompilerMessageSeverity.INFO;
case ERROR:
return CompilerMessageSeverity.ERROR;
case WARNING:
return CompilerMessageSeverity.WARNING;
}
throw new IllegalStateException("Unknown severity: " + severity);
}
@NotNull
private static final SimpleDiagnosticFactory<PsiErrorElement> SYNTAX_ERROR_FACTORY = SimpleDiagnosticFactory.create(Severity.ERROR);
private boolean hasErrors = false;
@NotNull
private final MessageCollector messageCollectorWrapper;
@Nullable
private AnalyzeExhaust analyzeExhaust = null;
public AnalyzerWithCompilerReport(@NotNull final MessageCollector collector) {
messageCollectorWrapper = new MessageCollector() {
@Override
public void report(@NotNull CompilerMessageSeverity severity,
@NotNull String message,
@NotNull CompilerMessageLocation location) {
if (CompilerMessageSeverity.ERRORS.contains(severity)) {
hasErrors = true;
}
collector.report(severity, message, location);
}
};
}
private void reportDiagnostic(@NotNull Diagnostic diagnostic) {
DiagnosticUtils.LineAndColumn lineAndColumn = DiagnosticUtils.getLineAndColumn(diagnostic);
VirtualFile virtualFile = diagnostic.getPsiFile().getVirtualFile();
String path = virtualFile == null ? null : virtualFile.getPath();
String render;
if (diagnostic.getFactory() == SYNTAX_ERROR_FACTORY) {
render = ((SyntaxErrorDiagnostic)diagnostic).message;
}
else {
render = DefaultErrorMessages.RENDERER.render(diagnostic);
}
messageCollectorWrapper.report(convertSeverity(diagnostic.getSeverity()), render,
CompilerMessageLocation.create(path, lineAndColumn.getLine(), lineAndColumn.getColumn()));
}
private void reportIncompleteHierarchies() {
assert analyzeExhaust != null;
Collection<ClassDescriptor> incompletes = analyzeExhaust.getBindingContext().getKeys(BindingContext.INCOMPLETE_HIERARCHY);
if (!incompletes.isEmpty()) {
StringBuilder message = new StringBuilder("The following classes have incomplete hierarchies:\n");
for (ClassDescriptor incomplete : incompletes) {
String fqName = DescriptorUtils.getFQName(incomplete).getFqName();
message.append(" ").append(fqName).append("\n");
}
messageCollectorWrapper.report(CompilerMessageSeverity.ERROR, message.toString(), CompilerMessageLocation.NO_LOCATION);
}
}
private void reportDiagnostics() {
assert analyzeExhaust != null;
for (Diagnostic diagnostic : analyzeExhaust.getBindingContext().getDiagnostics()) {
reportDiagnostic(diagnostic);
}
}
private void reportSyntaxErrors(@NotNull Collection<JetFile> files) {
for (JetFile file : files) {
file.accept(new PsiRecursiveElementWalkingVisitor() {
@Override
public void visitErrorElement(PsiErrorElement element) {
String description = element.getErrorDescription();
String message = StringUtil.isEmpty(description) ? "Syntax error" : description;
Diagnostic diagnostic = new SyntaxErrorDiagnostic(element, Severity.ERROR, message);
reportDiagnostic(diagnostic);
}
});
}
}
@Nullable
public AnalyzeExhaust getAnalyzeExhaust() {
return analyzeExhaust;
}
public boolean hasErrors() {
return hasErrors;
}
public void analyzeAndReport(@NotNull Function0<AnalyzeExhaust> analyzer, @NotNull Collection<JetFile> files) {
reportSyntaxErrors(files);
analyzeExhaust = analyzer.invoke();
reportDiagnostics();
reportIncompleteHierarchies();
}
public static class SyntaxErrorDiagnostic extends SimpleDiagnostic<PsiErrorElement> {
private String message;
public SyntaxErrorDiagnostic(@NotNull PsiErrorElement psiElement, @NotNull Severity severity, String message) {
super(psiElement, SYNTAX_ERROR_FACTORY, severity);
this.message = message;
}
}
}
@@ -1,57 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler.messages;
import org.jetbrains.annotations.Nullable;
/**
* @author abreslav
*/
public class CompilerMessageLocation {
public static final CompilerMessageLocation NO_LOCATION = new CompilerMessageLocation(null, -1, -1);
public static CompilerMessageLocation create(@Nullable String path, int line, int column) {
if (path == null) {
return NO_LOCATION;
}
return new CompilerMessageLocation(path, line, column);
}
private final String path;
private final int line;
private final int column;
private CompilerMessageLocation(@Nullable String path, int line, int column) {
this.path = path;
this.line = line;
this.column = column;
}
@Nullable
public String getPath() {
return path;
}
public int getLine() {
return line;
}
public int getColumn() {
return column;
}
}
@@ -1,32 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler.messages;
import java.util.EnumSet;
/**
* @author abreslav
*/
public enum CompilerMessageSeverity {
INFO,
ERROR,
WARNING,
EXCEPTION,
LOGGING;
public static final EnumSet<CompilerMessageSeverity> ERRORS = EnumSet.of(ERROR, EXCEPTION);
}
@@ -1,31 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler.messages;
import org.jetbrains.annotations.NotNull;
public interface MessageCollector {
MessageCollector PLAIN_TEXT_TO_SYSTEM_ERR = new MessageCollector() {
@Override
public void report(@NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location) {
System.err.println(MessageRenderer.PLAIN.render(severity, message, location));
}
};
void report(@NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location);
}
@@ -1,99 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler.messages;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* @author abreslav
*/
public interface MessageRenderer {
MessageRenderer TAGS = new MessageRenderer() {
@Override
public String renderPreamble() {
return "<MESSAGES>";
}
@Override
public String render(@NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location) {
StringBuilder out = new StringBuilder();
out.append("<").append(severity.toString());
if (location.getPath() != null) {
out.append(" path=\"").append(e(location.getPath())).append("\"");
out.append(" line=\"").append(location.getLine()).append("\"");
out.append(" column=\"").append(location.getColumn()).append("\"");
}
out.append(">\n");
out.append(e(message));
out.append("</").append(severity.toString()).append(">\n");
return out.toString();
}
private String e(String str) {
return StringUtil.escapeXml(str);
}
@Override
public String renderException(@NotNull Throwable e) {
return render(CompilerMessageSeverity.EXCEPTION, PLAIN.renderException(e), CompilerMessageLocation.NO_LOCATION);
}
@Override
public String renderConclusion() {
return "</MESSAGES>";
}
};
MessageRenderer PLAIN = new MessageRenderer() {
@Override
public String renderPreamble() {
return "";
}
@Override
public String render(@NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location) {
String path = location.getPath();
String position = path == null ? "" : path + ": (" + (location.getLine() + ", " + location.getColumn()) + ") ";
return severity + ": " + position + message;
}
@Override
public String renderException(@NotNull Throwable e) {
StringWriter out = new StringWriter();
//noinspection IOResourceOpenedButNotSafelyClosed
e.printStackTrace(new PrintWriter(out));
return out.toString();
}
@Override
public String renderConclusion() {
return "";
}
};
String renderPreamble();
String render(@NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location);
String renderException(@NotNull Throwable e);
String renderConclusion();
}
@@ -1,32 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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.jetbrains.jet.compiler.messages;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
/**
* @author abreslav
*/
public class MessageUtil {
public static CompilerMessageLocation psiElementToMessageLocation(PsiElement element) {
PsiFile file = element.getContainingFile();
DiagnosticUtils.LineAndColumn lineAndColumn = DiagnosticUtils.getLineAndColumnInPsiFile(file, element.getTextRange());
return CompilerMessageLocation.create(file.getVirtualFile().getPath(), lineAndColumn.getLine(), lineAndColumn.getColumn());
}
}