Merge branch 'master' of ssh://git.labs.intellij.net/jet

This commit is contained in:
svtk
2011-11-01 19:12:59 +04:00
72 changed files with 1208 additions and 391 deletions
+1
View File
@@ -29,6 +29,7 @@
<target name="jarRT" depends="compileRT">
<jar destfile="${output}/kotlin-runtime.jar">
<fileset dir="${output}/classes/runtime"/>
<fileset dir="${basedir}/stdlib/ktSrc"/>
</jar>
</target>
@@ -79,7 +79,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
this.intrinsics = state.getIntrinsics();
}
private CallableMethod asCallableMethod(FunctionDescriptor fd) {
private static CallableMethod asCallableMethod(FunctionDescriptor fd) {
Method descriptor = ClosureCodegen.erasedInvokeSignature(fd);
String owner = ClosureCodegen.getInternalClassName(fd);
final CallableMethod result = new CallableMethod(owner, descriptor, INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes()));
@@ -1187,7 +1187,24 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
mask |= (1 << index);
}
else if(resolvedValueArgument instanceof VarargValueArgument) {
throw new UnsupportedOperationException("Varargs are not supported yet");
VarargValueArgument valueArgument = (VarargValueArgument) resolvedValueArgument;
JetType outType = valueParameterDescriptor.getOutType();
Type type = typeMapper.mapType(outType);
assert type.getSort() == Type.ARRAY;
Type elementType = type.getElementType();
int size = valueArgument.getArgumentExpressions().size();
v.iconst(valueArgument.getArgumentExpressions().size());
v.newarray(elementType);
for(int i = 0; i != size; ++i) {
v.dup();
v.iconst(i);
gen(valueArgument.getArgumentExpressions().get(i), elementType);
StackValue.arrayElement(elementType, false).store(v);
}
// throw new UnsupportedOperationException("Varargs are not supported yet");
}
else {
throw new UnsupportedOperationException();
@@ -1238,29 +1255,44 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@Override
public StackValue visitSafeQualifiedExpression(JetSafeQualifiedExpression expression, StackValue receiver) {
genToJVMStack(expression.getReceiverExpression());
Label ifnull = new Label();
Label end = new Label();
v.dup();
v.ifnull(ifnull);
JetType receiverType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getReceiverExpression());
StackValue propValue = genQualified(StackValue.onStack(typeMapper.mapType(receiverType)), expression.getSelectorExpression());
Type type = propValue.type;
propValue.put(type, v);
if(JetTypeMapper.isPrimitive(type) && !type.equals(Type.VOID_TYPE)) {
StackValue.valueOf(v, type);
type = JetTypeMapper.boxType(type);
}
v.goTo(end);
JetExpression expr = expression.getReceiverExpression();
JetType receiverJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getReceiverExpression());
Type receiverType = typeMapper.mapType(receiverJetType);
gen(expr, receiverType);
if(receiverType.getSort() != Type.OBJECT && receiverType.getSort() != Type.ARRAY) {
StackValue propValue = genQualified(StackValue.onStack(receiverType), expression.getSelectorExpression());
Type type = propValue.type;
propValue.put(type, v);
if(JetTypeMapper.isPrimitive(type) && !type.equals(Type.VOID_TYPE)) {
StackValue.valueOf(v, type);
type = JetTypeMapper.boxType(type);
}
v.mark(ifnull);
v.pop();
if(!propValue.type.equals(Type.VOID_TYPE)) {
v.aconst(null);
return StackValue.onStack(type);
}
v.mark(end);
else {
Label ifnull = new Label();
Label end = new Label();
v.dup();
v.ifnull(ifnull);
StackValue propValue = genQualified(StackValue.onStack(receiverType), expression.getSelectorExpression());
Type type = propValue.type;
propValue.put(type, v);
if(JetTypeMapper.isPrimitive(type) && !type.equals(Type.VOID_TYPE)) {
StackValue.valueOf(v, type);
type = JetTypeMapper.boxType(type);
}
v.goTo(end);
return StackValue.onStack(type);
v.mark(ifnull);
v.pop();
if(!propValue.type.equals(Type.VOID_TYPE)) {
v.aconst(null);
}
v.mark(end);
return StackValue.onStack(type);
}
}
@Override
@@ -0,0 +1,23 @@
package org.jetbrains.jet.codegen;
/**
* @author yole
*/
public class GeneratedClassLoader extends ClassLoader {
private final ClassFileFactory state;
public GeneratedClassLoader(ClassFileFactory state) {
super(GeneratedClassLoader.class.getClassLoader());
this.state = state;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String file = name.replace('.', '/') + ".class";
if (state.files().contains(file)) {
byte[] bytes = state.asBytes(file);
return defineClass(name, bytes, 0, bytes.length);
}
return super.findClass(name);
}
}
@@ -15,6 +15,7 @@ import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
import org.objectweb.asm.commons.Method;
import java.util.*;
@@ -360,10 +361,6 @@ public class JetTypeMapper {
if (jetType.equals(standardLibrary.getNullableBooleanType())) {
return JL_BOOLEAN_TYPE;
}
if (jetType.equals(standardLibrary.getStringType()) || jetType.equals(standardLibrary.getNullableStringType())) {
return Type.getType(String.class);
}
if(jetType.equals(standardLibrary.getByteArrayType())){
return ARRAY_BYTE_TYPE;
}
@@ -389,6 +386,10 @@ public class JetTypeMapper {
return ARRAY_BOOL_TYPE;
}
if (jetType.equals(standardLibrary.getStringType()) || jetType.equals(standardLibrary.getNullableStringType())) {
return Type.getType(String.class);
}
DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
if (standardLibrary.getArray().equals(descriptor)) {
if (jetType.getArguments().size() != 1) {
@@ -415,6 +416,34 @@ public class JetTypeMapper {
throw new UnsupportedOperationException("Unknown type " + jetType);
}
public static Type unboxType(final Type type) {
if (type == JL_INTEGER_TYPE) {
return Type.INT_TYPE;
}
else if (type == JL_BOOLEAN_TYPE) {
return Type.BOOLEAN_TYPE;
}
else if (type == JL_CHAR_TYPE) {
return Type.CHAR_TYPE;
}
else if (type == JL_SHORT_TYPE) {
return Type.SHORT_TYPE;
}
else if (type == JL_LONG_TYPE) {
return Type.LONG_TYPE;
}
else if (type == JL_BYTE_TYPE) {
return Type.BYTE_TYPE;
}
else if (type == JL_FLOAT_TYPE) {
return Type.FLOAT_TYPE;
}
else if (type == JL_DOUBLE_TYPE) {
return Type.DOUBLE_TYPE;
}
throw new UnsupportedOperationException("Unboxing: " + type);
}
public static Type boxType(Type asmType) {
switch (asmType.getSort()) {
case Type.VOID:
@@ -462,9 +491,6 @@ public class JetTypeMapper {
}
for (ValueParameterDescriptor parameter : parameters) {
Type type = mapType(parameter.getOutType());
if(parameter.isVararg()) {
type = Type.getType("[" + type.getDescriptor());
}
valueParameterTypes.add(type);
parameterTypes.add(type);
}
@@ -488,7 +514,7 @@ public class JetTypeMapper {
return mapToCallableMethod(functionDescriptor, kind);
}
CallableMethod mapToCallableMethod(PsiMethod method) {
static CallableMethod mapToCallableMethod(PsiMethod method) {
final PsiClass containingClass = method.getContainingClass();
String owner = jvmName(containingClass);
Method signature = getMethodDescriptor(method);
@@ -562,13 +588,7 @@ public class JetTypeMapper {
parameterTypes.add(mapType(receiver.getType()));
}
for (ValueParameterDescriptor parameter : parameters) {
if(parameter.isVararg()) {
Type type = mapType(parameter.getOutType());
type = Type.getType("[" + type.getDescriptor());
parameterTypes.add(type);
}
else
parameterTypes.add(mapType(parameter.getOutType()));
parameterTypes.add(mapType(parameter.getOutType()));
}
Type returnType = mapReturnType(f.getReturnType());
return new Method(name, returnType, parameterTypes.toArray(new Type[parameterTypes.size()]));
@@ -681,6 +681,9 @@ public abstract class StackValue {
case Type.INT:
return JetTypeMapper.TYPE_SHARED_INT;
case Type.LONG:
return JetTypeMapper.TYPE_SHARED_LONG;
case Type.BOOLEAN:
return JetTypeMapper.TYPE_SHARED_BOOLEAN;
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.objectweb.asm.Type;
@@ -21,6 +22,10 @@ public class BinaryOp implements IntrinsicMethod {
@Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
boolean nullable = expectedType.getSort() == Type.OBJECT;
if(nullable) {
expectedType = JetTypeMapper.unboxType(expectedType);
}
if (arguments.size() == 1) {
// intrinsic is called as an ordinary function
if (receiver != null) {
@@ -33,6 +38,10 @@ public class BinaryOp implements IntrinsicMethod {
codegen.gen(arguments.get(1), expectedType);
}
v.visitInsn(expectedType.getOpcode(opcode));
if(nullable) {
StackValue.onStack(expectedType).put(expectedType = JetTypeMapper.boxType(expectedType), v);
}
return StackValue.onStack(expectedType);
}
}
+1
View File
@@ -10,6 +10,7 @@
<orderEntry type="module" module-name="backend" />
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="stdlib" />
</component>
</module>
@@ -0,0 +1,98 @@
package org.jetbrains.jet.cli;
import com.google.common.base.Predicates;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import org.jetbrains.jet.JetCoreEnvironment;
import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports;
import org.jetbrains.jet.plugin.JetFileType;
import java.util.ArrayList;
import java.util.List;
/**
* @author yole
*/
public class CompileSession {
private final JetCoreEnvironment myEnvironment;
private final List<JetNamespace> mySourceFileNamespaces = new ArrayList<JetNamespace>();
private final List<JetNamespace> myLibrarySourceFileNamespaces = new ArrayList<JetNamespace>();
private List<String> myErrors = new ArrayList<String>();
private BindingContext myBindingContext;
public CompileSession(JetCoreEnvironment environment) {
myEnvironment = environment;
}
public void addSources(String path) {
VirtualFile vFile = myEnvironment.getLocalFileSystem().findFileByPath(path);
if (vFile == null) {
myErrors.add("File/directory not found: " + path);
return;
}
if (!vFile.isDirectory() && vFile.getFileType() != JetFileType.INSTANCE) {
myErrors.add("Not a Kotlin file: " + path);
return;
}
addSources(vFile);
}
public void addSources(VirtualFile vFile) {
if (vFile.isDirectory()) {
for (VirtualFile virtualFile : vFile.getChildren()) {
if (virtualFile.getFileType() == JetFileType.INSTANCE) {
addSources(virtualFile);
}
}
}
else {
PsiFile psiFile = PsiManager.getInstance(myEnvironment.getProject()).findFile(vFile);
if (psiFile instanceof JetFile) {
mySourceFileNamespaces.add(((JetFile) psiFile).getRootNamespace());
}
}
}
public void addLibrarySources(VirtualFile vFile) {
PsiFile psiFile = PsiManager.getInstance(myEnvironment.getProject()).findFile(vFile);
if (psiFile instanceof JetFile) {
myLibrarySourceFileNamespaces.add(((JetFile) psiFile).getRootNamespace());
}
}
public List<JetNamespace> getSourceFileNamespaces() {
return mySourceFileNamespaces;
}
public boolean analyze() {
if (!myErrors.isEmpty()) {
for (String error : myErrors) {
System.out.println(error);
}
return false;
}
final AnalyzingUtils instance = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS);
List<JetNamespace> allNamespaces = new ArrayList<JetNamespace>(mySourceFileNamespaces);
allNamespaces.addAll(myLibrarySourceFileNamespaces);
myBindingContext = instance.analyzeNamespaces(myEnvironment.getProject(), allNamespaces, Predicates.<PsiFile>alwaysTrue(), JetControlFlowDataTraceFactory.EMPTY);
ErrorCollector errorCollector = new ErrorCollector(myBindingContext);
errorCollector.report();
return !errorCollector.hasErrors;
}
public ClassFileFactory generate() {
GenerationState generationState = new GenerationState(myEnvironment.getProject(), false);
generationState.compileCorrectNamespaces(myBindingContext, mySourceFileNamespaces);
return generationState.getFactory();
}
}
@@ -0,0 +1,52 @@
package org.jetbrains.jet.cli;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.intellij.psi.PsiFile;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithTextRange;
import org.jetbrains.jet.lang.diagnostics.Severity;
import org.jetbrains.jet.lang.resolve.BindingContext;
import java.util.Collection;
/**
* @author alex.tkachman
*/
class ErrorCollector {
Multimap<PsiFile,DiagnosticWithTextRange> maps = LinkedHashMultimap.<PsiFile, DiagnosticWithTextRange>create();
boolean hasErrors;
public ErrorCollector(BindingContext bindingContext) {
for (Diagnostic diagnostic : bindingContext.getDiagnostics()) {
report(diagnostic);
}
}
private void report(Diagnostic diagnostic) {
hasErrors |= diagnostic.getSeverity() == Severity.ERROR;
if(diagnostic instanceof DiagnosticWithTextRange) {
DiagnosticWithTextRange diagnosticWithTextRange = (DiagnosticWithTextRange) diagnostic;
maps.put(diagnosticWithTextRange.getPsiFile(), diagnosticWithTextRange);
}
else {
System.out.println(diagnostic.getSeverity().toString() + ": " + diagnostic.getMessage());
}
}
void report() {
if(!maps.isEmpty()) {
for (PsiFile psiFile : maps.keySet()) {
System.out.println(psiFile.getVirtualFile().getPath());
Collection<DiagnosticWithTextRange> diagnosticWithTextRanges = maps.get(psiFile);
for (DiagnosticWithTextRange diagnosticWithTextRange : diagnosticWithTextRanges) {
String position = DiagnosticUtils.formatPosition(diagnosticWithTextRange);
System.out.println("\t" + diagnosticWithTextRange.getSeverity().toString() + ": " + position + " " + diagnosticWithTextRange.getMessage());
}
}
}
}
}
@@ -1,48 +1,45 @@
package org.jetbrains.jet.cli;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.intellij.core.JavaCoreEnvironment;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.Processor;
import com.sampullara.cli.Args;
import com.sampullara.cli.Argument;
import jet.modules.IModuleBuilder;
import jet.modules.IModuleSetBuilder;
import org.jetbrains.jet.JetCoreEnvironment;
import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithTextRange;
import org.jetbrains.jet.lang.diagnostics.Severity;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.codegen.GeneratedClassLoader;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports;
import org.jetbrains.jet.plugin.JetMainDetector;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import java.util.List;
import java.util.jar.*;
/**
* @author yole
* @author alex.tkachman
*/
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public class KotlinCompiler {
public static class Arguments {
@Argument(value = "output", description = "output directory")
public String outputDir;
@Argument(value = "src", description = "source file or directory", required = true)
@Argument(value = "jar", description = "jar file name")
public String jar;
@Argument(value = "src", description = "source file or directory")
public String src;
@Argument(value = "module", description = "module to compile")
public String module;
}
public static void main(String[] args) {
@@ -52,7 +49,7 @@ public class KotlinCompiler {
Args.parse(arguments, args);
}
catch (Throwable t) {
System.out.println("Usage: KotlinCompiler -output <outputDir> -src <filename or dirname>");
System.out.println("Usage: KotlinCompiler [-output <outputDir>|-jar <jarFileName>] -src <filename or dirname>");
t.printStackTrace();
return;
}
@@ -68,107 +65,238 @@ public class KotlinCompiler {
if (rtJar == null) return;
environment.addToClasspath(rtJar);
VirtualFile vFile = environment.getLocalFileSystem().findFileByPath(arguments.src);
if (vFile == null) {
System.out.print("File/directory not found: " + arguments.src);
return;
}
Project project = environment.getProject();
GenerationState generationState = new GenerationState(project, false);
List<JetNamespace> namespaces = Lists.newArrayList();
if(vFile.isDirectory()) {
File dir = new File(vFile.getPath());
addFiles(environment, project, namespaces, dir);
final File unpackedRuntimePath = getUnpackedRuntimePath();
if (unpackedRuntimePath != null) {
environment.addToClasspath(unpackedRuntimePath);
}
else {
PsiFile psiFile = PsiManager.getInstance(project).findFile(vFile);
if (psiFile instanceof JetFile) {
namespaces.add(((JetFile) psiFile).getRootNamespace());
final File runtimeJarPath = getRuntimeJarPath();
if (runtimeJarPath != null && runtimeJarPath.exists()) {
environment.addToClasspath(runtimeJarPath);
}
else {
System.out.print("Not a Kotlin file: " + vFile.getPath());
System.out.println("No runtime library found");
return;
}
}
BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespaces(project, namespaces, JetControlFlowDataTraceFactory.EMPTY);
if (arguments.module != null) {
compileModuleScript(environment, arguments.module);
return;
}
ErrorCollector errorCollector = new ErrorCollector(bindingContext);
errorCollector.report();
CompileSession session = new CompileSession(environment);
session.addSources(arguments.src);
if (!errorCollector.hasErrors) {
generationState.compileCorrectNamespaces(bindingContext, namespaces);
final ClassFileFactory factory = generationState.getFactory();
if(arguments.outputDir == null) {
System.out.println("Output directory is not specified - no files will be saved to the disk");
String mainClass = null;
for (JetNamespace namespace : session.getSourceFileNamespaces()) {
if (JetMainDetector.hasMain(namespace.getDeclarations())) {
mainClass = namespace.getFQName() + ".namespace";
break;
}
else {
List<String> files = factory.files();
for (String file : files) {
File target = new File(arguments.outputDir, file);
}
if (!session.analyze()) {
return;
}
ClassFileFactory factory = session.generate();
if (arguments.jar != null) {
writeToJar(factory, arguments.jar, mainClass, true);
}
else if (arguments.outputDir != null) {
writeToOutputDirectory(factory, arguments.outputDir);
}
else {
System.out.println("Output directory or jar file is not specified - no files will be saved to the disk");
}
}
private static void compileModuleScript(JetCoreEnvironment environment, String moduleFile) {
CompileSession scriptCompileSession = new CompileSession(environment);
scriptCompileSession.addSources(moduleFile);
URL url = KotlinCompiler.class.getClassLoader().getResource("ModuleBuilder.kt");
if (url != null) {
String path = url.getPath();
if (path.startsWith("file:")) {
path = path.substring(5);
}
final VirtualFile vFile = environment.getJarFileSystem().findFileByPath(path);
if (vFile == null) {
System.out.println("Couldn't load ModuleBuilder.kt from runtime jar: "+ url);
return;
}
scriptCompileSession.addSources(vFile);
}
else {
// building from source
final String homeDirectory = getHomeDirectory();
final File file = new File(homeDirectory, "stdlib/ktSrc/ModuleBuilder.kt");
scriptCompileSession.addSources(environment.getLocalFileSystem().findFileByPath(file.getPath()));
}
if (!scriptCompileSession.analyze()) {
return;
}
final ClassFileFactory factory = scriptCompileSession.generate();
final IModuleSetBuilder moduleSetBuilder = runDefineModules(moduleFile, factory);
for (IModuleBuilder moduleBuilder : moduleSetBuilder.getModules()) {
compileModule(environment, moduleBuilder, new File(moduleFile).getParent());
}
}
private static IModuleSetBuilder runDefineModules(String moduleFile, ClassFileFactory factory) {
GeneratedClassLoader loader = new GeneratedClassLoader(factory);
try {
Class moduleSetBuilderClass = loader.loadClass("kotlin.modules.ModuleSetBuilder");
final IModuleSetBuilder moduleSetBuilder = (IModuleSetBuilder) moduleSetBuilderClass.newInstance();
Class namespaceClass = loader.loadClass("namespace");
final Method[] methods = namespaceClass.getMethods();
boolean modulesDefined = false;
for (Method method : methods) {
if (method.getName().equals("defineModules")) {
method.invoke(null, moduleSetBuilder);
modulesDefined = true;
break;
}
}
if (!modulesDefined) {
System.out.println("Module script " + moduleFile + " must define a defineModules() method");
return null;
}
return moduleSetBuilder;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private static void compileModule(JetCoreEnvironment environment, IModuleBuilder moduleBuilder, String directory) {
CompileSession moduleCompileSession = new CompileSession(environment);
for (String sourceFile : moduleBuilder.getSourceFiles()) {
moduleCompileSession.addSources(new File(directory, sourceFile).getPath());
}
for (String classpathRoot : moduleBuilder.getClasspathRoots()) {
environment.addToClasspath(new File(classpathRoot));
}
if (!moduleCompileSession.analyze()) {
return;
}
ClassFileFactory factory = moduleCompileSession.generate();
writeToJar(factory, new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(), null, true);
}
private static String getHomeDirectory() {
return new File(PathManager.getResourceRoot(KotlinCompiler.class, "/org/jetbrains/jet/cli/KotlinCompiler.class")).getParentFile().getParentFile().getParent();
}
private static void writeToJar(ClassFileFactory factory, String jar, String mainClass, boolean includeRuntime) {
try {
Manifest manifest = new Manifest();
final Attributes mainAttributes = manifest.getMainAttributes();
mainAttributes.putValue("Manifest-Version", "1.0");
mainAttributes.putValue("Created-By", "JetBrains Kotlin");
if (mainClass != null) {
mainAttributes.putValue("Main-Class", mainClass);
}
FileOutputStream fos = new FileOutputStream(jar);
JarOutputStream stream = new JarOutputStream(fos, manifest);
try {
for (String file : factory.files()) {
stream.putNextEntry(new JarEntry(file));
stream.write(factory.asBytes(file));
}
if (includeRuntime) {
writeRuntimeToJar(stream);
}
}
finally {
stream.close();
fos.close();
}
} catch (IOException e) {
System.out.println("Failed to generate jar file: " + e.getMessage());
}
}
private static File getUnpackedRuntimePath() {
URL url = KotlinCompiler.class.getClassLoader().getResource("jet/JetObject.class");
if (url != null && url.getProtocol().equals("file")) {
return new File(url.getPath()).getParentFile().getParentFile();
}
return null;
}
private static File getRuntimeJarPath() {
URL url = KotlinCompiler.class.getClassLoader().getResource("jet/JetObject.class");
if (url != null && url.getProtocol().equals("jar")) {
String path = url.getPath();
return new File(path.substring(path.indexOf(":") + 1, path.indexOf("!/")));
}
return null;
}
private static void writeRuntimeToJar(final JarOutputStream stream) throws IOException {
final File unpackedRuntimePath = getUnpackedRuntimePath();
if (unpackedRuntimePath != null) {
FileUtil.processFilesRecursively(unpackedRuntimePath, new Processor<File>() {
@Override
public boolean process(File file) {
if (file.isDirectory()) return true;
final String relativePath = FileUtil.getRelativePath(unpackedRuntimePath, file);
try {
FileUtil.writeToFile(target, factory.asBytes(file));
System.out.println("Generated classfile: " + target);
stream.putNextEntry(new JarEntry(FileUtil.toSystemIndependentName(relativePath)));
FileInputStream fis = new FileInputStream(file);
try {
FileUtil.copy(fis, stream);
} finally {
fis.close();
}
} catch (IOException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
}
return true;
}
}
});
}
}
private static class ErrorCollector {
Multimap<PsiFile,DiagnosticWithTextRange> maps = LinkedHashMultimap.<PsiFile, DiagnosticWithTextRange>create();
boolean hasErrors;
public ErrorCollector(BindingContext bindingContext) {
for (Diagnostic diagnostic : bindingContext.getDiagnostics()) {
report(diagnostic);
}
}
private void report(Diagnostic diagnostic) {
hasErrors |= diagnostic.getSeverity() == Severity.ERROR;
if(diagnostic instanceof DiagnosticWithTextRange) {
DiagnosticWithTextRange diagnosticWithTextRange = (DiagnosticWithTextRange) diagnostic;
maps.put(diagnosticWithTextRange.getPsiFile(), diagnosticWithTextRange);
}
else {
System.out.println(diagnostic.getSeverity().toString() + ": " + diagnostic.getMessage());
}
}
void report() {
if(!maps.isEmpty()) {
for (PsiFile psiFile : maps.keySet()) {
System.out.println(psiFile.getVirtualFile().getPath());
Collection<DiagnosticWithTextRange> diagnosticWithTextRanges = maps.get(psiFile);
for (DiagnosticWithTextRange diagnosticWithTextRange : diagnosticWithTextRanges) {
String position = DiagnosticUtils.formatPosition(diagnosticWithTextRange);
System.out.println("\t" + diagnosticWithTextRange.getSeverity().toString() + ": " + position + " " + diagnosticWithTextRange.getMessage());
else {
File runtimeJarPath = getRuntimeJarPath();
if (runtimeJarPath != null) {
JarInputStream jis = new JarInputStream(new FileInputStream(runtimeJarPath));
try {
while (true) {
JarEntry e = jis.getNextJarEntry();
if (e == null) {
break;
}
if (FileUtil.getExtension(e.getName()).equals("class")) {
stream.putNextEntry(e);
FileUtil.copy(jis, stream);
}
}
}
}
}
}
private static void addFiles(JavaCoreEnvironment environment, Project project, List<JetNamespace> namespaces, File dir) {
for(File file : dir.listFiles()) {
if(!file.isDirectory()) {
VirtualFile virtualFile = environment.getLocalFileSystem().findFileByPath(file.getAbsolutePath());
PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
if (psiFile instanceof JetFile) {
namespaces.add(((JetFile) psiFile).getRootNamespace());
} finally {
jis.close();
}
}
else {
addFiles(environment, project, namespaces, file);
System.out.println("Couldn't find runtime library");
}
}
}
private static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) {
List<String> files = factory.files();
for (String file : files) {
File target = new File(outputDir, file);
try {
FileUtil.writeToFile(target, factory.asBytes(file));
System.out.println("Generated classfile: " + target);
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
@@ -1,23 +1,85 @@
package org.jetbrains.jet.lang.resolve.java;
import com.google.common.base.Predicates;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import java.util.Collection;
import java.util.Collections;
/**
* @author abreslav
*/
public class AnalyzerFacade {
public static final Function<JetFile, Collection<JetDeclaration>> SINGLE_DECLARATION_PROVIDER = new Function<JetFile, Collection<JetDeclaration>>() {
@Override
public Collection<JetDeclaration> fun(JetFile file) {
return Collections.<JetDeclaration>singleton(file.getRootNamespace());
}
};
private static final AnalyzingUtils ANALYZING_UTILS = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS);
private final static Key<CachedValue<BindingContext>> BINDING_CONTEXT = Key.create("BINDING_CONTEXT");
private static final Object lock = new Object();
public static BindingContext analyzeNamespace(@NotNull JetNamespace namespace, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
return AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespace(namespace, flowDataTraceFactory);
return ANALYZING_UTILS.analyzeNamespace(namespace, flowDataTraceFactory);
}
public static BindingContext analyzeFileWithCache(@NotNull JetFile file) {
return AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeFileWithCache(file);
public static BindingContext analyzeFileWithCache(@NotNull final JetFile file, @NotNull final Function<JetFile, Collection<JetDeclaration>> declarationProvider) {
return analyzeFileWithCache(ANALYZING_UTILS, file, declarationProvider);
}
public static BindingContext analyzeFileWithCache(@NotNull final AnalyzingUtils analyzingUtils,
@NotNull final JetFile file,
@NotNull final Function<JetFile, Collection<JetDeclaration>> declarationProvider) {
// TODO : Synchronization?
CachedValue<BindingContext> bindingContextCachedValue = file.getUserData(BINDING_CONTEXT);
if (bindingContextCachedValue == null) {
bindingContextCachedValue = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<BindingContext>() {
@Override
public Result<BindingContext> compute() {
synchronized (lock) {
try {
BindingContext bindingContext = analyzingUtils.analyzeNamespaces(
file.getProject(),
declarationProvider.fun(file),
Predicates.<PsiFile>equalTo(file),
JetControlFlowDataTraceFactory.EMPTY);
return new Result<BindingContext>(bindingContext, PsiModificationTracker.MODIFICATION_COUNT);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
e.printStackTrace();
BindingTraceContext bindingTraceContext = new BindingTraceContext();
bindingTraceContext.report(Errors.EXCEPTION_WHILE_ANALYZING.on(file, e));
return new Result<BindingContext>(bindingTraceContext.getBindingContext(), PsiModificationTracker.MODIFICATION_COUNT);
}
}
}
}, false);
file.putUserData(BINDING_CONTEXT, bindingContextCachedValue);
}
return bindingContextCachedValue.getValue();
}
}
@@ -300,15 +300,26 @@ public class JavaDescriptorResolver {
for (int i = 0, parametersLength = parameters.length; i < parametersLength; i++) {
PsiParameter parameter = parameters[i];
String name = parameter.getName();
PsiType psiType = parameter.getType();
JetType varargElementType;
if (psiType instanceof PsiEllipsisType) {
PsiEllipsisType psiEllipsisType = (PsiEllipsisType) psiType;
varargElementType = semanticServices.getTypeTransformer().transformToType(psiEllipsisType.getComponentType());
}
else {
varargElementType = null;
}
JetType outType = semanticServices.getTypeTransformer().transformToType(psiType);
result.add(new ValueParameterDescriptorImpl(
containingDeclaration,
i,
Collections.<AnnotationDescriptor>emptyList(), // TODO
name == null ? "p" + i : name,
null, // TODO : review
semanticServices.getTypeTransformer().transformToType(parameter.getType()),
outType,
false,
parameter.isVarArgs()
varargElementType
));
}
return result;
@@ -16,35 +16,6 @@ import java.util.*;
* @author abreslav
*/
public class FunctionDescriptorUtil {
/** @return Minimal number of arguments to be passed */
public static int getMinimumArity(@NotNull FunctionDescriptor functionDescriptor) {
int result = 0;
for (ValueParameterDescriptor valueParameter : functionDescriptor.getValueParameters()) {
if (valueParameter.hasDefaultValue()) {
break;
}
result++;
}
return result;
}
/**
* @return Maximum number of arguments that can be passed. -1 if unbound (vararg)
*/
public static int getMaximumArity(@NotNull FunctionDescriptor functionDescriptor) {
List<ValueParameterDescriptor> unsubstitutedValueParameters = functionDescriptor.getValueParameters();
if (unsubstitutedValueParameters.isEmpty()) {
return 0;
}
// TODO : check somewhere that vararg is only the last one, and that varargs do not have default values
ValueParameterDescriptor lastParameter = unsubstitutedValueParameters.get(unsubstitutedValueParameters.size() - 1);
if (lastParameter.isVararg()) {
return -1;
}
return unsubstitutedValueParameters.size();
}
public static Map<TypeConstructor, TypeProjection> createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List<JetType> typeArguments) {
if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap();
@@ -69,13 +40,16 @@ public class FunctionDescriptorUtil {
ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i);
// TODO : Lazy?
JetType substitutedType = substitutor.substitute(unsubstitutedValueParameter.getOutType(), Variance.IN_VARIANCE);
JetType varargElementType = unsubstitutedValueParameter.getVarargElementType();
JetType substituteVarargElementType = varargElementType == null ? null : substitutor.substitute(varargElementType, Variance.IN_VARIANCE);
if (substitutedType == null) return null;
result.add(new ValueParameterDescriptorImpl(
substitutedDescriptor,
unsubstitutedValueParameter,
unsubstitutedValueParameter.getAnnotations(),
unsubstitutedValueParameter.getInType() == null ? null : substitutedType,
substitutedType
substitutedType,
substituteVarargElementType
));
}
return result;
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.descriptors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.types.JetType;
/**
@@ -15,7 +16,7 @@ public interface ValueParameterDescriptor extends VariableDescriptor {
int getIndex();
boolean hasDefaultValue();
boolean isRef();
boolean isVararg();
@Nullable JetType getVarargElementType();
@Override
@NotNull
@@ -26,4 +27,5 @@ public interface ValueParameterDescriptor extends VariableDescriptor {
@NotNull
ValueParameterDescriptor copy(DeclarationDescriptor newOwner);
}
@@ -14,7 +14,7 @@ import java.util.List;
*/
public class ValueParameterDescriptorImpl extends VariableDescriptorImpl implements MutableValueParameterDescriptor {
private final boolean hasDefaultValue;
private final boolean isVararg;
private final JetType varargElementType;
private final boolean isVar;
private final int index;
private final ValueParameterDescriptor original;
@@ -27,12 +27,12 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
@Nullable JetType inType,
@NotNull JetType outType,
boolean hasDefaultValue,
boolean isVararg) {
@Nullable JetType varargElementType) {
super(containingDeclaration, annotations, name, inType, outType);
this.original = this;
this.index = index;
this.hasDefaultValue = hasDefaultValue;
this.isVararg = isVararg;
this.varargElementType = varargElementType;
this.isVar = inType != null;
}
@@ -41,13 +41,14 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
@NotNull ValueParameterDescriptor original,
@NotNull List<AnnotationDescriptor> annotations,
@Nullable JetType inType,
@NotNull JetType outType
@NotNull JetType outType,
@Nullable JetType varargElementType
) {
super(containingDeclaration, annotations, original.getName(), inType, outType);
this.original = original;
this.index = original.getIndex();
this.hasDefaultValue = original.hasDefaultValue();
this.isVararg = original.isVararg();
this.varargElementType = varargElementType;
this.isVar = inType != null;
}
@@ -76,9 +77,9 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
throw new UnsupportedOperationException(); // TODO
}
@Override
public boolean isVararg() {
return isVararg;
@Nullable
public JetType getVarargElementType() {
return varargElementType;
}
@NotNull
@@ -106,6 +107,6 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
@NotNull
@Override
public ValueParameterDescriptor copy(@NotNull DeclarationDescriptor newOwner) {
return new ValueParameterDescriptorImpl(newOwner, index, Lists.newArrayList(getAnnotations()), getName(), getInType(), getOutType(), hasDefaultValue, isVararg);
return new ValueParameterDescriptorImpl(newOwner, index, Lists.newArrayList(getAnnotations()), getName(), getInType(), getOutType(), hasDefaultValue, varargElementType);
}
}
@@ -15,8 +15,8 @@ import static org.jetbrains.jet.lang.diagnostics.Severity.ERROR;
public interface RedeclarationDiagnostic extends DiagnosticWithPsiElement<PsiElement> {
public class SimpleRedeclarationDiagnostic extends DiagnosticWithPsiElementImpl<PsiElement> implements RedeclarationDiagnostic {
public SimpleRedeclarationDiagnostic(@NotNull PsiElement psiElement) {
super(RedeclarationDiagnosticFactory.INSTANCE, ERROR, "Redeclaration", psiElement);
public SimpleRedeclarationDiagnostic(@NotNull PsiElement psiElement, @NotNull String name) {
super(RedeclarationDiagnosticFactory.INSTANCE, ERROR, "Redeclaration: " + name, psiElement);
}
}
@@ -66,7 +66,7 @@ public interface RedeclarationDiagnostic extends DiagnosticWithPsiElement<PsiEle
@NotNull
@Override
public String getMessage() {
return "Redeclaration";
return "Redeclaration: " + duplicatingDescriptor.getName();
}
@NotNull
@@ -16,8 +16,8 @@ public class RedeclarationDiagnosticFactory extends AbstractDiagnosticFactory {
public RedeclarationDiagnosticFactory() {}
public RedeclarationDiagnostic on(@NotNull PsiElement duplicatingElement) {
return new RedeclarationDiagnostic.SimpleRedeclarationDiagnostic(duplicatingElement);
public RedeclarationDiagnostic on(@NotNull PsiElement duplicatingElement, @NotNull String name) {
return new RedeclarationDiagnostic.SimpleRedeclarationDiagnostic(duplicatingElement, name);
}
public Diagnostic on(DeclarationDescriptor duplicatingDescriptor, BindingContext contextToResolveToDeclaration) {
@@ -167,7 +167,7 @@ public class JetParsing extends AbstractJetParsing {
}
PsiBuilder.Marker reference = mark();
expect(IDENTIFIER, "Expecting qualified name", TokenSet.create(DOT, AS_KEYWORD));
expect(IDENTIFIER, "Expecting qualified name");
reference.done(REFERENCE_EXPRESSION);
while (at(DOT) && lookahead(1) != MUL) {
advance(); // DOT
@@ -1,7 +1,6 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
@@ -105,17 +104,6 @@ public class JetClass extends JetTypeParameterListOwner implements JetClassOrObj
return body.getProperties();
}
public String getFQName() {
JetNamedDeclaration parent = PsiTreeUtil.getParentOfType(this, JetNamespace.class, JetClass.class);
if (parent instanceof JetNamespace) {
return ((JetNamespace) parent).getFQName() + "." + getName();
}
if (parent instanceof JetClass) {
return ((JetClass) parent).getFQName() + "." + getName();
}
return getName();
}
public boolean isTrait() {
return findChildByType(JetTokens.TRAIT_KEYWORD) != null;
}
@@ -59,6 +59,11 @@ public class JetParameter extends JetNamedDeclaration {
return findChildByType(JetTokens.VAR_KEYWORD) != null || isRef();
}
public boolean isVarArg() {
JetModifierList modifierList = getModifierList();
return modifierList != null && modifierList.getModifierNode(JetTokens.VARARG_KEYWORD) != null;
}
@Nullable
public ASTNode getValOrVarNode() {
ASTNode val = getNode().findChildByType(JetTokens.VAL_KEYWORD);
@@ -1,40 +1,33 @@
package org.jetbrains.jet.lang.resolve;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.diagnostics.*;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.DiagnosticHolder;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
//import org.jetbrains.jet.lang.resolve.java.JavaPackageScope;
//import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices;
/**
* @author abreslav
*/
public class AnalyzingUtils {
private final static Key<CachedValue<BindingContext>> BINDING_CONTEXT = Key.create("BINDING_CONTEXT");
private static final Object lock = new Object();
public static AnalyzingUtils getInstance(@NotNull ImportingStrategy importingStrategy) {
return new AnalyzingUtils(importingStrategy);
}
@@ -69,17 +62,24 @@ public class AnalyzingUtils {
Project project = namespace.getProject();
List<JetDeclaration> declarations = Collections.<JetDeclaration>singletonList(namespace);
return analyzeNamespaces(project, declarations, flowDataTraceFactory);
return analyzeNamespaces(project, declarations, Predicates.equalTo(namespace.getContainingFile()), flowDataTraceFactory);
}
public BindingContext analyzeNamespaces(@NotNull Project project, @NotNull List<? extends JetDeclaration> declarations, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
public BindingContext analyzeNamespaces(
@NotNull Project project,
@NotNull Collection<? extends JetDeclaration> declarations,
@NotNull Predicate<PsiFile> filesToAnalyzeCompletely,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
BindingTraceContext bindingTraceContext = new BindingTraceContext();
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project);
JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope();
ModuleDescriptor owner = new ModuleDescriptor("<module>");
final WritableScope scope = new WritableScopeImpl(libraryScope, owner, new TraceBasedRedeclarationHandler(bindingTraceContext)).setDebugName("Root scope in analyzeNamespace");
final WritableScope scope = new WritableScopeImpl(JetScope.EMPTY, owner, new TraceBasedRedeclarationHandler(bindingTraceContext)).setDebugName("Root scope in analyzeNamespace");
importingStrategy.addImports(project, semanticServices, bindingTraceContext, scope);
scope.importScope(libraryScope);
TopDownAnalyzer.process(semanticServices, bindingTraceContext, scope, new NamespaceLike.Adapter(owner) {
@Override
@@ -111,38 +111,8 @@ public class AnalyzingUtils {
public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
throw new IllegalStateException("Must be guaranteed not to happen by the parser");
}
}, declarations, flowDataTraceFactory);
}, declarations, filesToAnalyzeCompletely, flowDataTraceFactory);
return bindingTraceContext.getBindingContext();
}
public BindingContext analyzeFileWithCache(@NotNull final JetFile file) {
// TODO : Synchronization?
CachedValue<BindingContext> bindingContextCachedValue = file.getUserData(BINDING_CONTEXT);
if (bindingContextCachedValue == null) {
bindingContextCachedValue = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<BindingContext>() {
@Override
public Result<BindingContext> compute() {
synchronized (lock) {
try {
JetNamespace rootNamespace = file.getRootNamespace();
BindingContext bindingContext = analyzeNamespace(rootNamespace, JetControlFlowDataTraceFactory.EMPTY);
return new Result<BindingContext>(bindingContext, PsiModificationTracker.MODIFICATION_COUNT);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
e.printStackTrace();
BindingTraceContext bindingTraceContext = new BindingTraceContext();
// bindingTraceContext.getErrorHandler().genericError(file.getNode(), e.getClass().getSimpleName() + ": " + e.getMessage());
bindingTraceContext.report(Errors.EXCEPTION_WHILE_ANALYZING.on(file, e));
return new Result<BindingContext>(bindingTraceContext.getBindingContext(), PsiModificationTracker.MODIFICATION_COUNT);
}
}
}
}, false);
file.putUserData(BINDING_CONTEXT, bindingContextCachedValue);
}
return bindingContextCachedValue.getValue();
}
}
@@ -8,6 +8,9 @@ import org.jetbrains.jet.lang.psi.JetReferenceExpression;
* @author abreslav
*/
public class BindingContextUtils {
private BindingContextUtils() {
}
public static PsiElement resolveToDeclarationPsiElement(BindingContext bindingContext, JetReferenceExpression referenceExpression) {
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, referenceExpression);
if (declarationDescriptor == null) {
@@ -71,7 +71,6 @@ public class BodyResolver {
}
public void resolveBehaviorDeclarationBodies() {
resolveDelegationSpecifierLists();
@@ -86,34 +85,6 @@ public class BodyResolver {
computeDeferredTypes();
}
private void computeDeferredTypes() {
Collection<DeferredType> deferredTypes = context.getTrace().get(DEFERRED_TYPES, DEFERRED_TYPE_KEY);
if (deferredTypes != null) {
final Queue<DeferredType> queue = new Queue<DeferredType>(deferredTypes.size());
context.getTrace().addHandler(DEFERRED_TYPE, new ObservableBindingTrace.RecordHandler<BindingContext.DeferredTypeKey, DeferredType>() {
@Override
public void handleRecord(WritableSlice<BindingContext.DeferredTypeKey, DeferredType> deferredTypeKeyDeferredTypeWritableSlice, BindingContext.DeferredTypeKey key, DeferredType value) {
queue.addLast(value);
}
});
for (DeferredType deferredType : deferredTypes) {
queue.addLast(deferredType);
}
while (!queue.isEmpty()) {
DeferredType deferredType = queue.pullFirst();
if (!deferredType.isComputed()) {
try {
deferredType.getActualType(); // to compute
}
catch (ReenteringLazyValueComputationException e) {
// A problem should be reported while computing the type
}
}
}
}
}
private void resolveDelegationSpecifierLists() {
// TODO : Make sure the same thing is not initialized twice
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
@@ -125,6 +96,7 @@ public class BodyResolver {
}
private void resolveDelegationSpecifierList(final JetClassOrObject jetClass, final MutableClassDescriptor descriptor) {
if (!context.completeAnalysisNeeded(jetClass)) return;
final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor();
final JetScope scopeForConstructor = primaryConstructor == null
? null
@@ -278,7 +250,6 @@ public class BodyResolver {
}
private void resolveClassAnnotations() {
}
private void resolveAnonymousInitializers() {
@@ -291,6 +262,7 @@ public class BodyResolver {
}
private void resolveAnonymousInitializers(JetClassOrObject jetClassOrObject, MutableClassDescriptor classDescriptor) {
if (!context.completeAnalysisNeeded(jetClassOrObject)) return;
List<JetClassInitializer> anonymousInitializers = jetClassOrObject.getAnonymousInitializers();
if (jetClassOrObject.hasPrimaryConstructor()) {
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
@@ -320,6 +292,7 @@ public class BodyResolver {
}
private void resolveSecondaryConstructorBody(JetConstructor declaration, final ConstructorDescriptor descriptor, final JetScope declaringScope) {
if (!context.completeAnalysisNeeded(declaration)) return;
final JetScope functionInnerScope = getInnerScopeForConstructor(descriptor, declaringScope, false);
final CallResolver callResolver = new CallResolver(context.getSemanticServices(), DataFlowInfo.EMPTY); // TODO: dataFlowInfo
@@ -419,6 +392,7 @@ public class BodyResolver {
Set<JetProperty> processed = Sets.newHashSet();
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
JetClass jetClass = entry.getKey();
if (!context.completeAnalysisNeeded(jetClass)) continue;
MutableClassDescriptor classDescriptor = entry.getValue();
for (JetProperty property : jetClass.getProperties()) {
@@ -444,6 +418,7 @@ public class BodyResolver {
// Top-level properties & properties of objects
for (Map.Entry<JetProperty, PropertyDescriptor> entry : this.context.getProperties().entrySet()) {
JetProperty property = entry.getKey();
if (!context.completeAnalysisNeeded(property)) return;
if (processed.contains(property)) continue;
final PropertyDescriptor propertyDescriptor = entry.getValue();
@@ -540,6 +515,7 @@ public class BodyResolver {
@NotNull JetDeclarationWithBody function,
@NotNull FunctionDescriptor functionDescriptor,
@NotNull JetScope declaringScope) {
if (!context.completeAnalysisNeeded(function)) return;
JetExpression bodyExpression = function.getBodyExpression();
if (bodyExpression != null) {
@@ -564,4 +540,31 @@ public class BodyResolver {
assert functionDescriptor.getReturnType() != null;
}
private void computeDeferredTypes() {
Collection<DeferredType> deferredTypes = context.getTrace().get(DEFERRED_TYPES, DEFERRED_TYPE_KEY);
if (deferredTypes != null) {
final Queue<DeferredType> queue = new Queue<DeferredType>(deferredTypes.size());
context.getTrace().addHandler(DEFERRED_TYPE, new ObservableBindingTrace.RecordHandler<BindingContext.DeferredTypeKey, DeferredType>() {
@Override
public void handleRecord(WritableSlice<BindingContext.DeferredTypeKey, DeferredType> deferredTypeKeyDeferredTypeWritableSlice, BindingContext.DeferredTypeKey key, DeferredType value) {
queue.addLast(value);
}
});
for (DeferredType deferredType : deferredTypes) {
queue.addLast(deferredType);
}
while (!queue.isEmpty()) {
DeferredType deferredType = queue.pullFirst();
if (!deferredType.isComputed()) {
try {
deferredType.getActualType(); // to compute
}
catch (ReenteringLazyValueComputationException e) {
// A problem should be reported while computing the type
}
}
}
}
}
}
@@ -246,21 +246,56 @@ public class ClassDescriptorResolver {
@NotNull
public MutableValueParameterDescriptor resolveValueParameterDescriptor(DeclarationDescriptor declarationDescriptor, JetParameter valueParameter, int index, JetType type) {
JetType varargElementType = null;
JetType variableType = type;
if (valueParameter.hasModifier(JetTokens.VARARG_KEYWORD)) {
varargElementType = type;
variableType = getVarargParameterType(type);
}
MutableValueParameterDescriptor valueParameterDescriptor = new ValueParameterDescriptorImpl(
declarationDescriptor,
index,
annotationResolver.createAnnotationStubs(valueParameter.getModifierList()),
JetPsiUtil.safeName(valueParameter.getName()),
valueParameter.isMutable() ? type : null,
type,
valueParameter.isMutable() ? variableType : null,
variableType,
valueParameter.getDefaultValue() != null,
valueParameter.hasModifier(JetTokens.VARARG_KEYWORD)
varargElementType
);
trace.record(BindingContext.VALUE_PARAMETER, valueParameter, valueParameterDescriptor);
return valueParameterDescriptor;
}
private JetType getVarargParameterType(JetType type) {
JetStandardLibrary standardLibrary = semanticServices.getStandardLibrary();
if (type.equals(standardLibrary.getByteType())) {
return standardLibrary.getByteArrayType();
}
if (type.equals(standardLibrary.getCharType())) {
return standardLibrary.getCharArrayType();
}
if (type.equals(standardLibrary.getShortType())) {
return standardLibrary.getShortArrayType();
}
if (type.equals(standardLibrary.getIntType())) {
return standardLibrary.getIntArrayType();
}
if (type.equals(standardLibrary.getLongType())) {
return standardLibrary.getLongArrayType();
}
if (type.equals(standardLibrary.getFloatType())) {
return standardLibrary.getFloatArrayType();
}
if (type.equals(standardLibrary.getDoubleType())) {
return standardLibrary.getDoubleArrayType();
}
if (type.equals(standardLibrary.getBooleanType())) {
return standardLibrary.getBooleanArrayType();
}
return standardLibrary.getArrayType(type);
}
public List<TypeParameterDescriptor> resolveTypeParameters(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, List<JetTypeParameter> typeParameters) {
List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>();
for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
@@ -46,6 +46,8 @@ public class ControlFlowAnalyzer {
JetNamedFunction function = entry.getKey();
FunctionDescriptorImpl functionDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(function)) continue;
final JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType()
? NO_EXPECTED_TYPE
: functionDescriptor.getReturnType();
@@ -40,7 +40,8 @@ public class DeclarationsChecker {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
JetClass aClass = entry.getKey();
MutableClassDescriptor classDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(aClass)) continue;
checkClass(aClass, classDescriptor);
checkModifiers(aClass.getModifierList());
}
@@ -50,6 +51,7 @@ public class DeclarationsChecker {
JetObjectDeclaration objectDeclaration = entry.getKey();
MutableClassDescriptor objectDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(objectDeclaration)) continue;
checkObject(objectDeclaration, objectDescriptor);
}
@@ -58,6 +60,7 @@ public class DeclarationsChecker {
JetNamedFunction function = entry.getKey();
FunctionDescriptorImpl functionDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(function)) continue;
checkFunction(function, functionDescriptor);
checkModifiers(function.getModifierList());
}
@@ -67,6 +70,7 @@ public class DeclarationsChecker {
JetProperty property = entry.getKey();
PropertyDescriptor propertyDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(property)) continue;
checkProperty(property, propertyDescriptor);
checkModifiers(property.getModifierList());
}
@@ -77,6 +81,7 @@ public class DeclarationsChecker {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
MutableClassDescriptor classDescriptor = entry.getValue();
JetClass jetClass = entry.getKey();
if (!context.completeAnalysisNeeded(jetClass)) return;
if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null && !(classDescriptor.getKind() == ClassKind.TRAIT)) {
for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) {
if (context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
@@ -1,13 +1,18 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.base.Predicate;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import java.io.PrintStream;
import java.util.Map;
import java.util.Set;
@@ -32,10 +37,42 @@ import java.util.Set;
private final Map<JetProperty, PropertyDescriptor> properties = Maps.newLinkedHashMap();
private final Set<PropertyDescriptor> primaryConstructorParameterProperties = Sets.newHashSet();
public TopDownAnalysisContext(JetSemanticServices semanticServices, BindingTrace trace) {
private final Predicate<PsiFile> analyzeCompletely;
private StringBuilder debugOutput;
public TopDownAnalysisContext(JetSemanticServices semanticServices, BindingTrace trace, Predicate<PsiFile> analyzeCompletely) {
this.trace = new ObservableBindingTrace(trace);
this.semanticServices = semanticServices;
this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace);
this.analyzeCompletely = analyzeCompletely;
}
public void debug(Object message) {
if (debugOutput != null) {
debugOutput.append(message).append("\n");
}
}
/*package*/ void enableDebugOutput() {
if (debugOutput == null) {
debugOutput = new StringBuilder();
}
}
/*package*/ void printDebugOutput(PrintStream out) {
if (debugOutput != null) {
out.print(debugOutput);
}
}
public boolean completeAnalysisNeeded(@NotNull PsiElement element) {
PsiFile containingFile = element.getContainingFile();
boolean result = containingFile != null && analyzeCompletely.apply(containingFile);
if (!result) {
debug(containingFile);
}
return result;
}
public ObservableBindingTrace getTrace() {
@@ -1,15 +1,21 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* @author abreslav
@@ -22,35 +28,43 @@ public class TopDownAnalyzer {
@NotNull JetSemanticServices semanticServices,
@NotNull BindingTrace trace,
@NotNull JetScope outerScope,
NamespaceLike owner,
@NotNull List<? extends JetDeclaration> declarations,
@NotNull NamespaceLike owner,
@NotNull Collection<? extends JetDeclaration> declarations,
@NotNull Predicate<PsiFile> analyzeCompletely,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
process(semanticServices, trace, outerScope, owner, declarations, flowDataTraceFactory, false);
process(semanticServices, trace, outerScope, owner, declarations, analyzeCompletely, flowDataTraceFactory, false);
}
private static void process(
@NotNull JetSemanticServices semanticServices,
@NotNull BindingTrace trace,
@NotNull JetScope outerScope,
NamespaceLike owner,
@NotNull List<? extends JetDeclaration> declarations,
@NotNull NamespaceLike owner,
@NotNull Collection<? extends JetDeclaration> declarations,
@NotNull Predicate<PsiFile> analyzeCompletely,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory,
boolean declaredLocally) {
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace);
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, analyzeCompletely);
// context.enableDebugOutput();
context.debug("Enter");
new TypeHierarchyResolver(context).process(outerScope, owner, declarations);
new DeclarationResolver(context).process();
new DelegationResolver(context).process();
new OverrideResolver(context).process();
new BodyResolver(context).resolveBehaviorDeclarationBodies();
new ControlFlowAnalyzer(context, flowDataTraceFactory, declaredLocally).process();
new DeclarationsChecker(context).process();
new DeclarationsChecker(context).process();
context.debug("Exit");
context.printDebugOutput(System.out);
}
public static void processStandardLibraryNamespace(
@NotNull JetSemanticServices semanticServices,
@NotNull BindingTrace trace,
@NotNull WritableScope outerScope, @NotNull NamespaceDescriptorImpl standardLibraryNamespace, @NotNull JetNamespace namespace) {
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace);
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, Predicates.<PsiFile>alwaysTrue());
context.getNamespaceScopes().put(namespace, standardLibraryNamespace.getMemberScope());
context.getNamespaceDescriptors().put(namespace, standardLibraryNamespace);
context.getDeclaringScopes().put(namespace, outerScope);
@@ -104,7 +118,7 @@ public class TopDownAnalyzer {
public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
return ClassObjectStatus.NOT_ALLOWED;
}
}, Collections.<JetDeclaration>singletonList(object), JetControlFlowDataTraceFactory.EMPTY, true);
}, Collections.<JetDeclaration>singletonList(object), Predicates.equalTo(object.getContainingFile()), JetControlFlowDataTraceFactory.EMPTY, true);
}
}
@@ -26,7 +26,7 @@ public class TraceBasedRedeclarationHandler implements RedeclarationHandler {
private void report(DeclarationDescriptor first) {
PsiElement firstElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, first);
if (firstElement != null) {
trace.report(REDECLARATION.on(firstElement));
trace.report(REDECLARATION.on(firstElement, first.getName()));
}
else {
trace.report(REDECLARATION.on(first, trace.getBindingContext()));
@@ -36,7 +36,7 @@ public class TypeHierarchyResolver {
this.context = context;
}
public void process(@NotNull JetScope outerScope, NamespaceLike owner, @NotNull List<? extends JetDeclaration> declarations) {
public void process(@NotNull JetScope outerScope, @NotNull NamespaceLike owner, @NotNull Collection<? extends JetDeclaration> declarations) {
collectNamespacesAndClassifiers(outerScope, owner, declarations); // namespaceScopes, classes
processTypeImports();
@@ -387,13 +387,15 @@ public class CallResolver {
ResolvedValueArgument valueArgument = entry.getValue();
ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor);
for (JetExpression expression : valueArgument.getArgumentExpressions()) {
// JetExpression expression = valueArgument.getArgumentExpression();
// TODO : more attempts, with different expected types
ExpressionTypingServices temporaryServices = new ExpressionTypingServices(semanticServices, temporaryTrace);
JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE);
if (type != null) {
constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType());
constraintSystem.addSubtypingConstraint(type, effectiveExpectedType);
}
else {
candidateCall.argumentHasNoType();
@@ -512,6 +514,14 @@ public class CallResolver {
return results;
}
private JetType getEffectiveExpectedType(ValueParameterDescriptor valueParameterDescriptor) {
JetType effectiveExpectedType = valueParameterDescriptor.getVarargElementType();
if (effectiveExpectedType == null) {
effectiveExpectedType = valueParameterDescriptor.getOutType();
}
return effectiveExpectedType;
}
private void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) {
if (receiver instanceof AutoCastReceiver) {
AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver;
@@ -606,7 +616,7 @@ public class CallResolver {
ValueParameterDescriptor parameterDescriptor = entry.getKey();
ResolvedValueArgument resolvedArgument = entry.getValue();
JetType parameterType = parameterDescriptor.getOutType();
JetType parameterType = getEffectiveExpectedType(parameterDescriptor);
List<JetExpression> argumentExpressions = resolvedArgument.getArgumentExpressions();
for (JetExpression argumentExpression : argumentExpressions) {
@@ -84,7 +84,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
}
else if (!valueParameters.isEmpty()) {
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1);
if (valueParameterDescriptor.isVararg()) {
if (valueParameterDescriptor.getVarargElementType() != null) {
put(candidateCall, valueParameterDescriptor, valueArgument, varargs);
usedParameters.add(valueParameterDescriptor);
}
@@ -123,7 +123,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
}
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1);
if (valueParameterDescriptor.isVararg()) {
if (valueParameterDescriptor.getVarargElementType() != null) {
// temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Passing value as a vararg is only allowed inside a parenthesized argument list");
temporaryTrace.report(VARARG_OUTSIDE_PARENTHESES.on(possiblyLabeledFunctionLiteral));
error = true;
@@ -154,7 +154,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
if (valueParameter.hasDefaultValue()) {
candidateCall.recordValueArgument(valueParameter, DefaultValueArgument.DEFAULT);
}
else if (valueParameter.isVararg()) {
else if (valueParameter.getVarargElementType() != null) {
candidateCall.recordValueArgument(valueParameter, new VarargValueArgument());
}
else {
@@ -182,7 +182,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
}
private static <D extends CallableDescriptor> void put(ResolvedCallImpl<D> candidateCall, ValueParameterDescriptor valueParameterDescriptor, ValueArgument valueArgument, Map<ValueParameterDescriptor, VarargValueArgument> varargs) {
if (valueParameterDescriptor.isVararg()) {
if (valueParameterDescriptor.getVarargElementType() != null) {
VarargValueArgument vararg = varargs.get(valueParameterDescriptor);
if (vararg == null) {
vararg = new VarargValueArgument();
@@ -147,7 +147,7 @@ public class ErrorUtils {
ERROR_PARAMETER_TYPE,
ERROR_PARAMETER_TYPE,
false,
false));
null));
}
return result;
}
@@ -378,7 +378,7 @@ public class JetStandardClasses {
List<ValueParameterDescriptor> valueParameters = Lists.newArrayList();
for (int i = first; i <= last; i++) {
JetType parameterType = arguments.get(i).getType();
ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(functionDescriptor, i, Collections.<AnnotationDescriptor>emptyList(), "p" + i, null, parameterType, false, false);
ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(functionDescriptor, i, Collections.<AnnotationDescriptor>emptyList(), "p" + i, null, parameterType, false, null);
valueParameters.add(valueParameterDescriptor);
}
return valueParameters;
@@ -316,8 +316,8 @@ public class JetStandardLibrary {
}
@NotNull
public JetType getArrayType(@NotNull Variance variance, @NotNull JetType argument) {
List<TypeProjection> types = Collections.singletonList(new TypeProjection(variance, argument));
public JetType getArrayType(@NotNull Variance projectionType, @NotNull JetType argument) {
List<TypeProjection> types = Collections.singletonList(new TypeProjection(projectionType, argument));
return new JetTypeImpl(
Collections.<AnnotationDescriptor>emptyList(),
getArray().getTypeConstructor(),
@@ -87,7 +87,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
if (functionTypeExpected && declaredValueParameters.isEmpty() && expectedValueParameters.size() == 1) {
ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0);
ValueParameterDescriptor it = new ValueParameterDescriptorImpl(
functionDescriptor, 0, Collections.<AnnotationDescriptor>emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.isVararg()
functionDescriptor, 0, Collections.<AnnotationDescriptor>emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.getVarargElementType()
);
valueParameterDescriptors.add(it);
parameterTypes.add(it.getOutType());
@@ -0,0 +1,35 @@
package org.jetbrains.jet.plugin;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.jet.lang.psi.JetTypeReference;
import java.util.List;
/**
* @author yole
*/
public class JetMainDetector {
private JetMainDetector() {
}
public static boolean hasMain(List<JetDeclaration> declarations) {
for (JetDeclaration declaration : declarations) {
if (declaration instanceof JetNamedFunction) {
JetNamedFunction function = (JetNamedFunction) declaration;
if ("main".equals(function.getName())) {
List<JetParameter> parameters = function.getValueParameters();
if (parameters.size() == 1) {
JetTypeReference reference = parameters.get(0).getTypeReference();
if (reference != null && reference.getText().equals("Array<String>")) { // TODO correct check
return true;
}
}
}
}
}
return false;
}
}
@@ -133,7 +133,7 @@ public class DescriptorRenderer implements Renderer {
@Override
public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) {
builder.append(renderKeyword("value-parameter")).append(" ");
if (descriptor.isVararg()) {
if (descriptor.getVarargElementType() != null) {
builder.append(renderKeyword("vararg")).append(" ");
}
return super.visitValueParameterDescriptor(descriptor, builder);
@@ -0,0 +1,26 @@
// KT-389 Wrong type inference for varargs etc.
import java.util.*
fun foob(vararg a : Byte) : ByteArray = a
fun fooc(vararg a : Char) : CharArray = a
fun foos(vararg a : Short) : ShortArray = a
fun fooi(vararg a : Int) : IntArray = a
fun fool(vararg a : Long) : LongArray = a
fun food(vararg a : Double) : DoubleArray = a
fun foof(vararg a : Float) : FloatArray = a
fun foob(vararg a : Boolean) : BooleanArray = a
fun foos(vararg a : String) : Array<String> = a
fun test() {
Arrays.asList(1, 2, 3)
Arrays.asList<Int>(1, 2, 3)
foob(1, 2, 3)
foos(1, 2, 3)
fooc('1', '2', '3')
fooi(1, 2, 3)
fool(1, 2, 3)
food(1.0, 2.0, 3.0)
foof(1.0.flt, 2.0.flt, 3.0.flt)
}
@@ -10,3 +10,14 @@ namespace b {
}
}
namespace c {
import d.X
val x : X = X()
}
namespace d {
class X() {
}
}
@@ -0,0 +1,15 @@
// KT-127 Support extension functions in when expressions
class Foo() {}
fun Any.equals(other : Any?) : Boolean = true
fun Any?.equals1(other : Any?) : Boolean = true
fun main(args: Array<String>) {
val command : Foo? = null
when (command) {
.equals(null) => 1; // must be resolved
?.equals(null) => 1 // same here
}
}
@@ -0,0 +1,12 @@
// KT-128 Support passing only the last closure if all the other parameters have default values
fun div(c : String = "", f : fun()) {}
fun f() {
div { // Nothing passed, but could have been...
// ...
}
div (c = "foo") { // More things could have been passed
// ...
}
}
@@ -0,0 +1,7 @@
// KT-26 Import namespaces defined in this file
namespace foo {
import bar.* // Must not be an error
}
namespace bar {}
@@ -0,0 +1,10 @@
// KT-26 Import namespaces defined in this file
import html.* // Must not be an error
namespace html {
abstract class Factory<T> {
fun create() : T? = null
}
}
@@ -0,0 +1,18 @@
// KT-282 Nullability in extension functions and in binary calls
class Set {
fun contains(x : Int) : Boolean = true
}
fun Set?.plus(x : Int) : Int = 1
fun Int?.contains(x : Int) : Boolean = false
fun f(): Unit {
var set : Set? = null
val i : Int? = null
i <!UNSAFE_INFIX_CALL!>+<!> 1
set + 1
1 <!UNSAFE_INFIX_CALL!>in<!> set
1 in 2
}
@@ -0,0 +1,4 @@
fun box() : String {
var a = 10
return if(a?.plus(10) == 20) "OK" else "fail"
}
+7 -3
View File
@@ -18,7 +18,8 @@ JetFile: Imports_ERR.jet
PsiWhiteSpace(' ')
REFERENCE_EXPRESSION
PsiErrorElement:Expecting qualified name
PsiElement(SEMICOLON)(';')
<empty list>
PsiElement(SEMICOLON)(';')
PsiWhiteSpace('\n')
IMPORT_DIRECTIVE
PsiElement(import)('import')
@@ -27,7 +28,9 @@ JetFile: Imports_ERR.jet
PsiElement(DOT)('.')
REFERENCE_EXPRESSION
PsiErrorElement:Expecting qualified name
PsiElement(MUL)('*')
<empty list>
PsiErrorElement:Expecting namespace or top level declaration
PsiElement(MUL)('*')
PsiWhiteSpace('\n')
IMPORT_DIRECTIVE
PsiElement(import)('import')
@@ -37,7 +40,8 @@ JetFile: Imports_ERR.jet
PsiWhiteSpace(' ')
REFERENCE_EXPRESSION
PsiErrorElement:Expecting qualified name
PsiElement(SEMICOLON)(';')
<empty list>
PsiElement(SEMICOLON)(';')
PsiWhiteSpace('\n\n')
IMPORT_DIRECTIVE
PsiElement(import)('import')
@@ -8,6 +8,7 @@ import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.ImportingStrategy;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import java.util.Collections;
import java.util.List;
@@ -80,7 +81,7 @@ public class CheckerTestUtilTest extends JetLiteFixture {
}
public void test(PsiFile psiFile) {
BindingContext bindingContext = AnalyzingUtils.getInstance(ImportingStrategy.NONE).analyzeFileWithCache((JetFile) psiFile);
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE), (JetFile) psiFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER);
String expectedText = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString();
List<CheckerTestUtil.DiagnosedRange> diagnosedRanges = Lists.newArrayList();
@@ -42,7 +42,7 @@ public class FullJetPsiCheckerTest extends JetLiteFixture {
String clearText = CheckerTestUtil.parseDiagnosedRanges(expectedText, diagnosedRanges);
myFile = createPsiFile(myName, clearText);
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(myFile);
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(myFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER);
CheckerTestUtil.diagnosticsDiff(diagnosedRanges, bindingContext.getDiagnostics(), new CheckerTestUtil.DiagnosticDiffCallbacks() {
@Override
@@ -12,6 +12,7 @@ import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.ImportingStrategy;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import java.util.List;
@@ -39,7 +40,7 @@ public class QuickJetPsiCheckerTest extends JetLiteFixture {
createAndCheckPsiFile(name, clearText);
JetFile jetFile = (JetFile) myFile;
BindingContext bindingContext = AnalyzingUtils.getInstance(ImportingStrategy.NONE).analyzeFileWithCache(jetFile);
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE), jetFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER);
CheckerTestUtil.diagnosticsDiff(diagnosedRanges, bindingContext.getDiagnostics(), new CheckerTestUtil.DiagnosticDiffCallbacks() {
@Override
@@ -88,7 +88,7 @@ public abstract class CodegenTestCase extends JetLiteFixture {
protected String blackBox() throws Exception {
ClassFileFactory codegens = generateClassesInFile();
CodegensClassLoader loader = new CodegensClassLoader(codegens);
GeneratedClassLoader loader = new GeneratedClassLoader(codegens);
final JetNamespace namespace = myFile.getRootNamespace();
String fqName = NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", ".");
@@ -215,23 +215,4 @@ public abstract class CodegenTestCase extends JetLiteFixture {
return super.loadClass(name);
}
}
private static class CodegensClassLoader extends ClassLoader {
private final ClassFileFactory state;
public CodegensClassLoader(ClassFileFactory state) {
super(CodegenTestCase.class.getClassLoader());
this.state = state;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String file = name.replace('.', '/') + ".class";
if (state.files().contains(file)) {
byte[] bytes = state.asBytes(file);
return defineClass(name, bytes, 0, bytes.length);
}
return super.findClass(name);
}
}
}
@@ -207,4 +207,9 @@ public class ControlStructuresTest extends CodegenTestCase {
public void testKt299() throws Exception {
blackBoxFile("regressions/kt299.jet");
}
public void testKt416() throws Exception {
blackBoxFile("regressions/kt416.jet");
System.out.println(generateToText());
}
}
@@ -8,22 +8,55 @@ import java.lang.reflect.Method;
*/
public class VarArgTest extends CodegenTestCase {
public void testStringArray () throws InvocationTargetException, IllegalAccessException {
/*
loadText("fun test(vararg ts: String) = ts");
System.out.println(generateToText());
final Method main = generateFunction();
Object[] args = {"mama", "papa"};
assertTrue(args == main.invoke(null, args));
*/
String[] args = {"mama", "papa"};
assertTrue(args == main.invoke(null, new Object[]{ args } ));
}
public void testIntArray () throws InvocationTargetException, IllegalAccessException {
/*
loadText("fun test(vararg ts: Int) = ts");
System.out.println(generateToText());
final Method main = generateFunction();
int[] args = {3, 4};
assertTrue(args == main.invoke(null, args));
*/
assertTrue(args == main.invoke(null, new Object[]{ args }));
}
public void testIntArrayKotlinNoArgs () throws InvocationTargetException, IllegalAccessException {
loadText("fun test() = testf(); fun testf(vararg ts: Int) = ts");
System.out.println(generateToText());
final Method main = generateFunction();
Object res = main.invoke(null, new Object[]{});
assertTrue(((int[])res).length == 0);
}
public void testIntArrayKotlin () throws InvocationTargetException, IllegalAccessException {
loadText("fun test() = testf(239, 7); fun testf(vararg ts: Int) = ts");
System.out.println(generateToText());
final Method main = generateFunction();
Object res = main.invoke(null, new Object[]{});
assertTrue(((int[])res).length == 2);
assertTrue(((int[])res)[0] == 239);
assertTrue(((int[])res)[1] == 7);
}
public void testNullableIntArrayKotlin () throws InvocationTargetException, IllegalAccessException {
loadText("fun test() = testf(239.byt, 7.byt); fun testf(vararg ts: Byte?) = ts");
System.out.println(generateToText());
final Method main = generateFunction();
Object res = main.invoke(null, new Object[]{});
assertTrue(((Byte[])res).length == 2);
assertTrue(((Byte[])res)[0] == (byte)239);
assertTrue(((Byte[])res)[1] == 7);
}
public void testIntArrayKotlinObj () throws InvocationTargetException, IllegalAccessException {
loadText("fun test() = testf(\"239\"); fun testf(vararg ts: String) = ts");
System.out.println(generateToText());
final Method main = generateFunction();
Object res = main.invoke(null, new Object[]{});
assertTrue(((String[])res).length == 1);
assertTrue(((String[])res)[0].equals("239"));
}
}
@@ -44,7 +44,7 @@ public class JetDefaultModalityModifiersTest extends JetLiteFixture {
List<JetDeclaration> declarations = file.getRootNamespace().getDeclarations();
JetDeclaration aClass = declarations.get(0);
assert aClass instanceof JetClass;
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file);
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER);
DeclarationDescriptor classDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, aClass);
WritableScopeImpl scope = new WritableScopeImpl(libraryScope, root, RedeclarationHandler.DO_NOTHING);
assert classDescriptor instanceof ClassifierDescriptor;
+72
View File
@@ -0,0 +1,72 @@
Code Generation 2012 - Session Proposal Form
Submission Deadline: Friday December 9th 2011
Session title:
DSLs in Kotlin
Session type and duration:
Tutorial, 60 min
Session abstract:
Kotlin is a statically typed programming language for the JVM, proposed recently by JetBrains. The language is intended for industrial use as a safer and more convenient alternative to Java. The language is fully Java compatible, so one can mix Kotlin and Java sources in the same project. Language documentation is available at http://jetbrains.com/kotlin.
In this session we will demonstrate Kotlin's abilities to define APIs as domain-specific languages (DSLs). This includes explanation of interesting language features illustrated with practical use-cases.
As a flagship example we will present Type-safe Builders, a technique that improves upon Groovy builders (http://groovy.codehaus.org/Builders) by making them statically checked for correctness. This enables specifying declarative data right inside the code. Want to describe a build file? Xml/HTML? Swing UI? Use builders! We will show how Kotlin compiler itself uses builders to specify modules. Along with this example we will show and explain a few other DSLs built in Kotlin.
Benefits of participating:
Participants will learn about Kotlin and how a few language features can be combined to create internal DSLs in a natural and flexible way.
Process & timetable:
Introduction to Kotlin — 7-10 minutes
Q&A - 5 minutes
DSL-enabling features - 15 minutes
Q&A - 5 minutes
Builders (live demo) - 20 minutes
Q&A - 5 minutes
Session outputs:
Slides, example code
Intended Audience:
The session is intended for developers and tech leads.
We expect the audience to be familiar with basic concepts of OOP and some of the statically typed languages (Java, Scala, C#, C++ etc).
Availability:
No constraints
Detailed Description / Supporting Information
Kotlin is a new statically typed JVM-targeted programming language developed by JetBrains and intended for industrial use. Kotlin is designed to be fully Java compatible, and at the same time safer, more concise than Java and way simpler than its main competitor, Scala. Also, IDE support is being developed in parallel with the language itself.
This session focuses on the language features that enable DSL creation and corresponding patterns.
During the introduction, we will give an overview of the language. The features were planning to cover include:
* function literals (closures);
* extension functions;
* type inference;
* operator overloading/overriding;
* null safety and automatic casts.
As a flagship example we will present type-safe builders, a technique that improves upon Groovy builders (http://groovy.codehaus.org/Builders) by making them statically checked for correctness. Builders are a flexible and clean way of describing declarative data in the code with very little syntactic overhead. The technique is so handy that Kotlin uses it instead of XML for compiler configuration, which we will show in action along with XML/HTML and Swing UI building.
This part is presented as a live demo within the IntelliJ IDEA IDE for Kotlin. Along with this example we'll demonstrate a DSL for LINQ-like collection processing and how to turn any type into a Fluent interface (http://martinfowler.com/bliki/FluentInterface.html) with extension functions.
This session has not been run before, but the material we use is partly taken from Kotlin talks from OSCON, StrangeLoop and Devoxx.
Main presenter name, contact details and biography
Name: Andrey Breslav
Affiliation: JetBrains
Telephone / Skype: andrey.breslav @ skype
Email: andrey.breslav@jetbrains.com
Biography (up to 100 words):
Andrey is the lead language designer working on Project Kotlin. He joined JetBrains in 2010.
+7
View File
@@ -0,0 +1,7 @@
import kotlin.modules.ModuleSetBuilder
fun defineModules(builder: ModuleSetBuilder) {
builder.module("hello") {
source files "HelloNames.kt"
}
}
-1
View File
@@ -20,7 +20,6 @@
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="stdlib" />
<orderEntry type="module" module-name="cli" />
<orderEntry type="module" module-name="compiler-tests" />
</component>
</module>
@@ -8,7 +8,7 @@ import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.resolve.DescriptorRenderer;
/**
@@ -26,7 +26,7 @@ public class JetQuickDocumentationProvider extends AbstractDocumentationProvider
ref = PsiTreeUtil.getParentOfType(originalElement, JetReferenceExpression.class);
}
if (ref != null) {
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache((JetFile) element.getContainingFile());
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) element.getContainingFile());
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, ref);
if (declarationDescriptor != null) {
return render(declarationDescriptor);
@@ -11,6 +11,7 @@ import org.jetbrains.jet.checkers.CheckerTestUtil;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
@@ -28,7 +29,7 @@ public class CopyAsDiagnosticTestAction extends AnAction {
PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE);
assert editor != null && psiFile != null;
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache((JetFile) psiFile);
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) psiFile);
String result = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString();
@@ -12,9 +12,9 @@ import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.JetLanguage;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
/**
* @author yole
@@ -26,7 +26,7 @@ public class ShowExpressionTypeAction extends AnAction {
PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE);
assert editor != null && psiFile != null;
JetExpression expression;
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache((JetFile) psiFile);
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) psiFile);
if (editor.getSelectionModel().hasSelection()) {
int startOffset = editor.getSelectionModel().getSelectionStart();
int endOffset = editor.getSelectionModel().getSelectionEnd();
@@ -20,6 +20,7 @@ import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.JetHighlighter;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import java.util.Collection;
import java.util.Set;
@@ -53,7 +54,7 @@ public class DebugInfoAnnotator implements Annotator {
if (element instanceof JetFile) {
JetFile file = (JetFile) element;
try {
final BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file);
final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
final Set<JetReferenceExpression> unresolvedReferences = Sets.newHashSet();
for (Diagnostic diagnostic : bindingContext.getDiagnostics()) {
@@ -24,7 +24,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import javax.swing.*;
@@ -45,7 +45,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
JetFile file = PsiTreeUtil.getParentOfType(element, JetFile.class);
if (file == null) return null;
final BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file);
final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
if (element instanceof JetClass) {
JetClass jetClass = (JetClass) element;
@@ -25,6 +25,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.JetHighlighter;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.plugin.quickfix.JetIntentionActionFactory;
import org.jetbrains.jet.plugin.quickfix.QuickFixes;
@@ -54,12 +55,13 @@ public class JetPsiChecker implements Annotator {
JetFile file = (JetFile) element;
Project project = element.getProject();
try {
final BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file);
final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
if (errorReportingEnabled) {
Collection<Diagnostic> diagnostics = Sets.newLinkedHashSet(bindingContext.getDiagnostics());
Set<PsiElement> redeclarations = Sets.newHashSet();
for (Diagnostic diagnostic : diagnostics) {
if (diagnostic.getFactory().getPsiFile(diagnostic) != file) continue; // This is needed because we have the same context for all files
Annotation annotation = null;
if (diagnostic.getSeverity() == Severity.ERROR) {
if (diagnostic instanceof UnresolvedReferenceDiagnostic) {
@@ -1,5 +1,6 @@
package org.jetbrains.jet.plugin.compiler;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompileContext;
@@ -66,16 +67,21 @@ public class JetCompiler implements TranslatingCompiler {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
VirtualFile[] allFiles = compileContext.getCompileScope().getFiles(null, true);
GenerationState generationState = new GenerationState(compileContext.getProject(), false);
List<JetNamespace> namespaces = Lists.newArrayList();
for (VirtualFile virtualFile : virtualFiles) {
for (VirtualFile virtualFile : allFiles) {
PsiFile psiFile = PsiManager.getInstance(compileContext.getProject()).findFile(virtualFile);
if (psiFile instanceof JetFile) {
namespaces.add(((JetFile) psiFile).getRootNamespace());
}
}
BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespaces(compileContext.getProject(), namespaces, JetControlFlowDataTraceFactory.EMPTY);
BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespaces(
compileContext.getProject(), namespaces,
Predicates.<PsiFile>alwaysTrue(),
JetControlFlowDataTraceFactory.EMPTY);
boolean errors = false;
for (Diagnostic diagnostic : bindingContext.getDiagnostics()) {
@@ -0,0 +1,63 @@
package org.jetbrains.jet.plugin.compiler;
import com.google.common.collect.Sets;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.ex.CompilerPathsEx;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.plugin.JetFileType;
import java.util.Collection;
import java.util.Set;
/**
* @author abreslav
*/
public class WholeProjectAnalyzerFacade {
public static final Function<JetFile, Collection<JetDeclaration>> WHOLE_PROJECT_DECLARATION_PROVIDER = new Function<JetFile, Collection<JetDeclaration>>() {
@Override
public Collection<JetDeclaration> fun(final JetFile rootFile) {
final Project project = rootFile.getProject();
final Set<JetDeclaration> namespaces = Sets.newLinkedHashSet();
ProjectRootManager rootManager = ProjectRootManager.getInstance(project);
if (rootManager != null && !ApplicationManager.getApplication().isUnitTestMode()) {
VirtualFile[] contentRoots = rootManager.getContentRoots();
CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() {
@Override
protected void acceptFile(VirtualFile file, String fileRoot, String filePath) {
final FileType fileType = FileTypeManager.getInstance().getFileTypeByFile(file);
if (fileType != JetFileType.INSTANCE) return;
PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
if (psiFile instanceof JetFile) {
if (rootFile.getOriginalFile() != psiFile) {
namespaces.add(((JetFile) psiFile).getRootNamespace());
}
}
}
});
}
namespaces.add(rootFile.getRootNamespace());
return namespaces;
}
};
@NotNull
public static BindingContext analyzeProjectWithCacheOnAFile(@NotNull JetFile file) {
return AnalyzerFacade.analyzeFileWithCache(file, WHOLE_PROJECT_DECLARATION_PROVIDER);
}
}
@@ -21,8 +21,8 @@ import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import java.util.*;
@@ -125,7 +125,7 @@ public class JetPositionManager implements PositionManager {
if (mapper != null) {
return mapper;
}
final BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file);
final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(myDebugProcess.getProject());
final JetTypeMapper typeMapper = new JetTypeMapper(standardLibrary, bindingContext);
file.acceptChildren(new JetVisitorVoid() {
@@ -12,7 +12,7 @@ import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import java.util.Collection;
@@ -76,7 +76,7 @@ public abstract class JetPsiReference implements PsiPolyVariantReference {
protected PsiElement doResolve() {
JetFile file = (JetFile) getElement().getContainingFile();
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file);
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
PsiElement psiElement = BindingContextUtils.resolveToDeclarationPsiElement(bindingContext, myExpression);
if (psiElement != null) {
return psiElement;
@@ -88,7 +88,7 @@ public abstract class JetPsiReference implements PsiPolyVariantReference {
protected ResolveResult[] doMultiResolve() {
JetFile file = (JetFile) getElement().getContainingFile();
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file);
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
Collection<? extends ResolvedCallImpl<? extends DeclarationDescriptor>> resolvedCalls = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression);
if (resolvedCalls == null) return ResolveResult.EMPTY_ARRAY;
ResolveResult[] results = new ResolveResult[resolvedCalls.size()];
@@ -13,9 +13,9 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import java.util.List;
@@ -51,7 +51,7 @@ class JetSimpleNameReference extends JetPsiReference {
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) parent;
JetExpression receiverExpression = qualifiedExpression.getReceiverExpression();
JetFile file = (JetFile) myExpression.getContainingFile();
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file);
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
final JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, receiverExpression);
if (expressionType != null) {
return collectLookupElements(bindingContext, expressionType.getMemberScope());
@@ -59,7 +59,7 @@ class JetSimpleNameReference extends JetPsiReference {
}
else {
JetFile file = (JetFile) myExpression.getContainingFile();
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file);
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
JetScope resolutionScope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, myExpression);
if (resolutionScope != null) {
return collectLookupElements(bindingContext, resolutionScope);
@@ -8,9 +8,12 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.jet.lang.psi.*;
import java.util.List;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamedDeclaration;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.plugin.JetMainDetector;
/**
* @author yole
@@ -22,6 +25,17 @@ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer im
super(JetRunConfigurationType.getInstance());
}
private static String getFQName(JetClass jetClass) {
JetNamedDeclaration parent = PsiTreeUtil.getParentOfType(jetClass, JetNamespace.class, JetClass.class);
if (parent instanceof JetNamespace) {
return ((JetNamespace) parent).getFQName() + "." + jetClass.getName();
}
if (parent instanceof JetClass) {
return getFQName(((JetClass) parent)) + "." + jetClass.getName();
}
return jetClass.getName();
}
@Override
public PsiElement getSourceElement() {
return mySourceElement;
@@ -30,14 +44,14 @@ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer im
@Override
protected RunnerAndConfigurationSettings createConfigurationByElement(Location location, ConfigurationContext configurationContext) {
JetClass containingClass = (JetClass) location.getParentElement(JetClass.class);
if (containingClass != null && hasMain(containingClass.getDeclarations())) {
if (containingClass != null && JetMainDetector.hasMain(containingClass.getDeclarations())) {
mySourceElement = containingClass;
return createConfigurationByQName(location.getModule(), configurationContext, containingClass.getFQName());
return createConfigurationByQName(location.getModule(), configurationContext, getFQName(containingClass));
}
PsiFile psiFile = location.getPsiElement().getContainingFile();
if (psiFile instanceof JetFile) {
JetNamespace namespace = ((JetFile) psiFile).getRootNamespace();
if (hasMain(namespace.getDeclarations())) {
if (JetMainDetector.hasMain(namespace.getDeclarations())) {
mySourceElement = namespace;
return createConfigurationByQName(location.getModule(), configurationContext, namespace.getFQName() + ".namespace");
}
@@ -45,25 +59,6 @@ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer im
return null;
}
private boolean hasMain(List<JetDeclaration> declarations) {
for (JetDeclaration declaration : declarations) {
if (declaration instanceof JetNamedFunction) {
JetNamedFunction function = (JetNamedFunction) declaration;
if ("main".equals(function.getName())) {
List<JetParameter> parameters = function.getValueParameters();
if (parameters.size() == 1) {
JetTypeReference reference = parameters.get(0).getTypeReference();
if (reference != null && reference.getText().equals("Array<String>")) { // TODO correct check
return true;
}
}
}
}
}
return false;
}
private RunnerAndConfigurationSettings createConfigurationByQName(Module module, ConfigurationContext context, String fqName) {
RunnerAndConfigurationSettings settings = cloneTemplateConfiguration(module.getProject(), context);
JetRunConfiguration configuration = (JetRunConfiguration) settings.getConfiguration();
+11 -3
View File
@@ -1,15 +1,20 @@
namespace kotlin.modules
namespace kotlin
namespace modules {
import java.util.*
import jet.modules.*
class ModuleSetBuilder() {
val modules: ArrayList<ModuleBuilder> = ArrayList<ModuleBuilder>()
class ModuleSetBuilder(): IModuleSetBuilder {
val modules: ArrayList<IModuleBuilder?> = ArrayList<IModuleBuilder?>()
fun module(name: String, callback: fun ModuleBuilder.()) {
val builder = ModuleBuilder(name)
builder.callback()
modules.add(builder)
}
override fun getModules(): List<IModuleBuilder?>? = modules
}
class SourcesBuilder(val parent: ModuleBuilder) {
@@ -44,4 +49,7 @@ class ModuleBuilder(val name: String): IModuleBuilder {
override fun getSourceFiles(): List<String?>? = sourceFiles
override fun getClasspathRoots(): List<String?>? = classpathRoots
override fun getModuleName(): String? = name
}
}
@@ -6,6 +6,7 @@ import java.util.List;
* @author yole
*/
public interface IModuleBuilder {
String getModuleName();
List<String> getSourceFiles();
List<String> getClasspathRoots();
}
@@ -0,0 +1,10 @@
package jet.modules;
import java.util.List;
/**
* @author yole
*/
public interface IModuleSetBuilder {
List<IModuleBuilder> getModules();
}