Proper handling of compiler messages

We used to have a triple (errorStream, messageRenderer, verbose) to represent the error reporting strategy.
 Now we have a single MessageCollector abstraction for this.
 As the MessageCollector abstraction was extracted, the need to CompilerMessageLocation and CompilerMessageSeverity arose, too.
This commit is contained in:
Andrey Breslav
2012-04-13 19:38:07 +04:00
parent b82416b5cd
commit 882412ea06
15 changed files with 269 additions and 155 deletions
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.compiler.CompileEnvironment; import org.jetbrains.jet.compiler.CompileEnvironment;
import org.jetbrains.jet.compiler.CompileEnvironmentException; import org.jetbrains.jet.compiler.CompileEnvironmentException;
import org.jetbrains.jet.compiler.CompilerPlugin; import org.jetbrains.jet.compiler.CompilerPlugin;
import org.jetbrains.jet.compiler.messages.MessageCollector;
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode;
@@ -49,7 +50,7 @@ public class BytecodeCompiler {
* @return compile environment instance * @return compile environment instance
*/ */
private CompileEnvironment env( String stdlib, String[] classpath ) { private CompileEnvironment env( String stdlib, String[] classpath ) {
CompileEnvironment env = new CompileEnvironment(CompilerDependencies.compilerDependenciesForProduction(CompilerSpecialMode.REGULAR)); CompileEnvironment env = new CompileEnvironment(MessageCollector.PLAIN_TEXT_TO_SYSTEM_ERR, CompilerDependencies.compilerDependenciesForProduction(CompilerSpecialMode.REGULAR));
if (( stdlib != null ) && ( stdlib.trim().length() > 0 )) { if (( stdlib != null ) && ( stdlib.trim().length() > 0 )) {
env.setStdlib( stdlib ); env.setStdlib( stdlib );
@@ -18,19 +18,24 @@ package org.jetbrains.jet.cli;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.sampullara.cli.Args; import com.sampullara.cli.Args;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.compiler.CompileEnvironment; import org.jetbrains.jet.compiler.CompileEnvironment;
import org.jetbrains.jet.compiler.CompileEnvironmentException; import org.jetbrains.jet.compiler.CompileEnvironmentException;
import org.jetbrains.jet.compiler.CompilerPlugin; import org.jetbrains.jet.compiler.CompilerPlugin;
import org.jetbrains.jet.compiler.MessageRenderer; import org.jetbrains.jet.compiler.messages.CompilerMessageLocation;
import org.jetbrains.jet.lang.diagnostics.Severity; import org.jetbrains.jet.compiler.messages.CompilerMessageSeverity;
import org.jetbrains.jet.compiler.messages.MessageCollector;
import org.jetbrains.jet.compiler.messages.MessageRenderer;
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode;
import org.jetbrains.jet.utils.PathUtil; import org.jetbrains.jet.utils.PathUtil;
import java.io.File; import java.io.File;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.Collection;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.cli.KotlinCompiler.ExitCode.*; import static org.jetbrains.jet.cli.KotlinCompiler.ExitCode.*;
@@ -93,17 +98,17 @@ public class KotlinCompiler {
/** /**
* Executes the compiler on the parsed arguments * Executes the compiler on the parsed arguments
*/ */
public ExitCode exec(PrintStream errStream, CompilerArguments arguments) { public ExitCode exec(final PrintStream errStream, CompilerArguments arguments) {
if (arguments.help) { if (arguments.help) {
usage(errStream); usage(errStream);
return OK; return OK;
} }
System.setProperty("java.awt.headless", "true"); System.setProperty("java.awt.headless", "true");
MessageRenderer messageRenderer = arguments.tags ? MessageRenderer.TAGS : MessageRenderer.PLAIN; final MessageRenderer messageRenderer = arguments.tags ? MessageRenderer.TAGS : MessageRenderer.PLAIN;
if (arguments.version) { if (arguments.version) {
errStream.println(messageRenderer.render(Severity.INFO, "Kotlin Compiler version " + CompilerVersion.VERSION, null, -1, -1)); errStream.println(messageRenderer.render(CompilerMessageSeverity.INFO, "Kotlin Compiler version " + CompilerVersion.VERSION, CompilerMessageLocation.NO_LOCATION));
} }
CompilerSpecialMode mode = parseCompilerSpecialMode(arguments); CompilerSpecialMode mode = parseCompilerSpecialMode(arguments);
@@ -135,9 +140,10 @@ public class KotlinCompiler {
} }
CompilerDependencies dependencies = new CompilerDependencies(mode, jdkHeadersJar,runtimeJar); CompilerDependencies dependencies = new CompilerDependencies(mode, jdkHeadersJar,runtimeJar);
CompileEnvironment environment = new CompileEnvironment(messageRenderer, arguments.verbose, dependencies); PrintingMessageCollector messageCollector = new PrintingMessageCollector(errStream, messageRenderer, arguments.verbose);
CompileEnvironment environment = new CompileEnvironment(messageCollector, dependencies);
try { try {
configureEnvironment(environment, arguments, errStream); configureEnvironment(environment, arguments);
boolean noErrors; boolean noErrors;
if (arguments.module != null) { if (arguments.module != null) {
@@ -160,6 +166,7 @@ public class KotlinCompiler {
} }
finally { finally {
environment.dispose(); environment.dispose();
messageCollector.printToErrStream();
} }
} }
@@ -225,10 +232,7 @@ public class KotlinCompiler {
* Strategy method to configure the environment, allowing compiler * Strategy method to configure the environment, allowing compiler
* based tools to customise their own plugins * based tools to customise their own plugins
*/ */
protected void configureEnvironment(CompileEnvironment environment, CompilerArguments arguments, PrintStream errStream) { protected void configureEnvironment(CompileEnvironment environment, CompilerArguments arguments) {
environment.setIgnoreErrors(false);
environment.setErrorStream(errStream);
// install any compiler plugins // install any compiler plugins
List<CompilerPlugin> plugins = arguments.getCompilerPlugins(); List<CompilerPlugin> plugins = arguments.getCompilerPlugins();
if (plugins != null) { if (plugins != null) {
@@ -244,4 +248,46 @@ public class KotlinCompiler {
environment.addToClasspath(Iterables.toArray(classpath, String.class)); environment.addToClasspath(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);
}
}
}
}
}
} }
@@ -26,6 +26,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.GeneratedClassLoader; import org.jetbrains.jet.codegen.GeneratedClassLoader;
import org.jetbrains.jet.codegen.GenerationState; import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.compiler.messages.MessageCollector;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.resolve.FqName; import org.jetbrains.jet.lang.resolve.FqName;
@@ -37,7 +38,6 @@ import org.jetbrains.jet.plugin.JetMainDetector;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.List; import java.util.List;
/** /**
@@ -49,48 +49,33 @@ public class CompileEnvironment {
private final Disposable rootDisposable; private final Disposable rootDisposable;
private JetCoreEnvironment environment; private JetCoreEnvironment environment;
private final MessageRenderer messageRenderer; private final MessageCollector messageCollector;
private PrintStream errorStream = System.err;
private boolean ignoreErrors = false;
@NotNull @NotNull
private final CompilerDependencies compilerDependencies; private final CompilerDependencies compilerDependencies;
private final boolean verbose;
public CompileEnvironment(CompilerDependencies compilerDependencies) {
this(MessageRenderer.PLAIN, false, compilerDependencies);
}
/** /**
* NOTE: It's very important to call dispose for every object of this class or there will be memory leaks. * NOTE: It's very important to call dispose for every object of this class or there will be memory leaks.
* @see Disposer * @see Disposer
*/ */
public CompileEnvironment(MessageRenderer messageRenderer, boolean verbose, @NotNull CompilerDependencies compilerDependencies) { public CompileEnvironment(@NotNull MessageCollector messageCollector, @NotNull CompilerDependencies compilerDependencies) {
this.messageCollector = messageCollector;
this.compilerDependencies = compilerDependencies; this.compilerDependencies = compilerDependencies;
this.verbose = verbose;
this.rootDisposable = new Disposable() { this.rootDisposable = new Disposable() {
@Override @Override
public void dispose() { public void dispose() {
} }
}; };
this.environment = new JetCoreEnvironment(rootDisposable, compilerDependencies); this.environment = new JetCoreEnvironment(rootDisposable, compilerDependencies);
this.messageRenderer = messageRenderer;
} }
public void setErrorStream(PrintStream errorStream) {
this.errorStream = errorStream;
}
public void setIgnoreErrors(boolean ignoreErrors) {
this.ignoreErrors = ignoreErrors;
}
public void dispose() { public void dispose() {
Disposer.dispose(rootDisposable); Disposer.dispose(rootDisposable);
} }
public boolean compileModuleScript(String moduleScriptFile, @Nullable String jarPath, @Nullable String outputDir, boolean jarRuntime) { public boolean compileModuleScript(String moduleScriptFile, @Nullable String jarPath, @Nullable String outputDir, boolean jarRuntime) {
List<Module> modules = CompileEnvironmentUtil.loadModuleScript(moduleScriptFile, messageRenderer, errorStream, verbose); List<Module> modules = CompileEnvironmentUtil.loadModuleScript(moduleScriptFile, messageCollector);
if (modules == null) { if (modules == null) {
throw new CompileEnvironmentException("Module script " + moduleScriptFile + " compilation failed"); throw new CompileEnvironmentException("Module script " + moduleScriptFile + " compilation failed");
@@ -212,7 +197,7 @@ public class CompileEnvironment {
boolean stubs = compilerDependencies.getCompilerSpecialMode().isStubs(); boolean stubs = compilerDependencies.getCompilerSpecialMode().isStubs();
GenerationState generationState = GenerationState generationState =
KotlinToJVMBytecodeCompiler KotlinToJVMBytecodeCompiler
.analyzeAndGenerate(environment, compilerDependencies, messageRenderer, errorStream, verbose, stubs); .analyzeAndGenerate(environment, compilerDependencies, messageCollector, stubs);
if (generationState == null) { if (generationState == null) {
return null; return null;
} }
@@ -28,13 +28,17 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.GeneratedClassLoader; import org.jetbrains.jet.codegen.GeneratedClassLoader;
import org.jetbrains.jet.codegen.GenerationState; 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.FqName;
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode;
import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.utils.PathUtil; import org.jetbrains.jet.utils.PathUtil;
import java.io.*; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
@@ -148,7 +152,7 @@ public class CompileEnvironmentUtil {
// return compileEnvironment; // return compileEnvironment;
//} //}
// //
public static List<Module> loadModuleScript(String moduleFile, MessageRenderer messageRenderer, PrintStream errorStream, boolean verbose) { public static List<Module> loadModuleScript(String moduleFile, MessageCollector messageCollector) {
Disposable disposable = new Disposable() { Disposable disposable = new Disposable() {
@Override @Override
public void dispose() { public void dispose() {
@@ -161,7 +165,7 @@ public class CompileEnvironmentUtil {
scriptEnvironment.addSources(moduleFile); scriptEnvironment.addSources(moduleFile);
GenerationState generationState = KotlinToJVMBytecodeCompiler GenerationState generationState = KotlinToJVMBytecodeCompiler
.analyzeAndGenerate(scriptEnvironment, dependencies, messageRenderer, errorStream, verbose, false); .analyzeAndGenerate(scriptEnvironment, dependencies, messageCollector, false);
if (generationState == null) { if (generationState == null) {
return null; return null;
} }
@@ -19,6 +19,7 @@ package org.jetbrains.jet.compiler;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiErrorElement; import com.intellij.psi.PsiErrorElement;
@@ -31,6 +32,9 @@ import org.jetbrains.jet.codegen.ClassBuilderFactories;
import org.jetbrains.jet.codegen.CompilationErrorHandler; import org.jetbrains.jet.codegen.CompilationErrorHandler;
import org.jetbrains.jet.codegen.GenerationState; import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.compiler.messages.CompilerMessageLocation;
import org.jetbrains.jet.compiler.messages.CompilerMessageSeverity;
import org.jetbrains.jet.compiler.messages.MessageCollector;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor;
@@ -47,7 +51,6 @@ import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
import org.jetbrains.jet.utils.Progress; import org.jetbrains.jet.utils.Progress;
import java.io.PrintStream;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@@ -62,31 +65,38 @@ public class KotlinToJVMBytecodeCompiler {
JetCoreEnvironment environment, JetCoreEnvironment environment,
CompilerDependencies dependencies, CompilerDependencies dependencies,
MessageRenderer messageRenderer, final MessageCollector messageCollector,
PrintStream errorStream,
boolean verbose,
boolean stubs boolean stubs
) { ) {
AnalyzeExhaust exhaust = analyze(environment, dependencies, messageRenderer, errorStream, stubs); AnalyzeExhaust exhaust = analyze(environment, dependencies, messageCollector, stubs);
if (exhaust == null) { if (exhaust == null) {
return null; return null;
} }
return generate(environment, dependencies, messageRenderer, errorStream, verbose, exhaust, stubs); return generate(environment, dependencies, messageCollector, exhaust, stubs);
} }
@Nullable @Nullable
private static AnalyzeExhaust analyze( private static AnalyzeExhaust analyze(
JetCoreEnvironment environment, JetCoreEnvironment environment,
CompilerDependencies dependencies, CompilerDependencies dependencies,
final MessageCollector messageCollector,
MessageRenderer messageRenderer,
PrintStream errorStream,
boolean stubs) { boolean stubs) {
final MessageCollector messageCollector = new MessageCollector(messageRenderer); final Ref<Boolean> hasErrors = new Ref<Boolean>(false);
final MessageCollector messageCollectorWrapper = new MessageCollector() {
@Override
public void report(@NotNull CompilerMessageSeverity severity,
@NotNull String message,
@NotNull CompilerMessageLocation location) {
if (CompilerMessageSeverity.ERRORS.contains(severity)) {
hasErrors.set(true);
}
messageCollector.report(severity, message, location);
}
};
//reportSyntaxErrors(); //reportSyntaxErrors();
for (JetFile file : environment.getSourceFiles()) { for (JetFile file : environment.getSourceFiles()) {
@@ -96,7 +106,7 @@ public class KotlinToJVMBytecodeCompiler {
String description = element.getErrorDescription(); String description = element.getErrorDescription();
String message = StringUtil.isEmpty(description) ? "Syntax error" : description; String message = StringUtil.isEmpty(description) ? "Syntax error" : description;
Diagnostic diagnostic = DiagnosticFactory.create(Severity.ERROR, message).on(element); Diagnostic diagnostic = DiagnosticFactory.create(Severity.ERROR, message).on(element);
reportDiagnostic(messageCollector, diagnostic); reportDiagnostic(messageCollectorWrapper, diagnostic);
} }
}); });
} }
@@ -109,14 +119,12 @@ public class KotlinToJVMBytecodeCompiler {
dependencies); dependencies);
for (Diagnostic diagnostic : exhaust.getBindingContext().getDiagnostics()) { for (Diagnostic diagnostic : exhaust.getBindingContext().getDiagnostics()) {
reportDiagnostic(messageCollector, diagnostic); reportDiagnostic(messageCollectorWrapper, diagnostic);
} }
reportIncompleteHierarchies(messageCollector, exhaust); reportIncompleteHierarchies(messageCollectorWrapper, exhaust);
messageCollector.printTo(errorStream); return hasErrors.get() ? null : exhaust;
return messageCollector.hasErrors() ? null : exhaust;
} }
@NotNull @NotNull
@@ -124,22 +132,20 @@ public class KotlinToJVMBytecodeCompiler {
JetCoreEnvironment environment, JetCoreEnvironment environment,
CompilerDependencies dependencies, CompilerDependencies dependencies,
final MessageRenderer messageRenderer, final MessageCollector messageCollector,
final PrintStream errorStream,
boolean verbose,
AnalyzeExhaust exhaust, AnalyzeExhaust exhaust,
boolean stubs) { boolean stubs) {
Project project = environment.getProject(); Project project = environment.getProject();
class BackendProgress implements Progress { Progress backendProgress = new Progress() {
@Override @Override
public void log(String message) { public void log(String message) {
errorStream.println(messageRenderer.render(Severity.LOGGING, message, null, -1, -1)); messageCollector.report(CompilerMessageSeverity.LOGGING, message, CompilerMessageLocation.NO_LOCATION);
} }
} };
GenerationState generationState = new GenerationState(project, ClassBuilderFactories.binaries(stubs), GenerationState generationState = new GenerationState(project, ClassBuilderFactories.binaries(stubs), backendProgress,
verbose ? new BackendProgress() : Progress.DEAF, exhaust, environment.getSourceFiles(), dependencies.getCompilerSpecialMode()); exhaust, environment.getSourceFiles(), dependencies.getCompilerSpecialMode());
generationState.compileCorrectFiles(CompilationErrorHandler.THROW_EXCEPTION); generationState.compileCorrectFiles(CompilationErrorHandler.THROW_EXCEPTION);
List<CompilerPlugin> plugins = environment.getCompilerPlugins(); List<CompilerPlugin> plugins = environment.getCompilerPlugins();
@@ -156,7 +162,19 @@ public class KotlinToJVMBytecodeCompiler {
DiagnosticUtils.LineAndColumn lineAndColumn = DiagnosticUtils.getLineAndColumn(diagnostic); DiagnosticUtils.LineAndColumn lineAndColumn = DiagnosticUtils.getLineAndColumn(diagnostic);
VirtualFile virtualFile = diagnostic.getPsiFile().getVirtualFile(); VirtualFile virtualFile = diagnostic.getPsiFile().getVirtualFile();
String path = virtualFile == null ? null : virtualFile.getPath(); String path = virtualFile == null ? null : virtualFile.getPath();
collector.report(diagnostic.getSeverity(), diagnostic.getMessage(), path, lineAndColumn.getLine(), lineAndColumn.getColumn()); collector.report(convertSeverity(diagnostic.getSeverity()), diagnostic.getMessage(), CompilerMessageLocation.create(path, lineAndColumn.getLine(), lineAndColumn.getColumn()));
}
private static CompilerMessageSeverity convertSeverity(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);
} }
private static void reportIncompleteHierarchies(MessageCollector collector, AnalyzeExhaust exhaust) { private static void reportIncompleteHierarchies(MessageCollector collector, AnalyzeExhaust exhaust) {
@@ -166,7 +184,7 @@ public class KotlinToJVMBytecodeCompiler {
for (ClassDescriptor incomplete : incompletes) { for (ClassDescriptor incomplete : incompletes) {
message.append(" ").append(fqName(incomplete)).append("\n"); message.append(" ").append(fqName(incomplete)).append("\n");
} }
collector.report(Severity.ERROR, message.toString(), null, -1, -1); collector.report(CompilerMessageSeverity.ERROR, message.toString(), CompilerMessageLocation.NO_LOCATION);
} }
} }
@@ -183,4 +201,8 @@ public class KotlinToJVMBytecodeCompiler {
return fqName((ClassOrNamespaceDescriptor) containingDeclaration) + "." + descriptor.getName(); return fqName((ClassOrNamespaceDescriptor) containingDeclaration) + "." + descriptor.getName();
} }
} }
public static CompilerMessageLocation create(@Nullable String path, @NotNull DiagnosticUtils.LineAndColumn lineAndColumn) {
return CompilerMessageLocation.create(path, lineAndColumn.getLine(), lineAndColumn.getColumn());
}
} }
@@ -1,61 +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.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.diagnostics.Severity;
import java.io.PrintStream;
import java.util.Collection;
/**
* @author alex.tkachman
*/
/*package*/ class MessageCollector {
// File path (nullable) -> error message
private final Multimap<String, String> groupedMessages = LinkedHashMultimap.create();
private final MessageRenderer renderer;
private boolean hasErrors;
public MessageCollector(@NotNull MessageRenderer renderer) {
this.renderer = renderer;
}
public void report(@NotNull Severity severity, @NotNull String message, @Nullable String path, int line, int column) {
hasErrors |= severity == Severity.ERROR;
groupedMessages.put(path, renderer.render(severity, message, path, line, column));
}
public void printTo(@NotNull PrintStream out) {
if (!groupedMessages.isEmpty()) {
for (String path : groupedMessages.keySet()) {
Collection<String> diagnostics = groupedMessages.get(path);
for (String diagnostic : diagnostics) {
out.println(diagnostic);
}
}
}
}
public boolean hasErrors() {
return hasErrors;
}
}
@@ -0,0 +1,57 @@
/*
* 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;
}
}
@@ -0,0 +1,32 @@
/*
* 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);
}
@@ -0,0 +1,31 @@
/*
* 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);
}
@@ -14,11 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.jet.compiler; package org.jetbrains.jet.compiler.messages;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.diagnostics.Severity;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
@@ -29,48 +27,46 @@ import java.io.StringWriter;
public interface MessageRenderer { public interface MessageRenderer {
MessageRenderer TAGS = new MessageRenderer() { MessageRenderer TAGS = new MessageRenderer() {
private String renderWithStringSeverity(String severityString, String message, String path, int line, int column) { @Override
public String render(@NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location) {
StringBuilder out = new StringBuilder(); StringBuilder out = new StringBuilder();
out.append("<").append(severityString); out.append("<").append(severity.toString());
if (path != null) { if (location.getPath() != null) {
out.append(" path=\"").append(path).append("\""); out.append(" path=\"").append(location.getPath()).append("\"");
out.append(" line=\"").append(line).append("\""); out.append(" line=\"").append(location.getLine()).append("\"");
out.append(" column=\"").append(column).append("\""); out.append(" column=\"").append(location.getColumn()).append("\"");
} }
out.append(">\n"); out.append(">\n");
out.append(message); out.append(message);
out.append("</").append(severityString).append(">\n"); out.append("</").append(severity.toString()).append(">\n");
return out.toString(); return out.toString();
} }
@Override
public String render(@NotNull Severity severity, @NotNull String message, @Nullable String path, int line, int column) {
return renderWithStringSeverity(severity.toString(), message, path, line, column);
}
@Override @Override
public String renderException(@NotNull Throwable e) { public String renderException(@NotNull Throwable e) {
return renderWithStringSeverity("EXCEPTION", PLAIN.renderException(e), null, -1, -1); return render(CompilerMessageSeverity.EXCEPTION, PLAIN.renderException(e), CompilerMessageLocation.NO_LOCATION);
} }
}; };
MessageRenderer PLAIN = new MessageRenderer() { MessageRenderer PLAIN = new MessageRenderer() {
@Override @Override
public String render(@NotNull Severity severity, @NotNull String message, @Nullable String path, int line, int column) { public String render(@NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location) {
String position = path == null ? "" : path + ": (" + (line + ", " + column) + ") "; String path = location.getPath();
String position = path == null ? "" : path + ": (" + (location.getLine() + ", " + location.getColumn()) + ") ";
return severity + ": " + position + message; return severity + ": " + position + message;
} }
@Override @Override
public String renderException(@NotNull Throwable e) { public String renderException(@NotNull Throwable e) {
StringWriter out = new StringWriter(); StringWriter out = new StringWriter();
//noinspection IOResourceOpenedButNotSafelyClosed
e.printStackTrace(new PrintWriter(out)); e.printStackTrace(new PrintWriter(out));
return out.toString(); return out.toString();
} }
}; };
String render(@NotNull Severity severity, @NotNull String message, @Nullable String path, int line, int column); String render(@NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location);
String renderException(@NotNull Throwable e); String renderException(@NotNull Throwable e);
} }
@@ -20,7 +20,6 @@ package org.jetbrains.jet.lang.diagnostics;
* @author abreslav * @author abreslav
*/ */
public enum Severity { public enum Severity {
LOGGING,
INFO, INFO,
ERROR, ERROR,
WARNING WARNING
@@ -18,6 +18,7 @@ package org.jetbrains.jet.codegen;
import org.jetbrains.jet.CompileCompilerDependenciesTest; import org.jetbrains.jet.CompileCompilerDependenciesTest;
import org.jetbrains.jet.compiler.CompileEnvironment; import org.jetbrains.jet.compiler.CompileEnvironment;
import org.jetbrains.jet.compiler.messages.MessageCollector;
import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@@ -26,7 +27,7 @@ import java.lang.reflect.Method;
public class CompileTextTest extends CodegenTestCase { public class CompileTextTest extends CodegenTestCase {
public void testMe() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { public void testMe() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
String text = "import org.jetbrains.jet.codegen.CompileTextTest; fun x() = CompileTextTest()"; String text = "import org.jetbrains.jet.codegen.CompileTextTest; fun x() = CompileTextTest()";
CompileEnvironment compileEnvironment = new CompileEnvironment(CompileCompilerDependenciesTest.compilerDependenciesForTests(CompilerSpecialMode.REGULAR)); CompileEnvironment compileEnvironment = new CompileEnvironment(MessageCollector.PLAIN_TEXT_TO_SYSTEM_ERR, CompileCompilerDependenciesTest.compilerDependenciesForTests(CompilerSpecialMode.REGULAR));
compileEnvironment.getEnvironment().addToClasspathFromClassLoader(getClass().getClassLoader()); compileEnvironment.getEnvironment().addToClasspathFromClassLoader(getClass().getClassLoader());
ClassLoader classLoader = compileEnvironment.compileText(text); ClassLoader classLoader = compileEnvironment.compileText(text);
Class<?> namespace = classLoader.loadClass("namespace"); Class<?> namespace = classLoader.loadClass("namespace");
@@ -24,7 +24,7 @@ import junit.framework.TestSuite;
import org.jetbrains.jet.CompileCompilerDependenciesTest; import org.jetbrains.jet.CompileCompilerDependenciesTest;
import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileRuntime; import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileRuntime;
import org.jetbrains.jet.compiler.KotlinToJVMBytecodeCompiler; import org.jetbrains.jet.compiler.KotlinToJVMBytecodeCompiler;
import org.jetbrains.jet.compiler.MessageRenderer; import org.jetbrains.jet.compiler.messages.MessageCollector;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.JetClass; import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetDeclaration;
@@ -92,7 +92,7 @@ public class TestlibTest extends CodegenTestCase {
myEnvironment.addSources(localFileSystem.findFileByPath(JetParsingTest.getTestDataDir() + "/../../libraries/kunit/src")); myEnvironment.addSources(localFileSystem.findFileByPath(JetParsingTest.getTestDataDir() + "/../../libraries/kunit/src"));
GenerationState generationState = KotlinToJVMBytecodeCompiler GenerationState generationState = KotlinToJVMBytecodeCompiler
.analyzeAndGenerate(myEnvironment, compilerDependencies, MessageRenderer.PLAIN, err, false, false); .analyzeAndGenerate(myEnvironment, compilerDependencies, MessageCollector.PLAIN_TEXT_TO_SYSTEM_ERR, false);
if (generationState == null) { if (generationState == null) {
throw new RuntimeException("There were compilation errors"); throw new RuntimeException("There were compilation errors");
@@ -42,7 +42,6 @@ import com.intellij.util.Chunk;
import com.intellij.util.SystemProperties; import com.intellij.util.SystemProperties;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.diagnostics.Severity;
import org.jetbrains.jet.plugin.JetFileType; import org.jetbrains.jet.plugin.JetFileType;
import org.jetbrains.jet.utils.PathUtil; import org.jetbrains.jet.utils.PathUtil;
@@ -446,15 +445,17 @@ public class JetCompiler implements TranslatingCompiler {
private String message; private String message;
public void setMessageCategoryFromString(String tagName) { public void setMessageCategoryFromString(String tagName) {
boolean exception = "EXCEPTION".equals(tagName); if ("ERROR".equals(tagName)) {
if (Severity.ERROR.toString().equals(tagName) || exception) {
messageCategory = ERROR; messageCategory = ERROR;
isException = exception;
} }
else if (Severity.WARNING.toString().equals(tagName)) { else if ("EXCEPTION".equals(tagName)) {
messageCategory = ERROR;
isException = true;
}
else if ("WARNING".equals(tagName)) {
messageCategory = WARNING; messageCategory = WARNING;
} }
else if (Severity.LOGGING.toString().equals(tagName)) { else if ("LOGGING".equals(tagName)) {
messageCategory = STATISTICS; messageCategory = STATISTICS;
} }
else { else {
@@ -20,8 +20,8 @@ fun main(args: Array<String?>): Unit {
*/ */
class KDocCompiler() : KotlinCompiler() { class KDocCompiler() : KotlinCompiler() {
protected override fun configureEnvironment(environment : CompileEnvironment?, arguments : CompilerArguments?, errStream : PrintStream?) { protected override fun configureEnvironment(environment : CompileEnvironment?, arguments : CompilerArguments?) {
super.configureEnvironment(environment, arguments, errStream) super.configureEnvironment(environment, arguments)
val coreEnvironment = environment?.getEnvironment() val coreEnvironment = environment?.getEnvironment()
if (coreEnvironment != null) { if (coreEnvironment != null) {
val kdoc = KDoc() val kdoc = KDoc()