Merge remote-tracking branch 'origin/master'

This commit is contained in:
Leonid Shalupov
2012-04-14 18:37:36 +04:00
63 changed files with 1366 additions and 538 deletions
@@ -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);
}
@@ -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);
}
@@ -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));
@@ -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;
}
}
@@ -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;
@@ -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()));
@@ -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 {
@@ -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) {
@@ -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
View File
@@ -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);
+22 -1
View File
@@ -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;
}
+1
View File
@@ -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))
+59 -10
View File
@@ -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
}
+20
View File
@@ -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
+7 -27
View File
@@ -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() {
+96 -6
View File
@@ -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")
}
*/
}
+17 -4
View File
@@ -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
@@ -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")
}
@@ -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(", ")
@@ -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>
@@ -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> &nbsp;
<A HREF="${relativePrefix()}index.html" target="_top"><B>FRAMES</B></A> &nbsp;
&nbsp;<A HREF="${klass.simpleName}.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
&nbsp;<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:&nbsp;PROPERTY&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<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> &nbsp;
<A HREF="${relativePrefix()}index.html" target="_top"><B>FRAMES</B></A> &nbsp;
&nbsp;<A HREF="${klass.simpleName}.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
&nbsp;<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) {
@@ -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 {
@@ -96,8 +96,8 @@ ${stylesheets()}
<TD NOWRAP><FONT size="+1" CLASS="FrameHeadingFont">Extensions</FONT>&nbsp;
<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>""")
@@ -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> &nbsp;
<A HREF="${relativePrefix()}index.html" target="_top"><B>FRAMES</B></A> &nbsp;
&nbsp;<A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
&nbsp;<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> &nbsp;
<A HREF="${relativePrefix()}index.html" target="_top"><B>FRAMES</B></A> &nbsp;
&nbsp;<A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
&nbsp;<SCRIPT type="text/javascript">
<!--
@@ -275,13 +275,13 @@ Copyright &#169; 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 &#169; 2010-2012. All Rights Reserved.
val prev = model.previous(pkg)
if (prev != null) {
println("""&nbsp;<A HREF="${prev.nameAsRelativePath}${prev.nameAsPath}/package-summary.html"><B>PREV PACKAGE</B></A>&nbsp;""")
} else {
println("""&nbsp;PREV PACKAGE&nbsp;""" )
}
val next = model.next(pkg)
if (next != null) {
println("""&nbsp;<A HREF="${next.nameAsRelativePath}${next.nameAsPath}/package-summary.html"><B>NEXT PACKAGE</B></A>""")
} else {
println("""&nbsp;NEXT PACKAGE""" )
}
println("""</FONT></TD>""")
@@ -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("""&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${deprecated}&nbsp;${property.detailedDescription(this)}</TD>""")
println("""&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${deprecated}&nbsp;${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>
"""
}
}