Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.compiler.CompileEnvironment;
|
||||
import org.jetbrains.jet.compiler.CompileEnvironmentException;
|
||||
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.CompilerSpecialMode;
|
||||
|
||||
@@ -49,7 +50,7 @@ public class BytecodeCompiler {
|
||||
* @return compile environment instance
|
||||
*/
|
||||
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 )) {
|
||||
env.setStdlib( stdlib );
|
||||
|
||||
@@ -30,6 +30,8 @@ import org.jetbrains.jet.lang.psi.JetImportDirective;
|
||||
import org.jetbrains.jet.lang.psi.JetNamespaceHeader;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||
@@ -53,10 +55,31 @@ public final class TipsManager {
|
||||
JetExpression receiverExpression = expression.getReceiverExpression();
|
||||
if (receiverExpression != null) {
|
||||
// Process as call expression
|
||||
final JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, receiverExpression);
|
||||
final JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression);
|
||||
final JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression);
|
||||
|
||||
if (expressionType != null && resolutionScope != null) {
|
||||
if (!(expressionType instanceof NamespaceType)) {
|
||||
ExpressionReceiver receiverDescriptor = new ExpressionReceiver(receiverExpression, expressionType);
|
||||
Set<DeclarationDescriptor> descriptors = new HashSet<DeclarationDescriptor>();
|
||||
|
||||
DataFlowInfo info = context.get(BindingContext.NON_DEFAULT_EXPRESSION_DATA_FLOW, expression);
|
||||
if (info == null) {
|
||||
info = DataFlowInfo.EMPTY;
|
||||
}
|
||||
|
||||
AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(info, context);
|
||||
List<ReceiverDescriptor> variantsForExplicitReceiver = autoCastService.getVariantsForReceiver(receiverDescriptor);
|
||||
|
||||
for (ReceiverDescriptor descriptor : variantsForExplicitReceiver) {
|
||||
descriptors.addAll(includeExternalCallableExtensions(
|
||||
excludePrivateDescriptors(descriptor.getType().getMemberScope().getAllDescriptors()),
|
||||
resolutionScope, descriptor));
|
||||
}
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
return includeExternalCallableExtensions(
|
||||
excludePrivateDescriptors(expressionType.getMemberScope().getAllDescriptors()),
|
||||
resolutionScope, new ExpressionReceiver(receiverExpression, expressionType));
|
||||
@@ -161,7 +184,7 @@ public final class TipsManager {
|
||||
});
|
||||
}
|
||||
|
||||
private static Collection<DeclarationDescriptor> includeExternalCallableExtensions(
|
||||
private static Set<DeclarationDescriptor> includeExternalCallableExtensions(
|
||||
@NotNull Collection<DeclarationDescriptor> descriptors,
|
||||
@NotNull final JetScope externalScope,
|
||||
@NotNull final ReceiverDescriptor receiverDescriptor
|
||||
@@ -169,7 +192,7 @@ public final class TipsManager {
|
||||
// It's impossible to add extension function for namespace
|
||||
JetType receiverType = receiverDescriptor.getType();
|
||||
if (receiverType instanceof NamespaceType) {
|
||||
return descriptors;
|
||||
return new HashSet<DeclarationDescriptor>(descriptors);
|
||||
}
|
||||
|
||||
Set<DeclarationDescriptor> descriptorsSet = Sets.newHashSet(descriptors);
|
||||
|
||||
@@ -18,19 +18,24 @@ 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.sampullara.cli.Args;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.compiler.CompileEnvironment;
|
||||
import org.jetbrains.jet.compiler.CompileEnvironmentException;
|
||||
import org.jetbrains.jet.compiler.CompilerPlugin;
|
||||
import org.jetbrains.jet.compiler.MessageRenderer;
|
||||
import org.jetbrains.jet.lang.diagnostics.Severity;
|
||||
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.compiler.messages.MessageRenderer;
|
||||
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.*;
|
||||
@@ -67,7 +72,7 @@ public class KotlinCompiler {
|
||||
*/
|
||||
public static void doMain(KotlinCompiler compiler, String[] args) {
|
||||
try {
|
||||
ExitCode rc = compiler.exec(args);
|
||||
ExitCode rc = compiler.exec(System.out, args);
|
||||
if (rc != OK) {
|
||||
System.err.println("exec() finished with " + rc + " return code");
|
||||
System.exit(rc.getCode());
|
||||
@@ -78,10 +83,6 @@ public class KotlinCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
public ExitCode exec(String... args) {
|
||||
return exec(System.out, args);
|
||||
}
|
||||
|
||||
public ExitCode exec(PrintStream errStream, String... args) {
|
||||
CompilerArguments arguments = createArguments();
|
||||
if (!parseArguments(errStream, arguments, args)) {
|
||||
@@ -93,17 +94,17 @@ public class KotlinCompiler {
|
||||
/**
|
||||
* 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) {
|
||||
usage(errStream);
|
||||
return OK;
|
||||
}
|
||||
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) {
|
||||
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);
|
||||
@@ -135,9 +136,10 @@ public class KotlinCompiler {
|
||||
}
|
||||
|
||||
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 {
|
||||
configureEnvironment(environment, arguments, errStream);
|
||||
configureEnvironment(environment, arguments);
|
||||
|
||||
boolean noErrors;
|
||||
if (arguments.module != null) {
|
||||
@@ -160,6 +162,7 @@ public class KotlinCompiler {
|
||||
}
|
||||
finally {
|
||||
environment.dispose();
|
||||
messageCollector.printToErrStream();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,10 +228,7 @@ public class KotlinCompiler {
|
||||
* Strategy method to configure the environment, allowing compiler
|
||||
* based tools to customise their own plugins
|
||||
*/
|
||||
protected void configureEnvironment(CompileEnvironment environment, CompilerArguments arguments, PrintStream errStream) {
|
||||
environment.setIgnoreErrors(false);
|
||||
environment.setErrorStream(errStream);
|
||||
|
||||
protected void configureEnvironment(CompileEnvironment environment, CompilerArguments arguments) {
|
||||
// install any compiler plugins
|
||||
List<CompilerPlugin> plugins = arguments.getCompilerPlugins();
|
||||
if (plugins != null) {
|
||||
@@ -244,4 +244,46 @@ public class KotlinCompiler {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
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.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetPsiUtil;
|
||||
import org.jetbrains.jet.lang.resolve.FqName;
|
||||
@@ -36,7 +38,6 @@ import org.jetbrains.jet.plugin.JetMainDetector;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -48,48 +49,33 @@ public class CompileEnvironment {
|
||||
private final Disposable rootDisposable;
|
||||
private JetCoreEnvironment environment;
|
||||
|
||||
private final MessageRenderer messageRenderer;
|
||||
private PrintStream errorStream = System.err;
|
||||
private final MessageCollector messageCollector;
|
||||
|
||||
private boolean ignoreErrors = false;
|
||||
@NotNull
|
||||
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.
|
||||
* @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.verbose = verbose;
|
||||
this.rootDisposable = new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
};
|
||||
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() {
|
||||
Disposer.dispose(rootDisposable);
|
||||
}
|
||||
|
||||
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) {
|
||||
throw new CompileEnvironmentException("Module script " + moduleScriptFile + " compilation failed");
|
||||
@@ -125,9 +111,6 @@ public class CompileEnvironment {
|
||||
}
|
||||
|
||||
public ClassFileFactory compileModule(Module moduleBuilder, String directory) {
|
||||
CompileSession moduleCompileSession = newCompileSession();
|
||||
moduleCompileSession.setStubs(compilerDependencies.getCompilerSpecialMode().isStubs());
|
||||
|
||||
if (moduleBuilder.getSourceFiles().isEmpty()) {
|
||||
throw new CompileEnvironmentException("No source files where defined");
|
||||
}
|
||||
@@ -150,45 +133,34 @@ public class CompileEnvironment {
|
||||
|
||||
CompileEnvironmentUtil.ensureRuntime(environment, compilerDependencies);
|
||||
|
||||
if (!moduleCompileSession.analyze() && !ignoreErrors) {
|
||||
return null;
|
||||
}
|
||||
return moduleCompileSession.generate(false).getFactory();
|
||||
return analyze();
|
||||
}
|
||||
|
||||
public ClassLoader compileText(String code) {
|
||||
CompileSession session = newCompileSession();
|
||||
environment.addSources(new LightVirtualFile("script" + LocalTimeCounter.currentTime() + ".kt", JetLanguage.INSTANCE, code));
|
||||
|
||||
if (!session.analyze() && !ignoreErrors) {
|
||||
ClassFileFactory factory = analyze();
|
||||
if (factory == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClassFileFactory factory = session.generate(false).getFactory();
|
||||
return new GeneratedClassLoader(factory);
|
||||
}
|
||||
|
||||
public boolean compileBunchOfSources(String sourceFileOrDir, String jar, String outputDir, boolean includeRuntime) {
|
||||
CompileSession session = newCompileSession();
|
||||
session.setStubs(compilerDependencies.getCompilerSpecialMode().isStubs());
|
||||
|
||||
environment.addSources(sourceFileOrDir);
|
||||
|
||||
return compileBunchOfSources(jar, outputDir, includeRuntime, session);
|
||||
return compileBunchOfSources(jar, outputDir, includeRuntime);
|
||||
}
|
||||
|
||||
public boolean compileBunchOfSourceDirectories(List<String> sources, String jar, String outputDir, boolean includeRuntime) {
|
||||
CompileSession session = newCompileSession();
|
||||
session.setStubs(compilerDependencies.getCompilerSpecialMode().isStubs());
|
||||
|
||||
for (String source : sources) {
|
||||
environment.addSources(source);
|
||||
}
|
||||
|
||||
return compileBunchOfSources(jar, outputDir, includeRuntime, session);
|
||||
return compileBunchOfSources(jar, outputDir, includeRuntime);
|
||||
}
|
||||
|
||||
private boolean compileBunchOfSources(String jar, String outputDir, boolean includeRuntime, CompileSession session) {
|
||||
private boolean compileBunchOfSources(String jar, String outputDir, boolean includeRuntime) {
|
||||
FqName mainClass = null;
|
||||
for (JetFile file : environment.getSourceFiles()) {
|
||||
if (JetMainDetector.hasMain(file.getDeclarations())) {
|
||||
@@ -200,11 +172,11 @@ public class CompileEnvironment {
|
||||
|
||||
CompileEnvironmentUtil.ensureRuntime(environment, compilerDependencies);
|
||||
|
||||
if (!session.analyze() && !ignoreErrors) {
|
||||
ClassFileFactory factory = analyze();
|
||||
if (factory == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ClassFileFactory factory = session.generate(false).getFactory();
|
||||
if (jar != null) {
|
||||
try {
|
||||
CompileEnvironmentUtil.writeToJar(factory, new FileOutputStream(jar), mainClass, includeRuntime);
|
||||
@@ -221,8 +193,15 @@ public class CompileEnvironment {
|
||||
return true;
|
||||
}
|
||||
|
||||
private CompileSession newCompileSession() {
|
||||
return new CompileSession(environment, messageRenderer, errorStream, verbose, compilerDependencies);
|
||||
private ClassFileFactory analyze() {
|
||||
boolean stubs = compilerDependencies.getCompilerSpecialMode().isStubs();
|
||||
GenerationState generationState =
|
||||
KotlinToJVMBytecodeCompiler
|
||||
.analyzeAndGenerate(environment, compilerDependencies, messageCollector, stubs);
|
||||
if (generationState == null) {
|
||||
return null;
|
||||
}
|
||||
return generationState.getFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,13 +27,18 @@ 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.*;
|
||||
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;
|
||||
@@ -147,7 +152,7 @@ public class CompileEnvironmentUtil {
|
||||
// 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() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
@@ -159,14 +164,13 @@ public class CompileEnvironmentUtil {
|
||||
ensureRuntime(scriptEnvironment, dependencies);
|
||||
scriptEnvironment.addSources(moduleFile);
|
||||
|
||||
CompileSession scriptCompileSession = new CompileSession(scriptEnvironment, messageRenderer, errorStream, verbose, dependencies);
|
||||
|
||||
if (!scriptCompileSession.analyze()) {
|
||||
GenerationState generationState = KotlinToJVMBytecodeCompiler
|
||||
.analyzeAndGenerate(scriptEnvironment, dependencies, messageCollector, false);
|
||||
if (generationState == null) {
|
||||
return null;
|
||||
}
|
||||
ClassFileFactory factory = scriptCompileSession.generate(true).getFactory();
|
||||
|
||||
List<Module> modules = runDefineModules(dependencies, moduleFile, factory);
|
||||
List<Module> modules = runDefineModules(dependencies, moduleFile, generationState.getFactory());
|
||||
|
||||
Disposer.dispose(disposable);
|
||||
return modules;
|
||||
|
||||
@@ -1,181 +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.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiErrorElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.analyzer.AnalyzeExhaust;
|
||||
import org.jetbrains.jet.codegen.ClassBuilderFactories;
|
||||
import org.jetbrains.jet.codegen.CompilationErrorHandler;
|
||||
import org.jetbrains.jet.codegen.GenerationState;
|
||||
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory;
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
|
||||
import org.jetbrains.jet.lang.diagnostics.Severity;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
|
||||
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
|
||||
import org.jetbrains.jet.utils.Progress;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The session which handles analyzing and compiling a single module.
|
||||
*
|
||||
* @author yole
|
||||
*/
|
||||
public class CompileSession {
|
||||
private final JetCoreEnvironment environment;
|
||||
private final MessageCollector messageCollector;
|
||||
private boolean stubs = false;
|
||||
private final MessageRenderer messageRenderer;
|
||||
private final PrintStream errorStream;
|
||||
private final boolean verbose;
|
||||
private final CompilerDependencies compilerDependencies;
|
||||
private AnalyzeExhaust bindingContext;
|
||||
|
||||
public CompileSession(JetCoreEnvironment environment, MessageRenderer messageRenderer, PrintStream errorStream, boolean verbose,
|
||||
@NotNull CompilerDependencies compilerDependencies) {
|
||||
this.environment = environment;
|
||||
this.messageRenderer = messageRenderer;
|
||||
this.errorStream = errorStream;
|
||||
this.verbose = verbose;
|
||||
this.compilerDependencies = compilerDependencies;
|
||||
this.messageCollector = new MessageCollector(this.messageRenderer);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public AnalyzeExhaust getBindingContext() {
|
||||
return bindingContext;
|
||||
}
|
||||
|
||||
public void setStubs(boolean stubs) {
|
||||
this.stubs = stubs;
|
||||
}
|
||||
|
||||
public boolean analyze() {
|
||||
reportSyntaxErrors();
|
||||
analyzeAndReportSemanticErrors();
|
||||
|
||||
messageCollector.printTo(errorStream);
|
||||
|
||||
return !messageCollector.hasErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see JetTypeMapper#getFQName(DeclarationDescriptor)
|
||||
* TODO possibly duplicates DescriptorUtils#getFQName(DeclarationDescriptor)
|
||||
*/
|
||||
private static String fqName(ClassOrNamespaceDescriptor descriptor) {
|
||||
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
||||
if (containingDeclaration == null || containingDeclaration instanceof ModuleDescriptor || containingDeclaration.getName().equals(JavaDescriptorResolver.JAVA_ROOT)) {
|
||||
return descriptor.getName();
|
||||
}
|
||||
else {
|
||||
return fqName((ClassOrNamespaceDescriptor) containingDeclaration) + "." + descriptor.getName();
|
||||
}
|
||||
}
|
||||
|
||||
private void analyzeAndReportSemanticErrors() {
|
||||
Predicate<PsiFile> filesToAnalyzeCompletely =
|
||||
stubs ? Predicates.<PsiFile>alwaysFalse() : Predicates.<PsiFile>alwaysTrue();
|
||||
bindingContext = AnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
|
||||
environment.getProject(), environment.getSourceFiles(), filesToAnalyzeCompletely, JetControlFlowDataTraceFactory.EMPTY,
|
||||
compilerDependencies);
|
||||
|
||||
for (Diagnostic diagnostic : bindingContext.getBindingContext().getDiagnostics()) {
|
||||
reportDiagnostic(messageCollector, diagnostic);
|
||||
}
|
||||
|
||||
reportIncompleteHierarchies(messageCollector);
|
||||
}
|
||||
|
||||
private void reportIncompleteHierarchies(MessageCollector collector) {
|
||||
Collection<ClassDescriptor> incompletes = bindingContext.getBindingContext().getKeys(BindingContext.INCOMPLETE_HIERARCHY);
|
||||
if (!incompletes.isEmpty()) {
|
||||
StringBuilder message = new StringBuilder("The following classes have incomplete hierarchies:\n");
|
||||
for (ClassDescriptor incomplete : incompletes) {
|
||||
message.append(" ").append(fqName(incomplete)).append("\n");
|
||||
}
|
||||
collector.report(Severity.ERROR, message.toString(), null, -1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
private void reportSyntaxErrors() {
|
||||
for (JetFile file : environment.getSourceFiles()) {
|
||||
file.accept(new PsiRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitErrorElement(PsiErrorElement element) {
|
||||
String description = element.getErrorDescription();
|
||||
String message = StringUtil.isEmpty(description) ? "Syntax error" : description;
|
||||
Diagnostic diagnostic = DiagnosticFactory.create(Severity.ERROR, message).on(element);
|
||||
reportDiagnostic(messageCollector, diagnostic);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void reportDiagnostic(MessageCollector collector, Diagnostic diagnostic) {
|
||||
DiagnosticUtils.LineAndColumn lineAndColumn = DiagnosticUtils.getLineAndColumn(diagnostic);
|
||||
VirtualFile virtualFile = diagnostic.getPsiFile().getVirtualFile();
|
||||
String path = virtualFile == null ? null : virtualFile.getPath();
|
||||
collector.report(diagnostic.getSeverity(), diagnostic.getMessage(), path, lineAndColumn.getLine(), lineAndColumn.getColumn());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GenerationState generate(boolean module) {
|
||||
Project project = environment.getProject();
|
||||
GenerationState generationState = new GenerationState(project, ClassBuilderFactories.binaries(stubs),
|
||||
verbose ? new BackendProgress() : Progress.DEAF, bindingContext, environment.getSourceFiles(), compilerDependencies.getCompilerSpecialMode());
|
||||
generationState.compileCorrectFiles(CompilationErrorHandler.THROW_EXCEPTION);
|
||||
|
||||
List<CompilerPlugin> plugins = environment.getCompilerPlugins();
|
||||
if (!module) {
|
||||
if (plugins != null) {
|
||||
CompilerPluginContext context = new CompilerPluginContext(project, bindingContext.getBindingContext(), environment.getSourceFiles());
|
||||
for (CompilerPlugin plugin : plugins) {
|
||||
plugin.processFiles(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
return generationState;
|
||||
}
|
||||
|
||||
private class BackendProgress implements Progress {
|
||||
@Override
|
||||
public void log(String message) {
|
||||
errorStream.println(messageRenderer.render(Severity.LOGGING, message, null, -1, -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiErrorElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.analyzer.AnalyzeExhaust;
|
||||
import org.jetbrains.jet.codegen.ClassBuilderFactories;
|
||||
import org.jetbrains.jet.codegen.CompilationErrorHandler;
|
||||
import org.jetbrains.jet.codegen.GenerationState;
|
||||
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.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory;
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
|
||||
import org.jetbrains.jet.lang.diagnostics.Severity;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
|
||||
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
|
||||
import org.jetbrains.jet.utils.Progress;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
* @author abreslav
|
||||
*/
|
||||
public class KotlinToJVMBytecodeCompiler {
|
||||
|
||||
@Nullable
|
||||
public static GenerationState analyzeAndGenerate(
|
||||
JetCoreEnvironment environment,
|
||||
CompilerDependencies dependencies,
|
||||
|
||||
final MessageCollector messageCollector,
|
||||
|
||||
boolean stubs
|
||||
) {
|
||||
AnalyzeExhaust exhaust = analyze(environment, dependencies, messageCollector, stubs);
|
||||
|
||||
if (exhaust == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return generate(environment, dependencies, messageCollector, exhaust, stubs);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static AnalyzeExhaust analyze(
|
||||
JetCoreEnvironment environment,
|
||||
CompilerDependencies dependencies,
|
||||
final MessageCollector messageCollector,
|
||||
boolean stubs) {
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
// Report syntax errors
|
||||
for (JetFile file : environment.getSourceFiles()) {
|
||||
file.accept(new PsiRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitErrorElement(PsiErrorElement element) {
|
||||
String description = element.getErrorDescription();
|
||||
String message = StringUtil.isEmpty(description) ? "Syntax error" : description;
|
||||
Diagnostic diagnostic = DiagnosticFactory.create(Severity.ERROR, message).on(element);
|
||||
reportDiagnostic(messageCollectorWrapper, diagnostic);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Analyze and report semantic errors
|
||||
Predicate<PsiFile> filesToAnalyzeCompletely =
|
||||
stubs ? Predicates.<PsiFile>alwaysFalse() : Predicates.<PsiFile>alwaysTrue();
|
||||
AnalyzeExhaust exhaust = AnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
|
||||
environment.getProject(), environment.getSourceFiles(), filesToAnalyzeCompletely, JetControlFlowDataTraceFactory.EMPTY,
|
||||
dependencies);
|
||||
|
||||
for (Diagnostic diagnostic : exhaust.getBindingContext().getDiagnostics()) {
|
||||
reportDiagnostic(messageCollectorWrapper, diagnostic);
|
||||
}
|
||||
|
||||
reportIncompleteHierarchies(messageCollectorWrapper, exhaust);
|
||||
|
||||
return hasErrors.get() ? null : exhaust;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static GenerationState generate(
|
||||
JetCoreEnvironment environment,
|
||||
CompilerDependencies dependencies,
|
||||
|
||||
final MessageCollector messageCollector,
|
||||
|
||||
AnalyzeExhaust exhaust,
|
||||
|
||||
boolean stubs) {
|
||||
Project project = environment.getProject();
|
||||
Progress backendProgress = new Progress() {
|
||||
@Override
|
||||
public void log(String message) {
|
||||
messageCollector.report(CompilerMessageSeverity.LOGGING, message, CompilerMessageLocation.NO_LOCATION);
|
||||
}
|
||||
};
|
||||
GenerationState generationState = new GenerationState(project, ClassBuilderFactories.binaries(stubs), backendProgress,
|
||||
exhaust, environment.getSourceFiles(), dependencies.getCompilerSpecialMode());
|
||||
generationState.compileCorrectFiles(CompilationErrorHandler.THROW_EXCEPTION);
|
||||
|
||||
List<CompilerPlugin> plugins = environment.getCompilerPlugins();
|
||||
if (plugins != null) {
|
||||
CompilerPluginContext context = new CompilerPluginContext(project, exhaust.getBindingContext(), environment.getSourceFiles());
|
||||
for (CompilerPlugin plugin : plugins) {
|
||||
plugin.processFiles(context);
|
||||
}
|
||||
}
|
||||
return generationState;
|
||||
}
|
||||
|
||||
private static void reportDiagnostic(MessageCollector collector, Diagnostic diagnostic) {
|
||||
DiagnosticUtils.LineAndColumn lineAndColumn = DiagnosticUtils.getLineAndColumn(diagnostic);
|
||||
VirtualFile virtualFile = diagnostic.getPsiFile().getVirtualFile();
|
||||
String path = virtualFile == null ? null : virtualFile.getPath();
|
||||
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) {
|
||||
Collection<ClassDescriptor> incompletes = exhaust.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");
|
||||
}
|
||||
collector.report(CompilerMessageSeverity.ERROR, message.toString(), CompilerMessageLocation.NO_LOCATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+15
-19
@@ -14,11 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.compiler;
|
||||
package org.jetbrains.jet.compiler.messages;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.diagnostics.Severity;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
@@ -29,48 +27,46 @@ import java.io.StringWriter;
|
||||
public interface 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();
|
||||
out.append("<").append(severityString);
|
||||
if (path != null) {
|
||||
out.append(" path=\"").append(path).append("\"");
|
||||
out.append(" line=\"").append(line).append("\"");
|
||||
out.append(" column=\"").append(column).append("\"");
|
||||
out.append("<").append(severity.toString());
|
||||
if (location.getPath() != null) {
|
||||
out.append(" path=\"").append(location.getPath()).append("\"");
|
||||
out.append(" line=\"").append(location.getLine()).append("\"");
|
||||
out.append(" column=\"").append(location.getColumn()).append("\"");
|
||||
}
|
||||
out.append(">\n");
|
||||
|
||||
out.append(message);
|
||||
|
||||
out.append("</").append(severityString).append(">\n");
|
||||
out.append("</").append(severity.toString()).append(">\n");
|
||||
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
|
||||
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() {
|
||||
@Override
|
||||
public String render(@NotNull Severity severity, @NotNull String message, @Nullable String path, int line, int column) {
|
||||
String position = path == null ? "" : path + ": (" + (line + ", " + column) + ") ";
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
+4
-2
@@ -1616,8 +1616,10 @@ public class JavaDescriptorResolver {
|
||||
PsiAnnotationParameterList parameterList = psiAnnotation.getParameterList();
|
||||
for (PsiNameValuePair psiNameValuePair : parameterList.getAttributes()) {
|
||||
PsiAnnotationMemberValue value = psiNameValuePair.getValue();
|
||||
// todo
|
||||
assert value instanceof PsiLiteralExpression;
|
||||
if (!(value instanceof PsiLiteralExpression)) {
|
||||
// todo
|
||||
continue;
|
||||
}
|
||||
Object literalValue = ((PsiLiteralExpression) value).getValue();
|
||||
if(literalValue instanceof String)
|
||||
valueArguments.add(new StringValue((String) literalValue));
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.lang.resolve.java;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.core.CoreJavaFileManager;
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElementFinder;
|
||||
import com.intellij.psi.PsiPackage;
|
||||
import com.intellij.psi.impl.JavaPsiFacadeImpl;
|
||||
import com.intellij.psi.impl.file.impl.JavaFileManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* TODO Temporary class until {@link JavaPsiFacadeImpl} hacked.
|
||||
*
|
||||
* @author Stepan Koltsov
|
||||
*
|
||||
* @see JavaPsiFacadeImpl
|
||||
*/
|
||||
public class JavaPsiFacadeKotlinHacks {
|
||||
public interface KotlinFinderMarker {}
|
||||
|
||||
private final JavaFileManager javaFileManager;
|
||||
private final List<PsiElementFinder> extensionPsiElementFinders;
|
||||
|
||||
public JavaPsiFacadeKotlinHacks(@NotNull Project project) {
|
||||
this.javaFileManager = findJavaFileManager(project);
|
||||
this.extensionPsiElementFinders = Lists.newArrayList();
|
||||
for (PsiElementFinder finder : project.getExtensions(PsiElementFinder.EP_NAME)) {
|
||||
if (!(finder instanceof KotlinFinderMarker)) {
|
||||
this.extensionPsiElementFinders.add(finder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JavaFileManager findJavaFileManager(@NotNull Project project) {
|
||||
JavaFileManager javaFileManager = project.getComponent(JavaFileManager.class);
|
||||
if (javaFileManager != null) {
|
||||
return javaFileManager;
|
||||
}
|
||||
javaFileManager = project.getComponent(CoreJavaFileManager.class);
|
||||
if (javaFileManager != null) {
|
||||
// TODO: why it is not found by JavaFileManager?
|
||||
return javaFileManager;
|
||||
}
|
||||
throw new IllegalStateException("JavaFileManager component is not found in project");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiPackage findPackage(@NotNull String qualifiedName) {
|
||||
PsiPackage psiPackage = javaFileManager.findPackage(qualifiedName);
|
||||
if (psiPackage != null) {
|
||||
return psiPackage;
|
||||
}
|
||||
|
||||
for (PsiElementFinder finder : extensionPsiElementFinders) {
|
||||
psiPackage = finder.findPackage(qualifiedName);
|
||||
if (psiPackage != null) {
|
||||
return psiPackage;
|
||||
}
|
||||
}
|
||||
return psiPackage;
|
||||
}
|
||||
|
||||
public PsiClass findClass(@NotNull final String qualifiedName, @NotNull GlobalSearchScope scope) {
|
||||
ProgressIndicatorProvider.checkCanceled(); // We hope this method is being called often enough to cancel daemon processes smoothly
|
||||
|
||||
PsiClass aClass = javaFileManager.findClass(qualifiedName, scope);
|
||||
if (aClass != null) {
|
||||
return aClass;
|
||||
}
|
||||
|
||||
for (PsiElementFinder finder : extensionPsiElementFinders) {
|
||||
aClass = finder.findClass(qualifiedName, scope);
|
||||
if (aClass != null) {
|
||||
return aClass;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-4
@@ -18,7 +18,6 @@ package org.jetbrains.jet.lang.resolve.java;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiAnnotation;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiPackage;
|
||||
@@ -46,7 +45,7 @@ public class PsiClassFinderForJvm implements PsiClassFinder {
|
||||
|
||||
private AltClassFinder altClassFinder;
|
||||
private GlobalSearchScope javaSearchScope;
|
||||
private JavaPsiFacade javaFacade;
|
||||
private JavaPsiFacadeKotlinHacks javaFacade;
|
||||
|
||||
@Inject
|
||||
public void setProject(@NotNull Project project) {
|
||||
@@ -67,7 +66,7 @@ public class PsiClassFinderForJvm implements PsiClassFinder {
|
||||
return myBaseScope.contains(file) && file.getFileType() != JetFileType.INSTANCE;
|
||||
}
|
||||
};
|
||||
this.javaFacade = JavaPsiFacade.getInstance(project);
|
||||
this.javaFacade = new JavaPsiFacadeKotlinHacks(project);
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +92,7 @@ public class PsiClassFinderForJvm implements PsiClassFinder {
|
||||
}
|
||||
|
||||
if (result instanceof JetJavaMirrorMarker) {
|
||||
return null;
|
||||
throw new IllegalStateException("JetJavaMirrorMaker is not possible in resolve.java, resolving: " + qualifiedName);
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
|
||||
@@ -20,7 +20,6 @@ package org.jetbrains.jet.lang.diagnostics;
|
||||
* @author abreslav
|
||||
*/
|
||||
public enum Severity {
|
||||
LOGGING,
|
||||
INFO,
|
||||
ERROR,
|
||||
WARNING
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.DeferredType;
|
||||
@@ -32,7 +33,6 @@ import org.jetbrains.jet.util.Box;
|
||||
import org.jetbrains.jet.util.slicedmap.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.jet.util.slicedmap.RewritePolicy.DO_NOTHING;
|
||||
|
||||
@@ -63,6 +63,9 @@ public interface BindingContext {
|
||||
/** A scope where type of expression has been resolved */
|
||||
WritableSlice<JetExpression, JetScope> RESOLUTION_SCOPE = Slices.createSimpleSlice();
|
||||
|
||||
/** Collected during analyze, used in IDE in auto-cast completion */
|
||||
WritableSlice<JetExpression, DataFlowInfo> NON_DEFAULT_EXPRESSION_DATA_FLOW = Slices.createSimpleSlice();
|
||||
|
||||
WritableSlice<JetExpression, Boolean> VARIABLE_REASSIGNMENT = Slices.createSimpleSetSlice();
|
||||
WritableSlice<ValueParameterDescriptor, Boolean> AUTO_CREATED_IT = Slices.createSimpleSetSlice();
|
||||
WritableSlice<JetExpression, DeclarationDescriptor> VARIABLE_ASSIGNMENT = Slices.createSimpleSlice();
|
||||
|
||||
@@ -358,7 +358,9 @@ public class BodyResolver {
|
||||
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
|
||||
JetTypeReference typeReference = call.getTypeReference();
|
||||
if (typeReference != null) {
|
||||
callResolver.resolveFunctionCall(trace, scopeForSupertypeInitializers, CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE, dataFlowInfo);
|
||||
callResolver.resolveFunctionCall(trace, scopeForSupertypeInitializers,
|
||||
CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call),
|
||||
NO_EXPECTED_TYPE, dataFlowInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,10 @@ import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemWithPriorities;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.DebugConstraintResolutionListener;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
@@ -42,8 +45,7 @@ import javax.inject.Inject;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLUTION_SCOPE;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.ResolutionStatus.*;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_CANDIDATE;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_RESULT;
|
||||
@@ -255,6 +257,10 @@ public class CallResolver {
|
||||
context.trace.record(ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, context.call.getCallElement(), debugInfo);
|
||||
context.trace.record(RESOLUTION_SCOPE, context.call.getCalleeExpression(), context.scope);
|
||||
|
||||
if (context.dataFlowInfo.hasTypeInfoConstraints()) {
|
||||
context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, context.call.getCalleeExpression(), context.dataFlowInfo);
|
||||
}
|
||||
|
||||
debugInfo.set(ResolutionDebugInfo.TASKS, prioritizedTasks);
|
||||
|
||||
TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null;
|
||||
|
||||
+6
-2
@@ -36,7 +36,10 @@ public class AutoCastUtils {
|
||||
/**
|
||||
* @return variants @param receiverToCast may be cast to according to @param dataFlowInfo, @param receiverToCast itself is NOT included
|
||||
*/
|
||||
public static List<ReceiverDescriptor> getAutoCastVariants(@NotNull final BindingContext bindingContext, @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast) {
|
||||
public static List<ReceiverDescriptor> getAutoCastVariants(
|
||||
@NotNull final BindingContext bindingContext,
|
||||
@NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast
|
||||
) {
|
||||
return receiverToCast.accept(new ReceiverDescriptorVisitor<List<ReceiverDescriptor>, Object>() {
|
||||
@Override
|
||||
public List<ReceiverDescriptor> visitNoReceiver(ReceiverDescriptor noReceiver, Object data) {
|
||||
@@ -72,7 +75,8 @@ public class AutoCastUtils {
|
||||
// else if (expression instanceof JetThisExpression) {
|
||||
// return castThis(dataFlowInfo, receiver);
|
||||
// }
|
||||
DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(receiver.getExpression(),receiver.getType(), bindingContext);
|
||||
DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(receiver.getExpression(),receiver.getType(),
|
||||
bindingContext);
|
||||
List<ReceiverDescriptor> result = Lists.newArrayList();
|
||||
for (JetType possibleType : dataFlowInfo.getPossibleTypes(dataFlowValue)) {
|
||||
result.add(new AutoCastReceiver(receiver, possibleType, dataFlowValue.isStableIdentifier()));
|
||||
|
||||
+7
-1
@@ -50,7 +50,9 @@ public class DataFlowInfo {
|
||||
}
|
||||
};
|
||||
|
||||
public static DataFlowInfo EMPTY = new DataFlowInfo(ImmutableMap.<DataFlowValue, Nullability>of(), Multimaps.newListMultimap(Collections.<DataFlowValue, Collection<JetType>>emptyMap(), CommonSuppliers.<JetType>getArrayListSupplier()));
|
||||
public static DataFlowInfo EMPTY = new DataFlowInfo(
|
||||
ImmutableMap.<DataFlowValue, Nullability>of(),
|
||||
Multimaps.newListMultimap(Collections.<DataFlowValue, Collection<JetType>>emptyMap(), CommonSuppliers.<JetType>getArrayListSupplier()));
|
||||
|
||||
private final ImmutableMap<DataFlowValue, Nullability> nullabilityInfo;
|
||||
/** Also immutable */
|
||||
@@ -195,6 +197,10 @@ public class DataFlowInfo {
|
||||
return new DataFlowInfo(ImmutableMap.copyOf(builder), newTypeInfo);
|
||||
}
|
||||
|
||||
public boolean hasTypeInfoConstraints() {
|
||||
return !typeInfo.isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//public class DataFlowInfo {
|
||||
|
||||
+8
@@ -617,6 +617,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
temporaryTrace.commit();
|
||||
return null;
|
||||
}
|
||||
|
||||
// Uncommitted changes in temp context
|
||||
context.trace.record(RESOLUTION_SCOPE, nameExpression, context.scope);
|
||||
if (context.dataFlowInfo.hasTypeInfoConstraints()) {
|
||||
context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, nameExpression, context.dataFlowInfo);
|
||||
}
|
||||
|
||||
ExpressionTypingContext newContext = receiver.exists()
|
||||
? context.replaceScope(receiver.getType().getMemberScope())
|
||||
: context;
|
||||
@@ -624,6 +631,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
if (jetType == null) {
|
||||
context.trace.report(UNRESOLVED_REFERENCE.on(nameExpression));
|
||||
}
|
||||
|
||||
return jetType;
|
||||
}
|
||||
else if (selectorExpression instanceof JetQualifiedExpression) {
|
||||
|
||||
+5
-2
@@ -59,7 +59,8 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
||||
JetPattern pattern = expression.getPattern();
|
||||
if (pattern != null) {
|
||||
WritableScopeImpl scopeToExtend = newWritableScopeImpl(context).setDebugName("Scope extended in 'is'");
|
||||
DataFlowInfo newDataFlowInfo = checkPatternType(pattern, knownType, false, scopeToExtend, context, DataFlowValueFactory.INSTANCE.createDataFlowValue(leftHandSide, knownType, context.trace.getBindingContext()));
|
||||
DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(leftHandSide, knownType, context.trace.getBindingContext());
|
||||
DataFlowInfo newDataFlowInfo = checkPatternType(pattern, knownType, false, scopeToExtend, context, dataFlowValue);
|
||||
context.patternsToDataFlowInfo.put(pattern, newDataFlowInfo);
|
||||
context.patternsToBoundVariableLists.put(pattern, scopeToExtend.getDeclaredVariables());
|
||||
}
|
||||
@@ -175,7 +176,9 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
||||
return newDataFlowInfo[0];
|
||||
}
|
||||
|
||||
private DataFlowInfo checkPatternType(@NotNull JetPattern pattern, @NotNull final JetType subjectType, final boolean conditionExpected, @NotNull final WritableScope scopeToExtend, final ExpressionTypingContext context, @NotNull final DataFlowValue... subjectVariables) {
|
||||
private DataFlowInfo checkPatternType(@NotNull JetPattern pattern, @NotNull final JetType subjectType, final boolean conditionExpected,
|
||||
@NotNull final WritableScope scopeToExtend, final ExpressionTypingContext context, @NotNull final DataFlowValue... subjectVariables
|
||||
) {
|
||||
final Ref<DataFlowInfo> result = new Ref<DataFlowInfo>(context.dataFlowInfo);
|
||||
pattern.accept(new JetVisitorVoid() {
|
||||
@Override
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaPsiFacadeKotlinHacks;
|
||||
import org.jetbrains.jet.lang.resolve.java.JetFilesProvider;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.util.QualifiedNamesUtil;
|
||||
@@ -41,7 +42,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class JavaElementFinder extends PsiElementFinder {
|
||||
public class JavaElementFinder extends PsiElementFinder implements JavaPsiFacadeKotlinHacks.KotlinFinderMarker {
|
||||
private final Project project;
|
||||
private final PsiManager psiManager;
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.jet.CompileCompilerDependenciesTest;
|
||||
import org.jetbrains.jet.compiler.CompileEnvironment;
|
||||
import org.jetbrains.jet.compiler.messages.MessageCollector;
|
||||
import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@@ -26,7 +27,7 @@ import java.lang.reflect.Method;
|
||||
public class CompileTextTest extends CodegenTestCase {
|
||||
public void testMe() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||
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());
|
||||
ClassLoader classLoader = compileEnvironment.compileText(text);
|
||||
Class<?> namespace = classLoader.loadClass("namespace");
|
||||
|
||||
@@ -23,8 +23,8 @@ import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import org.jetbrains.jet.CompileCompilerDependenciesTest;
|
||||
import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileRuntime;
|
||||
import org.jetbrains.jet.compiler.CompileSession;
|
||||
import org.jetbrains.jet.compiler.MessageRenderer;
|
||||
import org.jetbrains.jet.compiler.KotlinToJVMBytecodeCompiler;
|
||||
import org.jetbrains.jet.compiler.messages.MessageCollector;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetClass;
|
||||
import org.jetbrains.jet.lang.psi.JetDeclaration;
|
||||
@@ -37,6 +37,7 @@ import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.parsing.JetParsingTest;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
@@ -74,10 +75,8 @@ public class TestlibTest extends CodegenTestCase {
|
||||
|
||||
private TestSuite doBuildSuite() {
|
||||
try {
|
||||
PrintStream err = System.err;
|
||||
CompilerDependencies compilerDependencies = CompileCompilerDependenciesTest.compilerDependenciesForTests(CompilerSpecialMode.REGULAR);
|
||||
CompileSession session = new CompileSession(myEnvironment, MessageRenderer.PLAIN, System.err, false,
|
||||
compilerDependencies);
|
||||
|
||||
File junitJar = new File("libraries/lib/junit-4.9.jar");
|
||||
|
||||
if (!junitJar.exists()) {
|
||||
@@ -92,19 +91,21 @@ public class TestlibTest extends CodegenTestCase {
|
||||
myEnvironment.addSources(localFileSystem.findFileByPath(JetParsingTest.getTestDataDir() + "/../../libraries/stdlib/test"));
|
||||
myEnvironment.addSources(localFileSystem.findFileByPath(JetParsingTest.getTestDataDir() + "/../../libraries/kunit/src"));
|
||||
|
||||
if (!session.analyze()) {
|
||||
GenerationState generationState = KotlinToJVMBytecodeCompiler
|
||||
.analyzeAndGenerate(myEnvironment, compilerDependencies, MessageCollector.PLAIN_TEXT_TO_SYSTEM_ERR, false);
|
||||
|
||||
if (generationState == null) {
|
||||
throw new RuntimeException("There were compilation errors");
|
||||
}
|
||||
|
||||
GenerationState state = session.generate(false);
|
||||
ClassFileFactory classFileFactory = state.getFactory();
|
||||
ClassFileFactory classFileFactory = generationState.getFactory();
|
||||
|
||||
final GeneratedClassLoader loader = new GeneratedClassLoader(
|
||||
classFileFactory,
|
||||
new URLClassLoader(new URL[]{ForTestCompileRuntime.runtimeJarForTests().toURI().toURL(), junitJar.toURI().toURL()},
|
||||
TestCase.class.getClassLoader()));
|
||||
|
||||
JetTypeMapper typeMapper = state.getInjector().getJetTypeMapper();
|
||||
JetTypeMapper typeMapper = generationState.getInjector().getJetTypeMapper();
|
||||
TestSuite suite = new TestSuite("stdlib_test");
|
||||
try {
|
||||
for(JetFile jetFile : myEnvironment.getSourceFiles()) {
|
||||
@@ -112,7 +113,7 @@ public class TestlibTest extends CodegenTestCase {
|
||||
if(decl instanceof JetClass) {
|
||||
JetClass jetClass = (JetClass) decl;
|
||||
|
||||
ClassDescriptor descriptor = (ClassDescriptor) session.getBindingContext().getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, jetClass);
|
||||
ClassDescriptor descriptor = (ClassDescriptor) generationState.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, jetClass);
|
||||
Set<JetType> allSuperTypes = new THashSet<JetType>();
|
||||
DescriptorUtils.addSuperTypes(descriptor.getDefaultType(), allSuperTypes);
|
||||
|
||||
|
||||
@@ -18,11 +18,9 @@ package org.jetbrains.jet.compiler;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import junit.framework.TestCase;
|
||||
import org.jetbrains.jet.CompileCompilerDependenciesTest;
|
||||
import org.jetbrains.jet.cli.KotlinCompiler;
|
||||
import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileJdkHeaders;
|
||||
import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileRuntime;
|
||||
import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode;
|
||||
import org.jetbrains.jet.parsing.JetParsingTest;
|
||||
import org.junit.Assert;
|
||||
|
||||
@@ -47,11 +45,11 @@ public class CompileEnvironmentTest extends TestCase {
|
||||
File stdlib = ForTestCompileRuntime.runtimeJarForTests();
|
||||
File jdkHeaders = ForTestCompileJdkHeaders.jdkHeadersForTests();
|
||||
File resultJar = new File(tempDir, "result.jar");
|
||||
KotlinCompiler.ExitCode rv = new KotlinCompiler().exec(
|
||||
"-module", JetParsingTest.getTestDataDir() + "/compiler/smoke/Smoke.kts",
|
||||
"-jar", resultJar.getAbsolutePath(),
|
||||
"-stdlib", stdlib.getAbsolutePath(),
|
||||
"-jdkHeaders", jdkHeaders.getAbsolutePath());
|
||||
KotlinCompiler.ExitCode rv = new KotlinCompiler().exec(System.out,
|
||||
"-module", JetParsingTest.getTestDataDir() + "/compiler/smoke/Smoke.kts",
|
||||
"-jar", resultJar.getAbsolutePath(),
|
||||
"-stdlib", stdlib.getAbsolutePath(),
|
||||
"-jdkHeaders", jdkHeaders.getAbsolutePath());
|
||||
Assert.assertEquals("compilation completed with non-zero code", KotlinCompiler.ExitCode.OK, rv);
|
||||
FileInputStream fileInputStream = new FileInputStream(resultJar);
|
||||
try {
|
||||
@@ -80,11 +78,9 @@ public class CompileEnvironmentTest extends TestCase {
|
||||
File out = new File(tempDir, "out");
|
||||
File stdlib = ForTestCompileRuntime.runtimeJarForTests();
|
||||
File jdkHeaders = ForTestCompileJdkHeaders.jdkHeadersForTests();
|
||||
KotlinCompiler.ExitCode exitCode = new KotlinCompiler().exec(
|
||||
"-src", JetParsingTest.getTestDataDir() + "/compiler/smoke/Smoke.kt",
|
||||
"-output", out.getAbsolutePath(),
|
||||
"-stdlib", stdlib.getAbsolutePath(),
|
||||
"-jdkHeaders", jdkHeaders.getAbsolutePath());
|
||||
KotlinCompiler.ExitCode exitCode = new KotlinCompiler()
|
||||
.exec(System.out, "-src", JetParsingTest.getTestDataDir() + "/compiler/smoke/Smoke.kt", "-output",
|
||||
out.getAbsolutePath(), "-stdlib", stdlib.getAbsolutePath(), "-jdkHeaders", jdkHeaders.getAbsolutePath());
|
||||
Assert.assertEquals(KotlinCompiler.ExitCode.OK, exitCode);
|
||||
assertEquals(1, out.listFiles().length);
|
||||
assertEquals(1, out.listFiles()[0].listFiles().length);
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
<orderEntry type="library" scope="PROVIDED" name="junit-plugin" level="project" />
|
||||
<orderEntry type="module" module-name="j2k" />
|
||||
<orderEntry type="module" module-name="js.translator" />
|
||||
<orderEntry type="module" module-name="cli" />
|
||||
<orderEntry type="module" module-name="cli" scope="TEST" />
|
||||
<orderEntry type="module" module-name="js.tests" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
@@ -42,7 +42,6 @@ import com.intellij.util.Chunk;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.diagnostics.Severity;
|
||||
import org.jetbrains.jet.plugin.JetFileType;
|
||||
import org.jetbrains.jet.utils.PathUtil;
|
||||
|
||||
@@ -446,15 +445,17 @@ public class JetCompiler implements TranslatingCompiler {
|
||||
private String message;
|
||||
|
||||
public void setMessageCategoryFromString(String tagName) {
|
||||
boolean exception = "EXCEPTION".equals(tagName);
|
||||
if (Severity.ERROR.toString().equals(tagName) || exception) {
|
||||
if ("ERROR".equals(tagName)) {
|
||||
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;
|
||||
}
|
||||
else if (Severity.LOGGING.toString().equals(tagName)) {
|
||||
else if ("LOGGING".equals(tagName)) {
|
||||
messageCategory = STATISTICS;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
trait Expr
|
||||
class Num(val value : Int) : Expr
|
||||
|
||||
fun eval(e : Expr) {
|
||||
if (e is Num) {
|
||||
return e.<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: value
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
class Expr {}
|
||||
class Num : Expr() {
|
||||
fun testing() {}
|
||||
}
|
||||
|
||||
fun eval(e : Expr) {
|
||||
if (e is Num) {
|
||||
return e.<caret>()
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: testing
|
||||
@@ -0,0 +1,11 @@
|
||||
trait Expr {
|
||||
public fun testThis() {
|
||||
if (this is Num) {
|
||||
this.<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Num(val toCheck : Int) : Expr
|
||||
|
||||
// EXIST: toCheck
|
||||
@@ -0,0 +1,8 @@
|
||||
trait Expr
|
||||
class Sum(val left : Expr, val right : Expr) : Expr
|
||||
|
||||
fun evalWhen(e : Expr) : Int = when (e) {
|
||||
is Sum -> e.<caret>
|
||||
}
|
||||
|
||||
// EXIST: left, right
|
||||
@@ -0,0 +1,11 @@
|
||||
class TestClass {
|
||||
public fun testMethod() {
|
||||
}
|
||||
}
|
||||
|
||||
fun testFun() {
|
||||
val lambda = {() -> TestClass() }
|
||||
lambda().<caret>
|
||||
}
|
||||
|
||||
// EXIST: testMethod
|
||||
@@ -1,13 +1,13 @@
|
||||
package something
|
||||
|
||||
class SomeTempClass {
|
||||
fun testSome() {
|
||||
fun helloWorld() {
|
||||
|
||||
}
|
||||
|
||||
fun test() {
|
||||
test<caret>()
|
||||
hello<caret>()
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: test, testSome
|
||||
// EXIST: helloWorld
|
||||
@@ -25,6 +25,22 @@ import java.io.File;
|
||||
*/
|
||||
public class JetBasicCompletionTest extends JetCompletionTestBase {
|
||||
|
||||
public void testAutoCastAfterIf() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAutoCastAfterIfMethod() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAutoCastForThis() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAutoCastInWhen() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testBasicAny() {
|
||||
doTest();
|
||||
}
|
||||
@@ -37,6 +53,10 @@ public class JetBasicCompletionTest extends JetCompletionTestBase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testCallLocalLambda() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testExtendClassName() {
|
||||
doTest();
|
||||
}
|
||||
@@ -101,7 +121,7 @@ public class JetBasicCompletionTest extends JetCompletionTestBase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNoCLassNameDuplication() {
|
||||
public void testNoClassNameDuplication() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,8 @@ public abstract class AbstractLibrariesTest extends PlatformTestCase {
|
||||
});
|
||||
librarySourceDir = LocalFileSystem.getInstance().findFileByPath(TEST_DATA_PATH + "/library");
|
||||
assertNotNull(librarySourceDir);
|
||||
KotlinCompiler.ExitCode compilerExec = new KotlinCompiler().exec("-src", librarySourceDir.getPath(), "-output", libraryIoDir.getAbsolutePath());
|
||||
KotlinCompiler.ExitCode compilerExec =
|
||||
new KotlinCompiler().exec(System.out, "-src", librarySourceDir.getPath(), "-output", libraryIoDir.getAbsolutePath());
|
||||
assertEquals(KotlinCompiler.ExitCode.OK, compilerExec);
|
||||
libraryDir = LocalFileSystem.getInstance().findFileByIoFile(libraryIoDir);
|
||||
assertNotNull(libraryDir);
|
||||
|
||||
@@ -49,8 +49,29 @@
|
||||
<ignorePackage>jet</ignorePackage>
|
||||
<ignorePackage>junit</ignorePackage>
|
||||
<ignorePackage>org</ignorePackage>
|
||||
<ignorePackage>kotlin.support</ignorePackage>
|
||||
<ignorePackage>kotlin.properties</ignorePackage>
|
||||
</ignorePackages>
|
||||
|
||||
<sourceRootHref>https://github.com/JetBrains/kotlin/tree/master</sourceRootHref>
|
||||
<projectRootDir>${project-root}</projectRootDir>
|
||||
<packageDescriptionFiles>
|
||||
<kotlin.swing>${project-root}/libraries/kotlin-swing/ReadMe.md</kotlin.swing>
|
||||
</packageDescriptionFiles>
|
||||
<packageSummaryText>
|
||||
<kotlin>Core API</kotlin>
|
||||
<kotlin.beans>Functions for working with Java Beans</kotlin.beans>
|
||||
<kotlin.concurrent>Concurrent programing API</kotlin.concurrent>
|
||||
<kotlin.dom>Functions for working with the W3C DOM</kotlin.dom>
|
||||
<kotlin.io>IO API for working with files and streams</kotlin.io>
|
||||
<kotlin.jdbc>Functions for working with SQL databases via JDBC (in kotlin-jdbc module)</kotlin.jdbc>
|
||||
<kotlin.math>Mathematics API</kotlin.math>
|
||||
<kotlin.modules>API for defining compilation units</kotlin.modules>
|
||||
<kotlin.nullable>Functions for treating nullable types as composable collections of zero or one element</kotlin.nullable>
|
||||
<kotlin.swing>Swing API (in kotlin-swing module)</kotlin.swing>
|
||||
<kotlin.template>Text processing API</kotlin.template>
|
||||
<kotlin.test>Functions for writing tests (in kunit module)</kotlin.test>
|
||||
<kotlin.util>Utility functions</kotlin.util>
|
||||
</packageSummaryText>
|
||||
</configuration>
|
||||
|
||||
<executions>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// This execute once the document loads.
|
||||
$(function(){
|
||||
$("div.source-detail").hide();
|
||||
$("div.doc-member").hover(
|
||||
function() { $(this).children("div.source-detail").show(); },
|
||||
function() { $(this).children("div.source-detail").hide(); }
|
||||
);
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
@@ -117,3 +117,10 @@ th, table { border-collapse:collapse;border-color: #E6E7E8; }
|
||||
|
||||
.NavBarCell2 { background-color:#FFFFFF;}
|
||||
.NavBarCell3 { background-color:#FFFFFF;}
|
||||
|
||||
div.doc-member.function {
|
||||
border-bottom: 1px solid #E6E7E8;
|
||||
}
|
||||
div.source-detail {
|
||||
float:right;
|
||||
}
|
||||
@@ -4,6 +4,7 @@ The Kotlin Swing library provides some helper functions and extensions for creat
|
||||
|
||||
To try the sample run
|
||||
|
||||
cd kotlin/libraries/kotlin-swing
|
||||
mvn test -Pui
|
||||
|
||||
Or browse the [source of the sample](https://github.com/JetBrains/kotlin/blob/master/libraries/kotlin-swing/src/test/kotlin/test/kotlin/swing/SwingSample.kt)
|
||||
|
||||
@@ -44,10 +44,8 @@ abstract class Tag(val name : String) : Element() {
|
||||
builder.append("<")
|
||||
builder.append(name)
|
||||
if (!attributes.isEmpty()) {
|
||||
for (e in attributes.entrySet()) {
|
||||
if (e != null) {
|
||||
builder.append(" ${e.getKey()}=\"${e.getValue()}\"")
|
||||
}
|
||||
for (e in attributes) {
|
||||
builder.append(" ${e.key}=\"${e.value}\"")
|
||||
}
|
||||
}
|
||||
if (children.isEmpty()) {
|
||||
|
||||
@@ -141,11 +141,18 @@ public inline fun <T> Array<T>.fold(initial: T, operation: (T, T) -> T): T {
|
||||
public inline fun <T> Array<T>.foldRight(initial: T, operation: (T, T) -> T): T = reverse().fold(initial, operation)
|
||||
|
||||
/**
|
||||
* Transforms each element using the result as the key in a map to group elements by the result
|
||||
* Groups the elements in the collection into a new [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
|
||||
*
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt groupBy
|
||||
*/
|
||||
public inline fun <T, K> Array<T>.groupBy(result: Map<K, List<T>> = HashMap<K, List<T>>(), toKey: (T) -> K) : Map<K, List<T>> {
|
||||
public inline fun <T, K> Array<T>.groupBy(toKey: (T) -> K) : Map<K, List<T>> = groupByTo<T,K>(HashMap<K, List<T>>(), toKey)
|
||||
|
||||
/**
|
||||
* Groups the elements in the collection into the given [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
|
||||
*
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt groupBy
|
||||
*/
|
||||
public inline fun <T, K> Array<T>.groupByTo(result: Map<K, List<T>>, toKey: (T) -> K) : Map<K, List<T>> {
|
||||
for (element in this) {
|
||||
val key = toKey(element)
|
||||
val list = result.getOrPut(key) { ArrayList<T>() }
|
||||
@@ -160,7 +167,7 @@ public inline fun <T, K> Array<T>.groupBy(result: Map<K, List<T>> = HashMap<K, L
|
||||
* If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will
|
||||
* a special *truncated* separator (which defaults to "..."
|
||||
*
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt appendString
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt makeString
|
||||
*/
|
||||
public inline fun <T> Array<T>.makeString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): String {
|
||||
val buffer = StringBuilder()
|
||||
|
||||
@@ -139,11 +139,18 @@ public inline fun <T> java.util.Iterator<T>.fold(initial: T, operation: (T, T) -
|
||||
public inline fun <T> java.util.Iterator<T>.foldRight(initial: T, operation: (T, T) -> T): T = reverse().fold(initial, operation)
|
||||
|
||||
/**
|
||||
* Transforms each element using the result as the key in a map to group elements by the result
|
||||
* Groups the elements in the collection into a new [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
|
||||
*
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt groupBy
|
||||
*/
|
||||
public inline fun <T, K> java.util.Iterator<T>.groupBy(result: Map<K, List<T>> = HashMap<K, List<T>>(), toKey: (T) -> K) : Map<K, List<T>> {
|
||||
public inline fun <T, K> java.util.Iterator<T>.groupBy(toKey: (T) -> K) : Map<K, List<T>> = groupByTo<T,K>(HashMap<K, List<T>>(), toKey)
|
||||
|
||||
/**
|
||||
* Groups the elements in the collection into the given [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
|
||||
*
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt groupBy
|
||||
*/
|
||||
public inline fun <T, K> java.util.Iterator<T>.groupByTo(result: Map<K, List<T>>, toKey: (T) -> K) : Map<K, List<T>> {
|
||||
for (element in this) {
|
||||
val key = toKey(element)
|
||||
val list = result.getOrPut(key) { ArrayList<T>() }
|
||||
@@ -158,7 +165,7 @@ public inline fun <T, K> java.util.Iterator<T>.groupBy(result: Map<K, List<T>> =
|
||||
* If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will
|
||||
* a special *truncated* separator (which defaults to "..."
|
||||
*
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt appendString
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt makeString
|
||||
*/
|
||||
public inline fun <T> java.util.Iterator<T>.makeString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): String {
|
||||
val buffer = StringBuilder()
|
||||
|
||||
@@ -141,11 +141,18 @@ public inline fun <T> Iterable<T>.fold(initial: T, operation: (T, T) -> T): T {
|
||||
public inline fun <T> Iterable<T>.foldRight(initial: T, operation: (T, T) -> T): T = reverse().fold(initial, operation)
|
||||
|
||||
/**
|
||||
* Transforms each element using the result as the key in a map to group elements by the result
|
||||
* Groups the elements in the collection into a new [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
|
||||
*
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt groupBy
|
||||
*/
|
||||
public inline fun <T, K> Iterable<T>.groupBy(result: Map<K, List<T>> = HashMap<K, List<T>>(), toKey: (T) -> K) : Map<K, List<T>> {
|
||||
public inline fun <T, K> Iterable<T>.groupBy(toKey: (T) -> K) : Map<K, List<T>> = groupByTo<T,K>(HashMap<K, List<T>>(), toKey)
|
||||
|
||||
/**
|
||||
* Groups the elements in the collection into the given [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
|
||||
*
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt groupBy
|
||||
*/
|
||||
public inline fun <T, K> Iterable<T>.groupByTo(result: Map<K, List<T>>, toKey: (T) -> K) : Map<K, List<T>> {
|
||||
for (element in this) {
|
||||
val key = toKey(element)
|
||||
val list = result.getOrPut(key) { ArrayList<T>() }
|
||||
@@ -160,7 +167,7 @@ public inline fun <T, K> Iterable<T>.groupBy(result: Map<K, List<T>> = HashMap<K
|
||||
* If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will
|
||||
* a special *truncated* separator (which defaults to "..."
|
||||
*
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt appendString
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt makeString
|
||||
*/
|
||||
public inline fun <T> Iterable<T>.makeString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): String {
|
||||
val buffer = StringBuilder()
|
||||
|
||||
@@ -138,11 +138,18 @@ public inline fun <T> java.lang.Iterable<T>.fold(initial: T, operation: (T, T) -
|
||||
public inline fun <T> java.lang.Iterable<T>.foldRight(initial: T, operation: (T, T) -> T): T = reverse().fold(initial, operation)
|
||||
|
||||
/**
|
||||
* Transforms each element using the result as the key in a map to group elements by the result
|
||||
* Groups the elements in the collection into a new [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
|
||||
*
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt groupBy
|
||||
*/
|
||||
public inline fun <T, K> java.lang.Iterable<T>.groupBy(result: Map<K, List<T>> = HashMap<K, List<T>>(), toKey: (T) -> K) : Map<K, List<T>> {
|
||||
public inline fun <T, K> java.lang.Iterable<T>.groupBy(toKey: (T) -> K) : Map<K, List<T>> = groupByTo<T,K>(HashMap<K, List<T>>(), toKey)
|
||||
|
||||
/**
|
||||
* Groups the elements in the collection into the given [[Map]] using the supplied *toKey* function to calculate the key to group the elements by
|
||||
*
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt groupBy
|
||||
*/
|
||||
public inline fun <T, K> java.lang.Iterable<T>.groupByTo(result: Map<K, List<T>>, toKey: (T) -> K) : Map<K, List<T>> {
|
||||
for (element in this) {
|
||||
val key = toKey(element)
|
||||
val list = result.getOrPut(key) { ArrayList<T>() }
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.*
|
||||
//
|
||||
|
||||
/**
|
||||
* Returns a new List containing the results of applying the given function to each element in this collection
|
||||
* Returns a new List containing the results of applying the given *transform* function to each element in this collection
|
||||
*
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt map
|
||||
*/
|
||||
@@ -18,7 +18,10 @@ public inline fun <T, R> java.util.Collection<T>.map(transform : (T) -> R) : jav
|
||||
return mapTo(java.util.ArrayList<R>(this.size), transform)
|
||||
}
|
||||
|
||||
/** Transforms each element of this collection with the given function then adds the results to the given collection */
|
||||
/**
|
||||
* Transforms each element of this collection with the given *transform* function and
|
||||
* adds each return value to the given *results* collection
|
||||
*/
|
||||
public inline fun <T, R, C: Collection<in R>> java.util.Collection<T>.mapTo(result: C, transform : (T) -> R) : C {
|
||||
for (item in this)
|
||||
result.add(transform(item))
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package kotlin
|
||||
|
||||
import java.util.Map as JMap
|
||||
import java.util.HashMap
|
||||
import java.util.Map.Entry as JEntry
|
||||
import java.util.Collection
|
||||
import java.util.Collections
|
||||
|
||||
// Temporary workaround: commenting out
|
||||
//import java.util.Map.Entry as JEntry
|
||||
import java.util.HashMap
|
||||
import java.util.List
|
||||
|
||||
// Map APIs
|
||||
|
||||
@@ -26,14 +26,12 @@ public inline fun <K,V> java.util.Map<K,V>?.orEmpty() : java.util.Map<K,V>
|
||||
|
||||
|
||||
/** Returns the key of the entry */
|
||||
// Temporary workaround: commenting out
|
||||
//val <K,V> JEntry<K,V>.key : K
|
||||
// get() = getKey().sure()
|
||||
val <K,V> JEntry<K,V>.key : K
|
||||
get() = getKey().sure()
|
||||
|
||||
/** Returns the value of the entry */
|
||||
// Temporary workaround: commenting out
|
||||
//val <K,V> JEntry<K,V>.value : V
|
||||
// get() = getValue().sure()
|
||||
val <K,V> JEntry<K,V>.value : V
|
||||
get() = getValue().sure()
|
||||
|
||||
/**
|
||||
* Returns the value for the given key or returns the result of the defaultValue function if there was no entry for the given key
|
||||
@@ -64,3 +62,54 @@ public inline fun <K,V> java.util.Map<K,V>.getOrPut(key: K, defaultValue: ()-> V
|
||||
return answer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an [[Iterator]] over the entries in the [[Map]]
|
||||
*
|
||||
* @includeFunctionBody ../../test/MapTest.kt iterateWithProperties
|
||||
*/
|
||||
public inline fun <K,V> java.util.Map<K,V>.iterator(): java.util.Iterator<java.util.Map.Entry<K,V>> {
|
||||
val entrySet = this.entrySet()!!
|
||||
return entrySet.iterator()!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new List containing the results of applying the given *transform* function to each [[Map.Entry]] in this [[Map]]
|
||||
*
|
||||
* @includeFunctionBody ../../test/CollectionTest.kt map
|
||||
*/
|
||||
public inline fun <K,V,R> java.util.Map<K,V>.map(transform: (java.util.Map.Entry<K,V>) -> R) : java.util.List<R> {
|
||||
return mapTo(java.util.ArrayList<R>(this.size), transform)
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms each [[Map.Entry]] in this [[Map]] with the given *transform* function and
|
||||
* adds each return value to the given *results* collection
|
||||
*/
|
||||
public inline fun <K,V,R, C: Collection<in R>> java.util.Map<K,V>.mapTo(result: C, transform: (java.util.Map.Entry<K,V>) -> R) : C {
|
||||
for (item in this)
|
||||
result.add(transform(item))
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new Map containing the results of applying the given *transform* function to each [[Map.Entry]] in this [[Map]]
|
||||
*
|
||||
* @includeFunctionBody ../../test/MapTest.kt mapValues
|
||||
*/
|
||||
public inline fun <K,V,R> java.util.Map<K,V>.mapValues(transform : (java.util.Map.Entry<K,V>) -> R): java.util.Map<K,R> {
|
||||
return mapValuesTo(java.util.HashMap<K,R>(this.size), transform)
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the given *result* [[Map]] with the value returned by applying the *transform* function on each [[Map.Entry]] in this [[Map]]
|
||||
*/
|
||||
public inline fun <K,V,R,C: java.util.Map<K,R>> java.util.Map<K,V>.mapValuesTo(result: C, transform : (java.util.Map.Entry<K,V>) -> R) : C {
|
||||
for (e in this) {
|
||||
val newValue = transform(e)
|
||||
result.put(e.key, newValue)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
## Collections API
|
||||
|
||||
There are a number of extension functions on [Collection](http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/java/util/Collection-extensions.html), [Iterator](http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/java/util/Iterator-extensions.html), [Map](http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/java/util/Map-extensions.html) and arrays to allow easy composition collections using familiar combinators like
|
||||
|
||||
* <a href="http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/java/util/Collection-extensions.html#filter(jet.Function1)">filter()</a>
|
||||
* <a href="http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/java/util/Collection-extensions.html#flatMap(jet.Function1)">flatMap()</a>
|
||||
* <a href="http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/java/util/Collection-extensions.html#map(jet.Function1)">map()</a>
|
||||
* <a href="http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/java/util/Collection-extensions.html#fold(T, jet.Function2)">fold()</a>
|
||||
|
||||
Functions on [Collection](http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/java/util/Collection-extensions.html), [Map](http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/java/util/Map-extensions.html) and arrays are all *eager*, in that methods like <a href="http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/java/util/Collection-extensions.html#map(jet.Function1)">map()</a> will create a complete result List when the method completes.
|
||||
|
||||
Functions on [Iterator](http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/java/util/Iterator-extensions.html) are *lazy* so that they try to return new iterators that lazily evaluate things. For example <a href="http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/java/util/Iterator-extensions.html#map(jet.Function1)">map()</a> returns a new Iterator that lazily maps the values in the original iterator.
|
||||
|
||||
## Preconditions
|
||||
|
||||
When writing code it is recommended you add checks early in a function to ensure parameters are valid. There are a number of helper methods for this:
|
||||
|
||||
* <a href="http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/package-summary.html#assert(jet.Boolean)">assert(Boolean)</a> and <a href="http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/package-summary.html#assert(jet.Boolean, jet.Function0)">assert(Boolean) { lazyMessage }</a> which use the JDK's assertion feature so they can be disabled using the -ea option
|
||||
* <a href="http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/package-summary.html#check(jet.Boolean)">check(Boolean)</a> and <a href="http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/package-summary.html#check(jet.Boolean, jet.Function0)">check(Boolean) { lazyMessage }</a> for checking something to be true and throwing [IllegalStateException](http://docs.oracle.com/javase/6/docs/api/java/lang/IllegalStateException.html) if not
|
||||
* <a href="http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/package-summary.html#require(jet.Boolean)">require(Boolean)</a> and <a href="http://jetbrains.github.com/kotlin/versions/snapshot/apidocs/kotlin/package-summary.html#require(jet.Boolean, jet.Function0)">require(Boolean) { lazyMessage }</a> for requiring something to be true and throwing [IllegalArgumentException](http://docs.oracle.com/javase/6/docs/api/java/lang/IllegalArgumentException.html) if not
|
||||
@@ -120,9 +120,9 @@ class CollectionTest {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO would be nice to avoid the <String>
|
||||
test fun filterIntoSet() {
|
||||
val data = arrayList("foo", "bar")
|
||||
// TODO would be nice to avoid the <String>
|
||||
val foo = data.filterTo(hashSet<String>()){it.startsWith("f")}
|
||||
|
||||
assertTrue {
|
||||
@@ -136,9 +136,9 @@ class CollectionTest {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO would be nice to avoid the <String>
|
||||
test fun filterIntoSortedSet() {
|
||||
val data = arrayList("foo", "bar")
|
||||
// TODO would be nice to avoid the <String>
|
||||
val sorted = data.filterTo(sortedSet<String>()){it.length == 3}
|
||||
assertEquals(2, sorted.size)
|
||||
assertEquals(sortedSet("bar", "foo"), sorted)
|
||||
@@ -176,59 +176,39 @@ class CollectionTest {
|
||||
assertEquals(6, count)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// TODO would be nice to be able to write this as this
|
||||
//numbers.fold(0){it + it2}
|
||||
numbers.fold(0){(it, it2) -> it + it2}
|
||||
|
||||
// TODO would be nice to be able to write this as this
|
||||
// numbers.map{it.toString()}.fold(""){it + it2}
|
||||
numbers.map<Int, String>{it.toString()}.fold(""){(it, it2) -> it + it2}
|
||||
*/
|
||||
test fun fold() {
|
||||
// lets calculate the sum of some numbers
|
||||
expect(10) {
|
||||
val numbers = arrayList(1, 2, 3, 4)
|
||||
numbers.fold(0){(it, it2) -> it + it2}
|
||||
numbers.fold(0){ a, b -> a + b}
|
||||
}
|
||||
|
||||
expect(0) {
|
||||
val numbers = arrayList<Int>()
|
||||
numbers.fold(0){(it, it2) -> it + it2}
|
||||
numbers.fold(0){ a, b -> a + b}
|
||||
}
|
||||
|
||||
// lets concatenate some strings
|
||||
expect("1234") {
|
||||
val numbers = arrayList(1, 2, 3, 4)
|
||||
numbers.map<Int, String>{it.toString()}.fold(""){(it, it2) -> it + it2}
|
||||
numbers.map<Int, String>{it.toString()}.fold(""){ a, b -> a + b}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO would be nice to be able to write this as this
|
||||
// numbers.map{it.toString()}.foldRight(""){it + it2}
|
||||
numbers.map<Int, String>{it.toString()}.foldRight(""){(it, it2) -> it + it2}
|
||||
*/
|
||||
test fun foldRight() {
|
||||
expect("4321") {
|
||||
val numbers = arrayList(1, 2, 3, 4)
|
||||
numbers.map<Int, String>{it.toString()}.foldRight(""){(it, it2) -> it + it2}
|
||||
numbers.map<Int, String>{it.toString()}.foldRight(""){ a, b -> a + b}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TODO inference engine should not need this type info?
|
||||
val byLength = words.groupBy<String, Int>{it.length}
|
||||
*/
|
||||
test fun groupBy() {
|
||||
val words = arrayList("a", "ab", "abc", "def", "abcd")
|
||||
val byLength = words.groupBy<String, Int>{it.length}
|
||||
val byLength = words.groupBy{ it.length }
|
||||
assertEquals(4, byLength.size())
|
||||
|
||||
val l3 = byLength.getOrElse(3, {ArrayList<String>()})
|
||||
assertEquals(2, l3.size)
|
||||
|
||||
}
|
||||
|
||||
test fun makeString() {
|
||||
|
||||
@@ -3,12 +3,11 @@ package test.collections
|
||||
import kotlin.test.*
|
||||
|
||||
import java.util.*
|
||||
import junit.framework.TestCase
|
||||
import org.junit.Test
|
||||
import org.junit.Test as test
|
||||
|
||||
class MapTest {
|
||||
|
||||
Test fun getOrElse() {
|
||||
test fun getOrElse() {
|
||||
val data = HashMap<String, Int>()
|
||||
val a = data.getOrElse("foo"){2}
|
||||
assertEquals(2, a)
|
||||
@@ -18,7 +17,7 @@ class MapTest {
|
||||
assertEquals(0, data.size())
|
||||
}
|
||||
|
||||
Test fun getOrPut() {
|
||||
test fun getOrPut() {
|
||||
val data = HashMap<String, Int>()
|
||||
val a = data.getOrPut("foo"){2}
|
||||
assertEquals(2, a)
|
||||
@@ -29,13 +28,13 @@ class MapTest {
|
||||
assertEquals(1, data.size())
|
||||
}
|
||||
|
||||
Test fun sizeAndEmpty() {
|
||||
test fun sizeAndEmpty() {
|
||||
val data = HashMap<String, Int>()
|
||||
assertTrue{ data.empty }
|
||||
assertEquals(data.size, 0)
|
||||
}
|
||||
|
||||
Test fun setViaIndexOperators() {
|
||||
test fun setViaIndexOperators() {
|
||||
val map = HashMap<String, String>()
|
||||
assertTrue{ map.empty }
|
||||
assertEquals(map.size, 0)
|
||||
@@ -46,4 +45,95 @@ class MapTest {
|
||||
assertEquals(map.size(), 1)
|
||||
assertEquals("James", map["name"])
|
||||
}
|
||||
|
||||
test fun iterate() {
|
||||
val map = TreeMap<String, String>()
|
||||
map["beverage"] = "beer"
|
||||
map["location"] = "Mells"
|
||||
map["name"] = "James"
|
||||
|
||||
val list = arrayList<String>()
|
||||
for (e in map) {
|
||||
println("key = ${e.getKey()}, value = ${e.getValue()}")
|
||||
list.add(e.getKey())
|
||||
list.add(e.getValue())
|
||||
}
|
||||
|
||||
assertEquals(6, list.size())
|
||||
assertEquals("beverage,beer,location,Mells,name,James", list.makeString(","))
|
||||
}
|
||||
|
||||
test fun iterateWithProperties() {
|
||||
val map = TreeMap<String, String>()
|
||||
map["beverage"] = "beer"
|
||||
map["location"] = "Mells"
|
||||
map["name"] = "James"
|
||||
|
||||
val list = arrayList<String>()
|
||||
for (e in map) {
|
||||
println("key = ${e.key}, value = ${e.value}")
|
||||
list.add(e.key)
|
||||
list.add(e.value)
|
||||
}
|
||||
|
||||
assertEquals(6, list.size())
|
||||
assertEquals("beverage,beer,location,Mells,name,James", list.makeString(","))
|
||||
}
|
||||
|
||||
/*
|
||||
TODO compiler bug
|
||||
we should be able to remove the explicit type <String,String,String> on the map function
|
||||
http://youtrack.jetbrains.net/issue/KT-1145
|
||||
*/
|
||||
test fun map() {
|
||||
val m1 = TreeMap<String, String>()
|
||||
m1["beverage"] = "beer"
|
||||
m1["location"] = "Mells"
|
||||
|
||||
val list = m1.map<String,String,String>{ it.value + " rocks" }
|
||||
|
||||
println("Got new list $list")
|
||||
assertEquals(arrayList("beer rocks", "Mells rocks"), list)
|
||||
}
|
||||
|
||||
/*
|
||||
TODO compiler bug
|
||||
we should be able to remove the explicit type <String,String,String> on the mapValues function
|
||||
http://youtrack.jetbrains.net/issue/KT-1145
|
||||
*/
|
||||
test fun mapValues() {
|
||||
val m1 = TreeMap<String, String>()
|
||||
m1["beverage"] = "beer"
|
||||
m1["location"] = "Mells"
|
||||
|
||||
val m2 = m1.mapValues<String,String,String>{ it.value + "2" }
|
||||
|
||||
println("Got new map $m2")
|
||||
assertEquals(arrayList("beer2", "Mells2"), m2.values().toList())
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
TODO
|
||||
test case for http://youtrack.jetbrains.com/issue/KT-1773
|
||||
|
||||
test fun compilerBug() {
|
||||
val map = TreeMap<String, String>()
|
||||
map["beverage"] = "beer"
|
||||
map["location"] = "Mells"
|
||||
map["name"] = "James"
|
||||
|
||||
var list = arrayList<String>()
|
||||
for (e in map) {
|
||||
println("key = ${e.getKey()}, value = ${e.getValue()}")
|
||||
list += e.getKey()
|
||||
list += e.getValue()
|
||||
}
|
||||
|
||||
assertEquals(6, list.size())
|
||||
assertEquals("beverage,beer,location,Mells,name,James", list.makeString(","))
|
||||
println("==== worked! $list")
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
@@ -4,15 +4,15 @@ import kotlin.*
|
||||
import kotlin.dom.*
|
||||
import kotlin.test.*
|
||||
import org.w3c.dom.*
|
||||
import junit.framework.TestCase
|
||||
import org.junit.Test as test
|
||||
|
||||
class DomTest() : TestCase() {
|
||||
class DomTest {
|
||||
|
||||
fun testCreateDocument() {
|
||||
test fun testCreateDocument() {
|
||||
var doc = createDocument()
|
||||
assertNotNull(doc, "Should have created a document")
|
||||
|
||||
val e = doc.createElement("foo").sure()
|
||||
val e = doc.createElement("foo")!!
|
||||
assertCssClass(e, "")
|
||||
|
||||
// now lets update the cssClass property
|
||||
@@ -27,6 +27,19 @@ class DomTest() : TestCase() {
|
||||
println("document ${doc.toXmlString()}")
|
||||
}
|
||||
|
||||
test fun addText() {
|
||||
var doc = createDocument()
|
||||
assertNotNull(doc, "Should have created a document")
|
||||
|
||||
val e = doc.createElement("foo")!!
|
||||
e + "hello"
|
||||
|
||||
println("element after text ${e.toXmlString()}")
|
||||
|
||||
assertEquals("hello", e.text)
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun assertCssClass(e: Element, value: String?): Unit {
|
||||
val cl = e.classes
|
||||
|
||||
+53
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.doc.KDocConfig;
|
||||
import org.jetbrains.kotlin.maven.KotlinCompileMojoBase;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Generates API docs documentation for kotlin sources
|
||||
@@ -118,6 +119,20 @@ public class KDocMojo extends KotlinCompileMojoBase {
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* The HTTP link to source code
|
||||
*
|
||||
* @parameter expression="${sourceRootHref}"
|
||||
*/
|
||||
private String sourceRootHref;
|
||||
|
||||
/**
|
||||
* The root project directory used to deduce relative file names when linking to source code
|
||||
*
|
||||
* @parameter expression="${projectRootDir}" default-value="${project.basedir}"
|
||||
*/
|
||||
private String projectRootDir;
|
||||
|
||||
/**
|
||||
* Whether warnings should be generated if no comments could be found for classes, functions and properties being documented
|
||||
*
|
||||
@@ -125,6 +140,29 @@ public class KDocMojo extends KotlinCompileMojoBase {
|
||||
*/
|
||||
private boolean warnNoComments;
|
||||
|
||||
/**
|
||||
* A Map of package name to file names for the description of packages.
|
||||
* This allows you to refer to ReadMe.md files in your project root directory which will then be included in the API Doc.
|
||||
* For packages which are not configured, KDoc will look for ReadMe.html or ReadMe.md files in the package source directory
|
||||
*
|
||||
* @parameter expression="${packageDescriptionFiles}"
|
||||
*/
|
||||
private Map<String,String> packageDescriptionFiles;
|
||||
|
||||
/**
|
||||
* A Map of package name prefixes to HTTP URLs so we can link the API docs to external packages
|
||||
*
|
||||
* @parameter expression="${packagePrefixToUrls}"
|
||||
*/
|
||||
private Map<String,String> packagePrefixToUrls;
|
||||
|
||||
/**
|
||||
* A Map of package name to summary text used in the package overview tables to give a brief summary for each package
|
||||
*
|
||||
* @parameter expression="${packagePrefixToUrls}"
|
||||
*/
|
||||
private Map<String, String> packageSummaryText;
|
||||
|
||||
@Override
|
||||
protected KotlinCompiler createCompiler() {
|
||||
return new KDocCompiler();
|
||||
@@ -146,14 +184,29 @@ public class KDocMojo extends KotlinCompileMojoBase {
|
||||
if (ignorePackages != null) {
|
||||
docConfig.getIgnorePackages().addAll(ignorePackages);
|
||||
}
|
||||
if (packageDescriptionFiles != null) {
|
||||
docConfig.getPackageDescriptionFiles().putAll(packageDescriptionFiles);
|
||||
}
|
||||
if (packagePrefixToUrls != null) {
|
||||
docConfig.getPackagePrefixToUrls().putAll(packagePrefixToUrls);
|
||||
}
|
||||
if (packageSummaryText != null) {
|
||||
docConfig.getPackageSummaryText().putAll(packageSummaryText);
|
||||
}
|
||||
docConfig.setIncludeProtected(includeProtected);
|
||||
docConfig.setTitle(title);
|
||||
docConfig.setVersion(version);
|
||||
docConfig.setWarnNoComments(warnNoComments);
|
||||
docConfig.setSourceRootHref(sourceRootHref);
|
||||
docConfig.setProjectRootDir(projectRootDir);
|
||||
getLog().info("API docs output to: " + docConfig.getDocOutputDir());
|
||||
getLog().info("classpath: " + classpath);
|
||||
getLog().info("title: " + title);
|
||||
getLog().info("sources: " + sources);
|
||||
getLog().info("sourceRootHref: " + sourceRootHref);
|
||||
getLog().info("projectRootDir: " + projectRootDir);
|
||||
getLog().info("packageDescriptionFiles: " + packageDescriptionFiles);
|
||||
getLog().info("packagePrefixToUrls: " + packagePrefixToUrls);
|
||||
getLog().info("API docs ignore packages: " + ignorePackages);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -20,8 +20,8 @@ fun main(args: Array<String?>): Unit {
|
||||
*/
|
||||
class KDocCompiler() : KotlinCompiler() {
|
||||
|
||||
protected override fun configureEnvironment(environment : CompileEnvironment?, arguments : CompilerArguments?, errStream : PrintStream?) {
|
||||
super.configureEnvironment(environment, arguments, errStream)
|
||||
protected override fun configureEnvironment(environment : CompileEnvironment?, arguments : CompilerArguments?) {
|
||||
super.configureEnvironment(environment, arguments)
|
||||
val coreEnvironment = environment?.getEnvironment()
|
||||
if (coreEnvironment != null) {
|
||||
val kdoc = KDoc()
|
||||
|
||||
@@ -26,7 +26,8 @@ class KDocConfig() {
|
||||
public var version: String = "SNAPSHOT"
|
||||
|
||||
/**
|
||||
* Returns a map of the package prefix to the URLs to use to link to it in the documentation
|
||||
* Returns a map of the package prefix to the HTML URL for the root of the apidoc using javadoc/kdoc style
|
||||
* directory layouts so that this API doc report can link to external packages
|
||||
*/
|
||||
public val packagePrefixToUrls: Map<String, String> = TreeMap<String, String>(LongestFirstStringComparator())
|
||||
|
||||
@@ -41,6 +42,27 @@ class KDocConfig() {
|
||||
*/
|
||||
public var warnNoComments: Boolean = true
|
||||
|
||||
/**
|
||||
* Returns the HTTP URL of the root directory of source code that we should link to
|
||||
*/
|
||||
public var sourceRootHref: String? = null
|
||||
|
||||
/**
|
||||
* The root project directory used to deduce relative file names when linking to source code
|
||||
*/
|
||||
public var projectRootDir: String? = null
|
||||
|
||||
/**
|
||||
* A map of package name to html or markdown files used to describe the package. If none is
|
||||
* speciied we will look for a package.html or package.md file in the source tree
|
||||
*/
|
||||
public var packageDescriptionFiles: Map<String,String> = HashMap<String,String>()
|
||||
|
||||
/**
|
||||
* A map of package name to summary text used in the package overviews
|
||||
*/
|
||||
public var packageSummaryText: Map<String,String> = HashMap<String,String>()
|
||||
|
||||
/**
|
||||
* Returns true if protected functions and properties should be documented
|
||||
*/
|
||||
@@ -69,21 +91,16 @@ class KDocConfig() {
|
||||
/**
|
||||
* Resolves a link to the given class name
|
||||
*/
|
||||
fun resolveLink(packageName: String): String {
|
||||
// TODO should be able to do something like
|
||||
// for (e in packageUrls.filterNotNull()) {
|
||||
val entrySet = packagePrefixToUrls.entrySet()
|
||||
if (entrySet != null) {
|
||||
for (e in entrySet) {
|
||||
val p = e?.getKey()
|
||||
val url = e?.getValue()
|
||||
if (p != null && url != null) {
|
||||
if (packageName.startsWith(p)) {
|
||||
return url
|
||||
}
|
||||
fun resolveLink(packageName: String, warn: Boolean = true): String {
|
||||
for (e in packagePrefixToUrls) {
|
||||
val p = e.key
|
||||
val url = e.value
|
||||
if (p != null && url != null) {
|
||||
if (packageName.startsWith(p)) {
|
||||
return url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (missingPackageUrls.add(packageName)) {
|
||||
println("Warning: could not find external link to package: $packageName")
|
||||
}
|
||||
|
||||
+194
-27
@@ -39,6 +39,10 @@ import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import org.jetbrains.jet.lang.descriptors.Visibilities
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils.LineAndColumn
|
||||
import com.intellij.psi.PsiFileSystemItem
|
||||
import java.io.File
|
||||
|
||||
|
||||
/**
|
||||
@@ -75,6 +79,10 @@ fun warning(message: String) {
|
||||
println("Warning: $message")
|
||||
}
|
||||
|
||||
fun info(message: String) {
|
||||
// println("info: $message")
|
||||
}
|
||||
|
||||
// TODO for some reason the SortedMap causes kotlin to freak out a little :)
|
||||
fun inheritedExtensionFunctions(functions: Collection<KFunction>): Map<KClass, SortedSet<KFunction>> {
|
||||
//fun inheritedExtensionFunctions(functions: Collection<KFunction>): SortedMap<KClass, SortedSet<KFunction>> {
|
||||
@@ -136,14 +144,14 @@ fun inheritedExtensionProperties(properties: Collection<KProperty>): Map<KClass,
|
||||
// TODO for some reason the SortedMap causes kotlin to freak out a little :)
|
||||
fun extensionFunctions(functions: Collection<KFunction>): Map<KClass, List<KFunction>> {
|
||||
val map = TreeMap<KClass, List<KFunction>>()
|
||||
functions.filter{ it.extensionClass != null }.groupBy(map){ it.extensionClass.sure() }
|
||||
functions.filter{ it.extensionClass != null }.groupByTo(map){ it.extensionClass.sure() }
|
||||
return map
|
||||
}
|
||||
|
||||
// TODO for some reason the SortedMap causes kotlin to freak out a little :)
|
||||
fun extensionProperties(properties: Collection<KProperty>): Map<KClass, List<KProperty>> {
|
||||
val map = TreeMap<KClass, List<KProperty>>()
|
||||
properties.filter{ it.extensionClass != null }.groupBy(map){ it.extensionClass.sure() }
|
||||
properties.filter{ it.extensionClass != null }.groupByTo(map){ it.extensionClass.sure() }
|
||||
return map
|
||||
}
|
||||
|
||||
@@ -190,6 +198,32 @@ class KModel(var context: BindingContext, val config: KDocConfig) {
|
||||
public val version: String
|
||||
get() = config.version
|
||||
|
||||
private var _projectRootDir: String? = null
|
||||
|
||||
/**
|
||||
* File names we look for in a package directory for the overall description of a package for KDoc
|
||||
*/
|
||||
val packageDescriptionFiles = arrayList("readme.md", "ReadMe.md, readme.html, ReadMe.html")
|
||||
|
||||
private val readMeDirsScanned = HashSet<String>()
|
||||
|
||||
/**
|
||||
* Returns the root project directory for calculating relative source links
|
||||
*/
|
||||
fun projectRootDir(): String {
|
||||
if (_projectRootDir == null) {
|
||||
val rootDir = config.projectRootDir
|
||||
_projectRootDir = if (rootDir == null) {
|
||||
warning("KDocConfig does not have a projectRootDir defined so we cannot generate relative source Hrefs")
|
||||
""
|
||||
} else {
|
||||
File(rootDir).getCanonicalPath() ?: ""
|
||||
}
|
||||
}
|
||||
return _projectRootDir ?: ""
|
||||
}
|
||||
|
||||
|
||||
/** Loads the model from the given set of source files */
|
||||
fun load(sources: List<JetFile?>): Unit {
|
||||
val allNamespaces = HashSet<NamespaceDescriptor>()
|
||||
@@ -236,10 +270,52 @@ class KModel(var context: BindingContext, val config: KDocConfig) {
|
||||
val scope = descriptor.getMemberScope()
|
||||
addFunctions(pkg, scope)
|
||||
pkg.local = isLocal(descriptor)
|
||||
pkg.useExternalLink = pkg.model.config.resolveLink(pkg.name, false).notEmpty()
|
||||
|
||||
if (pkg.wikiDescription.isEmpty()) {
|
||||
// lets try find a custom doc
|
||||
var file = config.packageDescriptionFiles[name]
|
||||
loadWikiDescription(pkg, file)
|
||||
}
|
||||
}
|
||||
return pkg;
|
||||
}
|
||||
|
||||
protected fun loadWikiDescription(pkg: KPackage, file: String?): Unit {
|
||||
if (file != null) {
|
||||
try {
|
||||
pkg.wikiDescription = File(file).readText()
|
||||
} catch (e: Throwable) {
|
||||
warning("Failed to load package ${pkg.name} documentation file $file. Reason $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a package has no detailed description lets try load it from the descriptors
|
||||
* source directory if we've not checked that directory before
|
||||
*/
|
||||
fun tryLoadReadMe(pkg: KPackage, descriptor: DeclarationDescriptor): Unit {
|
||||
if (pkg.wikiDescription.isEmpty()) {
|
||||
// lets try find the package.html or package.md file
|
||||
val srcPath = pkg.model.filePath(descriptor)
|
||||
if (srcPath != null) {
|
||||
val srcFile = File(srcPath)
|
||||
val dir = if (srcFile.isDirectory()) srcFile else srcFile.getParentFile()
|
||||
if (dir != null && readMeDirsScanned.add(dir.getPath()!!)) {
|
||||
val f = packageDescriptionFiles.map{ File(dir, it) }.find{ it.exists() }
|
||||
if (f != null) {
|
||||
val file = f.getCanonicalPath()
|
||||
loadWikiDescription(pkg, file)
|
||||
}
|
||||
else {
|
||||
info("package ${pkg.name} has no ReadMe.(html|md) in $dir")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun wikiConvert(text: String, linkRenderer: LinkRenderer, fileName: String?): String {
|
||||
return markdownProcessor.markdownToHtml(text, linkRenderer).sure()
|
||||
}
|
||||
@@ -344,12 +420,30 @@ class KModel(var context: BindingContext, val config: KDocConfig) {
|
||||
return null
|
||||
}
|
||||
|
||||
fun locationFor(descriptor: DeclarationDescriptor): LineAndColumn? {
|
||||
val psiElement = getPsiElement(descriptor)
|
||||
if (psiElement != null) {
|
||||
val document = psiElement.getContainingFile()?.getViewProvider()?.getDocument()
|
||||
if (document != null) {
|
||||
val offset = psiElement.getTextOffset()
|
||||
return DiagnosticUtils.offsetToLineAndColumn(document, offset)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun fileFor(descriptor: DeclarationDescriptor): String? {
|
||||
val psiElement = getPsiElement(descriptor)
|
||||
return psiElement?.getContainingFile()?.getName()
|
||||
}
|
||||
|
||||
fun filePath(descriptor: DeclarationDescriptor): String? {
|
||||
val psiElement = getPsiElement(descriptor)
|
||||
val file = psiElement?.getContainingFile()
|
||||
return filePath(file)
|
||||
}
|
||||
|
||||
|
||||
protected fun getPsiElement(descriptor: DeclarationDescriptor): PsiElement? {
|
||||
return try {
|
||||
BindingContextUtils.descriptorToDeclaration(context, descriptor)
|
||||
@@ -412,7 +506,7 @@ class KModel(var context: BindingContext, val config: KDocConfig) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warning("Uknown kdoc macro @$remaining")
|
||||
warning("Unknown kdoc macro @$remaining")
|
||||
}
|
||||
}
|
||||
buffer.append(text)
|
||||
@@ -446,6 +540,17 @@ class KModel(var context: BindingContext, val config: KDocConfig) {
|
||||
return null
|
||||
}
|
||||
|
||||
protected fun filePath(file: PsiFileSystemItem?): String? {
|
||||
if (file != null) {
|
||||
var dir = file.getParent()
|
||||
if (dir != null) {
|
||||
val parentName = filePath(dir) ?: ""
|
||||
return parentName + "/" + file.getName()
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the block of code within { .. } tokens or returning null if it can't be found
|
||||
*/
|
||||
@@ -543,14 +648,20 @@ class KModel(var context: BindingContext, val config: KDocConfig) {
|
||||
|
||||
fun getClass(classElement: ClassDescriptor): KClass? {
|
||||
val name = classElement.getName()
|
||||
val container = classElement.getContainingDeclaration()
|
||||
if (name != null && container is NamespaceDescriptor) {
|
||||
val pkg = getPackage(container)
|
||||
return pkg.getClass(name, classElement)
|
||||
} else {
|
||||
warning("no package found for $container and class $name")
|
||||
return null
|
||||
if (name != null) {
|
||||
var dec: DeclarationDescriptor? = classElement.getContainingDeclaration()
|
||||
while (dec != null) {
|
||||
val container = dec
|
||||
if (container is NamespaceDescriptor) {
|
||||
val pkg = getPackage(container)
|
||||
return pkg.getClass(name, classElement)
|
||||
} else {
|
||||
dec = dec?.getContainingDeclaration()
|
||||
}
|
||||
}
|
||||
warning("no package found for class $name")
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun previous(pkg: KPackage): KPackage? {
|
||||
@@ -690,7 +801,7 @@ abstract class KAnnotated(val model: KModel, val declarationDescriptor: Declarat
|
||||
|
||||
public open var deprecated: Boolean = false
|
||||
|
||||
fun description(template: KDocTemplate): String {
|
||||
open fun description(template: KDocTemplate): String {
|
||||
val detailedText = detailedDescription(template)
|
||||
val idx = detailedText.indexOf("</p>")
|
||||
return if (idx > 0) {
|
||||
@@ -701,8 +812,52 @@ abstract class KAnnotated(val model: KModel, val declarationDescriptor: Declarat
|
||||
}
|
||||
|
||||
fun detailedDescription(template: KDocTemplate): String {
|
||||
val wiki = wikiDescription
|
||||
return wikiConvert(wiki, template)
|
||||
}
|
||||
|
||||
protected fun wikiConvert(wiki: String, template: KDocTemplate): String {
|
||||
val file = model.fileFor(declarationDescriptor)
|
||||
return model.wikiConvert(wikiDescription, TemplateLinkRenderer(this, template), file)
|
||||
return model.wikiConvert(wiki, TemplateLinkRenderer(this, template), file)
|
||||
}
|
||||
|
||||
fun isLinkToSourceRepo(): Boolean {
|
||||
return model.config.sourceRootHref != null
|
||||
}
|
||||
|
||||
fun sourceTargetAttribute(): String {
|
||||
return if (isLinkToSourceRepo()) " target=\"_top\" class=\"repoSourceCode\"" else ""
|
||||
}
|
||||
|
||||
fun sourceLink(): String {
|
||||
val file = filePath()
|
||||
if (file != null) {
|
||||
// lets remove the root project directory
|
||||
val rootDir = model.projectRootDir()
|
||||
val canonicalFile = File(file).getCanonicalPath() ?: ""
|
||||
val relativeFile = if (rootDir != null && canonicalFile.startsWith(rootDir))
|
||||
canonicalFile.substring(rootDir.length()) else canonicalFile
|
||||
return sourceLinkFor(relativeFile!!)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
fun filePath(): String? = model.filePath(declarationDescriptor)
|
||||
|
||||
protected fun sourceLinkFor(filePath: String, lineLinkText: String = "#L"): String {
|
||||
val root = model.config.sourceRootHref!!
|
||||
val cleanRoot = root.trimTrailing("/")
|
||||
val cleanPath = filePath.trimLeading("/")
|
||||
return "$cleanRoot/$cleanPath$lineLinkText$sourceLine"
|
||||
|
||||
}
|
||||
|
||||
fun location(): LineAndColumn? = model.locationFor(declarationDescriptor)
|
||||
|
||||
val sourceLine: Int
|
||||
get() {
|
||||
val loc = location()
|
||||
return if (loc != null) loc.getLine() else 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -718,7 +873,18 @@ abstract class KNamed(val name: String, model: KModel, declarationDescriptor: De
|
||||
|
||||
class KPackage(model: KModel, val descriptor: NamespaceDescriptor,
|
||||
val name: String,
|
||||
var local: Boolean = false): KClassOrPackage(model, descriptor), Comparable<KPackage> {
|
||||
var local: Boolean = false,
|
||||
var useExternalLink: Boolean = false): KClassOrPackage(model, descriptor), Comparable<KPackage> {
|
||||
|
||||
|
||||
// TODO generates java.lang.NoSuchMethodError: kotlin.util.namespace.hashMap(Ljet/TypeInfo;Ljet/TypeInfo;)Ljava/util/HashMap;
|
||||
//val classes = sortedMap<String,KClass>()
|
||||
public val classMap: SortedMap<String, KClass> = TreeMap<String, KClass>()
|
||||
|
||||
public val classes: Collection<KClass>
|
||||
get() = classMap.values().sure().filter{ it.isApi() }
|
||||
|
||||
public val annotations: Collection<KClass> = ArrayList<KClass>()
|
||||
|
||||
public override fun compareTo(other: KPackage): Int = name.compareTo(other.name)
|
||||
|
||||
@@ -733,6 +899,10 @@ class KPackage(model: KModel, val descriptor: NamespaceDescriptor,
|
||||
KClass(this, descriptor, name)
|
||||
}
|
||||
if (created) {
|
||||
// sometimes we may have source files for a package in different source directories
|
||||
// such as the kotlin package in generated directory; so lets always check if we can find
|
||||
// the readme
|
||||
model.tryLoadReadMe(this, descriptor)
|
||||
model.configureComments(klass, descriptor)
|
||||
val typeConstructor = descriptor.getTypeConstructor()
|
||||
val superTypes = typeConstructor.getSupertypes()
|
||||
@@ -772,14 +942,14 @@ class KPackage(model: KModel, val descriptor: NamespaceDescriptor,
|
||||
return if (answer.length == 0) "" else answer + "/"
|
||||
}
|
||||
|
||||
// TODO generates java.lang.NoSuchMethodError: kotlin.util.namespace.hashMap(Ljet/TypeInfo;Ljet/TypeInfo;)Ljava/util/HashMap;
|
||||
//val classes = sortedMap<String,KClass>()
|
||||
public val classMap: SortedMap<String, KClass> = TreeMap<String, KClass>()
|
||||
|
||||
public val classes: Collection<KClass>
|
||||
get() = classMap.values().sure().filter{ it.isApi() }
|
||||
|
||||
public val annotations: Collection<KClass> = ArrayList<KClass>()
|
||||
override fun description(template: KDocTemplate): String {
|
||||
// lets see if we can find a custom summary
|
||||
val text = model.config.packageSummaryText[name]
|
||||
return if (text != null)
|
||||
wikiConvert(text, template).trimLeading("<p>").trimTrailing("</p>")
|
||||
else
|
||||
super<KClassOrPackage>.description(template)
|
||||
}
|
||||
|
||||
fun qualifiedName(simpleName: String): String {
|
||||
return if (name.length() > 0) {
|
||||
@@ -789,7 +959,6 @@ class KPackage(model: KModel, val descriptor: NamespaceDescriptor,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun previous(pkg: KClass): KClass? {
|
||||
// TODO
|
||||
return null
|
||||
@@ -801,7 +970,7 @@ class KPackage(model: KModel, val descriptor: NamespaceDescriptor,
|
||||
}
|
||||
|
||||
fun groupClassMap(): Map<String, List<KClass>> {
|
||||
return classes.groupBy(TreeMap<String, List<KClass>>()){it.group}
|
||||
return classes.groupByTo(TreeMap<String, List<KClass>>()){it.group}
|
||||
}
|
||||
|
||||
fun packageFunctions() = functions.filter{ it.extensionClass == null }
|
||||
@@ -838,8 +1007,7 @@ class KClass(val pkg: KPackage, val descriptor: ClassDescriptor,
|
||||
var since: String = "",
|
||||
var authors: List<String> = arrayList<String>(),
|
||||
var baseClasses: List<KType> = arrayList<KType>(),
|
||||
var nestedClasses: List<KClass> = arrayList<KClass>(),
|
||||
var sourceLine: Int = 2): KClassOrPackage(pkg.model, descriptor), Comparable<KClass> {
|
||||
var nestedClasses: List<KClass> = arrayList<KClass>()): KClassOrPackage(pkg.model, descriptor), Comparable<KClass> {
|
||||
|
||||
public override fun compareTo(other: KClass): Int = name.compareTo(other.name)
|
||||
|
||||
@@ -921,8 +1089,7 @@ class KFunction(val descriptor: CallableDescriptor, val owner: KClassOrPackage,
|
||||
var modifiers: List<String> = arrayList<String>(),
|
||||
var typeParameters: List<KTypeParameter> = arrayList<KTypeParameter>(),
|
||||
var exceptions: List<KClass> = arrayList<KClass>(),
|
||||
var annotations: List<KAnnotation> = arrayList<KAnnotation>(),
|
||||
var sourceLine: Int = 2): KAnnotated(owner.model, descriptor), Comparable<KFunction> {
|
||||
var annotations: List<KAnnotation> = arrayList<KAnnotation>()): KAnnotated(owner.model, descriptor), Comparable<KFunction> {
|
||||
|
||||
public val parameterTypeText: String = parameters.map{ it.aType.name }.makeString(", ")
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -29,7 +29,7 @@ ${pkg.name}</FONT>
|
||||
Extensions on ${klass.name}</H2>
|
||||
<DL>
|
||||
<DT>
|
||||
extension functions on class <A HREF="${sourceHref(klass)}"><B>${klass.name}</B></A><DT>
|
||||
extension functions on class <A HREF="${sourceHref(klass)}"${klass.sourceTargetAttribute()}><B>${klass.name}</B></A><DT>
|
||||
from package ${link(pkg)}
|
||||
</DL>
|
||||
</PRE>
|
||||
|
||||
+5
-5
@@ -77,17 +77,17 @@ function windowTitle()
|
||||
|
||||
printPrevNextClass()
|
||||
println("""<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
|
||||
<A HREF="${pkg.nameAsRelativePath}index.html?${klass.nameAsPath}.html" target="_top"><B>FRAMES</B></A>
|
||||
<A HREF="${relativePrefix()}index.html" target="_top"><B>FRAMES</B></A>
|
||||
<A HREF="${klass.simpleName}.html" target="_top"><B>NO FRAMES</B></A>
|
||||
<SCRIPT type="text/javascript">
|
||||
<!--
|
||||
if(window==top) {
|
||||
document.writeln('<A HREF="${pkg.nameAsRelativePath}allclasses-noframe.html"><B>All Classes</B></A>');
|
||||
document.writeln('<A HREF="${relativePrefix()}allclasses-noframe.html"><B>All Classes</B></A>');
|
||||
}
|
||||
//-->
|
||||
</SCRIPT>
|
||||
<NOSCRIPT>
|
||||
<A HREF="${pkg.nameAsRelativePath}allclasses-noframe.html"><B>All Classes</B></A>
|
||||
<A HREF="${relativePrefix()}allclasses-noframe.html"><B>All Classes</B></A>
|
||||
</NOSCRIPT>
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ DETAIL: PROPERTY | CONSTR | <A HREF="#method_detail">FU
|
||||
<TR>""")
|
||||
printPrevNextClass()
|
||||
println("""<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
|
||||
<A HREF="${pkg.nameAsRelativePath}index.html?${klass.nameAsPath}.html" target="_top"><B>FRAMES</B></A>
|
||||
<A HREF="${relativePrefix()}index.html" target="_top"><B>FRAMES</B></A>
|
||||
<A HREF="${klass.simpleName}.html" target="_top"><B>NO FRAMES</B></A>
|
||||
<SCRIPT type="text/javascript">
|
||||
<!--
|
||||
@@ -184,7 +184,7 @@ Class ${klass.simpleName}</H2>
|
||||
<DL>
|
||||
<DT><PRE><FONT SIZE="-1">""")
|
||||
printAnnotations(klass.annotations)
|
||||
print("""</FONT>${klass.visibility} ${klass.kindCode} <A HREF="${sourceHref(klass)}"><B>${klass.simpleName}</B></A><DT>""")
|
||||
print("""</FONT>${klass.visibility} ${klass.kindCode} <A HREF="${sourceHref(klass)}"${klass.sourceTargetAttribute()}><B>${klass.simpleName}</B></A><DT>""")
|
||||
if (!klass.baseClasses.isEmpty()) {
|
||||
print("""extends """)
|
||||
for (bc in klass.baseClasses) {
|
||||
|
||||
+53
-22
@@ -14,7 +14,7 @@ import java.util.List
|
||||
|
||||
abstract class KDocTemplate() : TextTemplate() {
|
||||
open fun rootHref(pkg: KPackage): String {
|
||||
return if (pkg.local)
|
||||
return if (!pkg.useExternalLink)
|
||||
relativePrefix()
|
||||
else
|
||||
pkg.model.config.resolveLink(pkg.name)
|
||||
@@ -24,7 +24,7 @@ abstract class KDocTemplate() : TextTemplate() {
|
||||
= "${rootHref(p)}${p.nameAsPath}/package-summary.html"
|
||||
|
||||
open fun href(c: KClass): String {
|
||||
val postfix = if (c.pkg.local) "" else "?is-external=true"
|
||||
val postfix = if (!c.pkg.useExternalLink) "" else "?is-external=true"
|
||||
return "${rootHref(c.pkg)}${c.nameAsPath}.html$postfix"
|
||||
}
|
||||
|
||||
@@ -54,30 +54,61 @@ abstract class KDocTemplate() : TextTemplate() {
|
||||
}
|
||||
|
||||
open fun sourceHref(klass: KClass): String {
|
||||
val pkg = klass.pkg
|
||||
return if (pkg.local) {
|
||||
"${pkg.nameAsRelativePath}src-html/${klass.nameAsPath}.html#line.${klass.sourceLine}"
|
||||
if (klass.isLinkToSourceRepo()) {
|
||||
return klass.sourceLink()
|
||||
} else {
|
||||
href(klass)
|
||||
val pkg = klass.pkg
|
||||
return if (!pkg.useExternalLink) {
|
||||
"${pkg.nameAsRelativePath}src-html/${klass.nameAsPath}.html#line.${klass.sourceLine}"
|
||||
} else {
|
||||
href(klass)
|
||||
}
|
||||
}
|
||||
}
|
||||
open fun sourceHref(f: KFunction): String {
|
||||
val owner = f.owner
|
||||
return if (owner is KClass) {
|
||||
val pkg = owner.pkg
|
||||
if (pkg.local) {
|
||||
"${rootHref(pkg)}src-html/${owner.simpleName}.html#line.${f.sourceLine}"
|
||||
} else {
|
||||
href(f)
|
||||
}
|
||||
} else if (owner is KPackage) {
|
||||
if (owner.local) {
|
||||
// TODO how to find the function in a package???
|
||||
"${rootHref(owner)}src-html/namespace.html#line.${f.sourceLine}"
|
||||
} else {
|
||||
href(owner)
|
||||
}
|
||||
} else href(f)
|
||||
if (f.isLinkToSourceRepo()) {
|
||||
return f.sourceLink()
|
||||
} else {
|
||||
val owner = f.owner
|
||||
return if (owner is KClass) {
|
||||
val pkg = owner.pkg
|
||||
if (!pkg.useExternalLink) {
|
||||
"${rootHref(pkg)}src-html/${owner.simpleName}.html#line.${f.sourceLine}"
|
||||
} else {
|
||||
href(f)
|
||||
}
|
||||
} else if (owner is KPackage) {
|
||||
if (!owner.useExternalLink) {
|
||||
// TODO how to find the function in a package???
|
||||
"${rootHref(owner)}src-html/namespace.html#line.${f.sourceLine}"
|
||||
} else {
|
||||
href(owner)
|
||||
}
|
||||
} else href(f)
|
||||
}
|
||||
}
|
||||
|
||||
open fun sourceHref(f: KProperty): String {
|
||||
if (f.isLinkToSourceRepo()) {
|
||||
return f.sourceLink()
|
||||
} else {
|
||||
val owner = f.owner
|
||||
return if (owner is KClass) {
|
||||
val pkg = owner.pkg
|
||||
if (!pkg.useExternalLink) {
|
||||
"${rootHref(pkg)}src-html/${owner.simpleName}.html#line.${f.sourceLine}"
|
||||
} else {
|
||||
href(f)
|
||||
}
|
||||
} else if (owner is KPackage) {
|
||||
if (!owner.useExternalLink) {
|
||||
// TODO how to find the function in a package???
|
||||
"${rootHref(owner)}src-html/namespace.html#line.${f.sourceLine}"
|
||||
} else {
|
||||
href(owner)
|
||||
}
|
||||
} else href(f)
|
||||
}
|
||||
}
|
||||
|
||||
open fun link(c: KClass, fullName: Boolean = false): String {
|
||||
|
||||
Vendored
+2
-2
@@ -96,8 +96,8 @@ ${stylesheets()}
|
||||
<TD NOWRAP><FONT size="+1" CLASS="FrameHeadingFont">Extensions</FONT>
|
||||
<FONT CLASS="FrameItemFont">
|
||||
<BR>""")
|
||||
for (e in map.entrySet()) {
|
||||
val c = e?.getKey()
|
||||
for (e in map) {
|
||||
val c = e.key
|
||||
if (c != null) {
|
||||
println("""<A HREF="${extensionsHref(pkg, c)}" title="extensions functions on class ${c.name} from ${pkg.name}" target="classFrame"><I>${c.name}</I></A>
|
||||
<BR>""")
|
||||
|
||||
Vendored
+14
-10
@@ -74,17 +74,17 @@ function windowTitle()
|
||||
|
||||
printNextPrevPackages()
|
||||
println("""<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
|
||||
<A HREF="${pkg.nameAsRelativePath}index.html?${pkg.nameAsPath}/package-summary.html" target="_top"><B>FRAMES</B></A>
|
||||
<A HREF="${relativePrefix()}index.html" target="_top"><B>FRAMES</B></A>
|
||||
<A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A>
|
||||
<SCRIPT type="text/javascript">
|
||||
<!--
|
||||
if(window==top) {
|
||||
document.writeln('<A HREF="${pkg.nameAsRelativePath}allclasses-noframe.html"><B>All Classes</B></A>');
|
||||
document.writeln('<A HREF="${relativePrefix()}allclasses-noframe.html"><B>All Classes</B></A>');
|
||||
}
|
||||
//-->
|
||||
</SCRIPT>
|
||||
<NOSCRIPT>
|
||||
<A HREF="${pkg.nameAsRelativePath}allclasses-noframe.html"><B>All Classes</B></A>
|
||||
<A HREF="${relativePrefix()}allclasses-noframe.html"><B>All Classes</B></A>
|
||||
</NOSCRIPT>
|
||||
|
||||
|
||||
@@ -136,9 +136,9 @@ ${pkg.detailedDescription(this)}
|
||||
""")
|
||||
|
||||
val groupMap = pkg.groupClassMap()
|
||||
for (e in groupMap.entrySet()) {
|
||||
val group = e?.getKey() ?: "Other"
|
||||
val list = e?.getValue()
|
||||
for (e in groupMap) {
|
||||
val group = e.key ?: "Other"
|
||||
val list = e.value
|
||||
if (list != null) {
|
||||
println(""" <h3>$group</h3>
|
||||
|
||||
@@ -192,7 +192,7 @@ ${pkg.detailedDescription(this)}
|
||||
printNextPrevPackages()
|
||||
|
||||
println("""<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
|
||||
) <A HREF="${pkg.nameAsRelativePath}index.html?${pkg.nameAsPath}/package-summary.html" target="_top"><B>FRAMES</B></A>
|
||||
<A HREF="${relativePrefix()}index.html" target="_top"><B>FRAMES</B></A>
|
||||
<A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A>
|
||||
<SCRIPT type="text/javascript">
|
||||
<!--
|
||||
@@ -275,13 +275,13 @@ Copyright © 2010-2012. All Rights Reserved.
|
||||
<B>Extensions Summary</B></FONT></TH>
|
||||
</TR>""")
|
||||
|
||||
for (e in map.entrySet()) {
|
||||
val c = e?.getKey()
|
||||
for (e in map) {
|
||||
val c = e.key
|
||||
if (c != null) {
|
||||
println("""<TR BGCOLOR="white" CLASS="TableRowColor">
|
||||
<TD WIDTH="15%"><B><A HREF="${extensionsHref(pkg, c)}" title="extensions on ${pkg.name}">${c.name}</A></B></TD>
|
||||
<TD>""")
|
||||
val list = e?.getValue()
|
||||
val list = e.value
|
||||
if (list != null) {
|
||||
val functions = filterDuplicateNames(list)
|
||||
for (f in functions) {
|
||||
@@ -306,10 +306,14 @@ Copyright © 2010-2012. All Rights Reserved.
|
||||
val prev = model.previous(pkg)
|
||||
if (prev != null) {
|
||||
println(""" <A HREF="${prev.nameAsRelativePath}${prev.nameAsPath}/package-summary.html"><B>PREV PACKAGE</B></A> """)
|
||||
} else {
|
||||
println(""" PREV PACKAGE """ )
|
||||
}
|
||||
val next = model.next(pkg)
|
||||
if (next != null) {
|
||||
println(""" <A HREF="${next.nameAsRelativePath}${next.nameAsPath}/package-summary.html"><B>NEXT PACKAGE</B></A>""")
|
||||
} else {
|
||||
println(""" NEXT PACKAGE""" )
|
||||
}
|
||||
println("""</FONT></TD>""")
|
||||
|
||||
|
||||
Vendored
+15
-5
@@ -119,6 +119,9 @@ abstract class PackageTemplateSupport(open val pkg: KPackage) : KDocTemplate() {
|
||||
}
|
||||
|
||||
fun printFunctionDetail(function: KFunction): Unit {
|
||||
println("""<div class="doc-member function">""")
|
||||
println("""<div class="source-detail"><a href="${sourceHref(function)}"${function.sourceTargetAttribute()}>source</a></div>""")
|
||||
|
||||
println("""<A NAME="${function.name}{${function.parameterTypeText}}"><!-- --></A><A NAME="${function.link}"><!-- --></A><H3>""")
|
||||
println("""${function.name}</H3>""")
|
||||
println("""<PRE>""")
|
||||
@@ -128,7 +131,7 @@ abstract class PackageTemplateSupport(open val pkg: KPackage) : KDocTemplate() {
|
||||
|
||||
printTypeParameters(function, " ")
|
||||
printReceiverType(function, " ", ".", " ")
|
||||
print("""<A HREF="${sourceHref(function)}"><B>${function.name}</B></A>""")
|
||||
print("""<B>${function.name}</B>""")
|
||||
printParameters(function)
|
||||
print(": ")
|
||||
print(link(function.returnType))
|
||||
@@ -160,7 +163,7 @@ abstract class PackageTemplateSupport(open val pkg: KPackage) : KDocTemplate() {
|
||||
</DD>
|
||||
</DL>
|
||||
*/
|
||||
println("""<HR>""")
|
||||
println("""</div>""")
|
||||
}
|
||||
|
||||
fun printPropertySummary(properties: Collection<KProperty>): Unit {
|
||||
@@ -207,13 +210,17 @@ abstract class PackageTemplateSupport(open val pkg: KPackage) : KDocTemplate() {
|
||||
}
|
||||
*/
|
||||
println("""</CODE></FONT></TD>""")
|
||||
print("""<TD><CODE><B><A HREF="${href(property)}">${property.name}</A></B>: """)
|
||||
print("""<TD>
|
||||
<div class="doc-member property">
|
||||
<div class="source-detail"><a HREF="${sourceHref(property)}"${property.sourceTargetAttribute()}>source</a></div>
|
||||
<CODE><B>${property.name}</B>: """)
|
||||
print(link(property.returnType))
|
||||
//printParameters(property)
|
||||
println("""</CODE>""")
|
||||
println("""""")
|
||||
println("""<BR>""")
|
||||
println(""" ${deprecated} ${property.detailedDescription(this)}</TD>""")
|
||||
println(""" ${deprecated} ${property.detailedDescription(this)}
|
||||
</div></TD>""")
|
||||
println("""</TR>""")
|
||||
}
|
||||
|
||||
@@ -280,6 +287,9 @@ abstract class PackageTemplateSupport(open val pkg: KPackage) : KDocTemplate() {
|
||||
|
||||
fun stylesheets(): String {
|
||||
return """<LINK REL="stylesheet" TYPE="text/css" HREF="${relativePrefix()}stylesheet.css" TITLE="Style">
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="${relativePrefix()}kotlin.css" TITLE="Style">"""
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="${relativePrefix()}kotlin.css" TITLE="Style">
|
||||
<script type="text/javascript" src="${relativePrefix()}js/jquery.js"></script>
|
||||
<script type="text/javascript" src="${relativePrefix()}js/apidoc.js"></script>
|
||||
"""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user