diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index 2a3c0d45b67..e83fd50e11e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -82,11 +82,12 @@ public class GenerationState { return factory.forNamespace(namespace); } - public void compile(JetFile psiFile) { + public BindingContext compile(JetFile psiFile) { final JetNamespace namespace = psiFile.getRootNamespace(); final BindingContext bindingContext = AnalyzerFacade.analyzeOneNamespaceWithJavaIntegration(namespace, JetControlFlowDataTraceFactory.EMPTY); AnalyzingUtils.throwExceptionOnErrors(bindingContext); compileCorrectNamespaces(bindingContext, Collections.singletonList(namespace)); + return bindingContext; // NamespaceCodegen codegen = forNamespace(namespace); // bindingContexts.push(bindingContext); // typeMapper = new JetTypeMapper(standardLibrary, bindingContext); diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java index cf23d5c948b..ba0f2765822 100644 --- a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java @@ -356,7 +356,7 @@ public class CompileEnvironment { } } - private static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) { + public static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) { List files = factory.files(); for (String file : files) { if(!skipFile(file)) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index f37b2993d9a..fef54bc7f40 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -332,7 +332,6 @@ public class JavaDescriptorResolver { } private ValueParameterDescriptor resolveParameterDescriptor(DeclarationDescriptor containingDeclaration, int i, PsiParameter parameter) { - String name = parameter.getName(); PsiType psiType = parameter.getType(); JetType varargElementType; @@ -343,14 +342,41 @@ public class JavaDescriptorResolver { else { varargElementType = null; } + + boolean nullable = true; + + // TODO: must be very slow, make it lazy? + String name = parameter.getName() != null ? parameter.getName() : "p" + i; + for (PsiAnnotation annotation : parameter.getModifierList().getAnnotations()) { + // TODO: softcode annotation name + + PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); + attributes.toString(); + + if (annotation.getQualifiedName().equals("jet.typeinfo.JetParameter")) { + PsiLiteralExpression nameExpression = (PsiLiteralExpression) annotation.findAttributeValue("name"); + if (nameExpression != null) { + name = (String) nameExpression.getValue(); + } + + PsiLiteralExpression nullableExpression = (PsiLiteralExpression) annotation.findAttributeValue("nullable"); + if (nullableExpression != null) { + nullable = (Boolean) nullableExpression.getValue(); + } else { + // default value of parameter + nullable = false; + } + } + } + JetType outType = semanticServices.getTypeTransformer().transformToType(psiType); return new ValueParameterDescriptorImpl( containingDeclaration, i, Collections.emptyList(), // TODO - name == null ? "p" + i : name, + name, null, // TODO : review - outType, + TypeUtils.makeNullableAsSpecified(outType, nullable), false, varargElementType ); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java index 11b92aee25a..776e5219dfc 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.resolve.java; +import com.intellij.psi.PsiClass; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl; @@ -34,7 +35,17 @@ public class JavaPackageScope extends JetScopeImpl { @NotNull @Override public Set getFunctions(@NotNull String name) { - return Collections.emptySet(); + // TODO: what is GlobalSearchScope + PsiClass psiClass = semanticServices.getDescriptorResolver().javaFacade.findClass(packagePrefix + "namespace"); + if (psiClass == null) { + return Collections.emptySet(); + } + + if (containingDescriptor == null) { + return Collections.emptySet(); + } + + return semanticServices.getDescriptorResolver().resolveFunctionGroup(containingDescriptor, psiClass, null, name, true); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java b/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java index eac28f341d6..65218c54fcf 100644 --- a/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java +++ b/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java @@ -1,6 +1,7 @@ package org.jetbrains.jet; import com.intellij.core.JavaCoreEnvironment; +import com.intellij.lang.java.JavaParserDefinition; import com.intellij.openapi.Disposable; import org.jetbrains.jet.lang.parsing.JetParserDefinition; import org.jetbrains.jet.plugin.JetFileType; @@ -15,6 +16,7 @@ public class JetCoreEnvironment extends JavaCoreEnvironment { registerFileType(JetFileType.INSTANCE, "kts"); registerFileType(JetFileType.INSTANCE, "ktm"); registerFileType(JetFileType.INSTANCE, "jet"); + registerParserDefinition(new JavaParserDefinition()); registerParserDefinition(new JetParserDefinition()); } } diff --git a/compiler/testData/readClass/Class.kt b/compiler/testData/readClass/Class.kt new file mode 100644 index 00000000000..957e3e9c54d --- /dev/null +++ b/compiler/testData/readClass/Class.kt @@ -0,0 +1,3 @@ +namespace test + +class Ramification diff --git a/compiler/testData/readClass/ClassFun.kt b/compiler/testData/readClass/ClassFun.kt new file mode 100644 index 00000000000..27eb0bc5e37 --- /dev/null +++ b/compiler/testData/readClass/ClassFun.kt @@ -0,0 +1,5 @@ +namespace test + +class River { + fun song() = 1 +} diff --git a/compiler/testData/readClass/FunParamNotNull.kt b/compiler/testData/readClass/FunParamNotNull.kt new file mode 100644 index 00000000000..72d84f88278 --- /dev/null +++ b/compiler/testData/readClass/FunParamNotNull.kt @@ -0,0 +1,3 @@ +namespace test + +fun fff(a: String) = 1 diff --git a/compiler/testData/readClass/FunParamNullable.kt b/compiler/testData/readClass/FunParamNullable.kt new file mode 100644 index 00000000000..288582a2f08 --- /dev/null +++ b/compiler/testData/readClass/FunParamNullable.kt @@ -0,0 +1,3 @@ +namespace test + +fun fff(a: String?) = 1 diff --git a/compiler/testData/readClass/NsFun.kt b/compiler/testData/readClass/NsFun.kt new file mode 100644 index 00000000000..6fc14ecc6df --- /dev/null +++ b/compiler/testData/readClass/NsFun.kt @@ -0,0 +1,3 @@ +namespace test + +fun f() = 1 diff --git a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java new file mode 100644 index 00000000000..67380ad3cee --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java @@ -0,0 +1,245 @@ +package org.jetbrains.jet; + +import com.intellij.lang.ASTFactory; +import com.intellij.lang.LanguageASTFactory; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.CharsetToolkit; +import com.intellij.psi.PsiFileFactory; +import com.intellij.psi.impl.PsiFileFactoryImpl; +import com.intellij.psi.impl.source.tree.JavaASTFactory; +import com.intellij.testFramework.LightVirtualFile; +import com.intellij.testFramework.UsefulTestCase; +import junit.framework.Test; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.codegen.ClassBuilderFactory; +import org.jetbrains.jet.codegen.ClassFileFactory; +import org.jetbrains.jet.codegen.GenerationState; +import org.jetbrains.jet.compiler.CompileEnvironment; +import org.jetbrains.jet.lang.JetSemanticServices; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +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.BindingTraceContext; +import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; +import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; +import org.jetbrains.jet.plugin.JetLanguage; +import org.junit.Assert; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Set; + +/** + * @author Stepan Koltsov + */ +public class ReadClassDataTest extends UsefulTestCase { + + protected final Disposable myTestRootDisposable = new Disposable() { + @Override + public void dispose() { + } + }; + + private JetCoreEnvironment jetCoreEnvironment; + private File tmpdir; + + private final File testFile; + + public ReadClassDataTest(@NotNull File testFile) { + this.testFile = testFile; + setName(testFile.getName()); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + tmpdir = new File("tmp/" + this.getClass().getSimpleName() + "." + this.getName()); + rmrf(tmpdir); + mkdirs(tmpdir); + } + + @Override + public void tearDown() throws Exception { + Disposer.dispose(myTestRootDisposable); + } + + private void mkdirs(File file) throws IOException { + if (file.isDirectory()) { + return; + } + if (!file.mkdirs()) { + throw new IOException(); + } + } + + private void rmrf(File file) { + if (file != null) { + File[] children = file.listFiles(); + if (children != null) { + for (File child : children) { + rmrf(child); + } + } + file.delete(); + } + } + + private void createMockCoreEnvironment() { + jetCoreEnvironment = new JetCoreEnvironment(myTestRootDisposable); + + final File rtJar = new File(JetTestCaseBuilder.getHomeDirectory(), "compiler/testData/mockJDK-1.7/jre/lib/rt.jar"); + jetCoreEnvironment.addToClasspath(rtJar); + jetCoreEnvironment.addToClasspath(new File(JetTestCaseBuilder.getHomeDirectory(), "compiler/testData/mockJDK-1.7/jre/lib/annotations.jar")); + } + + @Override + public void runTest() throws Exception { + createMockCoreEnvironment(); + + LanguageASTFactory.INSTANCE.addExplicitExtension(JavaLanguage.INSTANCE, new JavaASTFactory()); + + + String text = FileUtil.loadFile(testFile); + + LightVirtualFile virtualFile = new LightVirtualFile("Hello.kt", JetLanguage.INSTANCE, text); + virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET); + JetFile psiFile = (JetFile) ((PsiFileFactoryImpl) PsiFileFactory.getInstance(jetCoreEnvironment.getProject())).trySetupPsiForFile(virtualFile, JetLanguage.INSTANCE, true, false); + + GenerationState state = new GenerationState(jetCoreEnvironment.getProject(), ClassBuilderFactory.BINARIES); + AnalyzingUtils.checkForSyntacticErrors(psiFile); + BindingContext bindingContext = state.compile(psiFile); + + ClassFileFactory classFileFactory = state.getFactory(); + + CompileEnvironment.writeToOutputDirectory(classFileFactory, tmpdir.getPath()); + + NamespaceDescriptor namespaceFromSource = (NamespaceDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiFile.getRootNamespace()); + + Assert.assertEquals("test", namespaceFromSource.getName()); + + Disposer.dispose(myTestRootDisposable); + + + + createMockCoreEnvironment(); + + jetCoreEnvironment.addToClasspath(tmpdir); + + JetSemanticServices jetSemanticServices = JetSemanticServices.createSemanticServices(jetCoreEnvironment.getProject()); + JavaSemanticServices semanticServices = new JavaSemanticServices(jetCoreEnvironment.getProject(), jetSemanticServices, new BindingTraceContext()); + + JavaDescriptorResolver javaDescriptorResolver = semanticServices.getDescriptorResolver(); + NamespaceDescriptor namespaceFromClass = javaDescriptorResolver.resolveNamespace("test"); + + compareNamespaces(namespaceFromSource, namespaceFromClass); + } + + private void compareNamespaces(@NotNull NamespaceDescriptor nsa, @NotNull NamespaceDescriptor nsb) { + Assert.assertEquals(nsa.getName(), nsb.getName()); + System.out.println("namespace " + nsa.getName()); + for (DeclarationDescriptor ad : nsa.getMemberScope().getAllDescriptors()) { + if (ad instanceof ClassifierDescriptor) { + ClassifierDescriptor bd = nsb.getMemberScope().getClassifier(ad.getName()); + compareClassifiers((ClassifierDescriptor) ad, bd); + } else if (ad instanceof FunctionDescriptor) { + Set functions = nsb.getMemberScope().getFunctions(ad.getName()); + Assert.assertTrue(functions.size() >= 1); + Assert.assertTrue("not implemented", functions.size() == 1); + FunctionDescriptor bd = functions.iterator().next(); + compareFunctions((FunctionDescriptor) ad, bd); + } else { + throw new AssertionError("Unknown member: " + ad); + } + } + } + + private void compareClassifiers(@NotNull ClassifierDescriptor a, @NotNull ClassifierDescriptor b) { + Assert.assertEquals(a.getName(), b.getName()); + System.out.println("classifier " + a.getName()); + if (a instanceof ClassDescriptor || b instanceof ClassDescriptor) { + compareClasses((ClassDescriptor) a, (ClassDescriptor) b); + } + } + + private void compareClasses(@NotNull ClassDescriptor a, @NotNull ClassDescriptor b) { + System.out.println("... is class"); + } + + private void compareFunctions(@NotNull FunctionDescriptor a, @NotNull FunctionDescriptor b) { + Assert.assertEquals(a.getName(), b.getName()); + Assert.assertEquals(a.getValueParameters().size(), b.getValueParameters().size()); + for (int i = 0; i < a.getValueParameters().size(); ++i) { + compareAnything(ValueParameterDescriptor.class, a.getValueParameters().get(i), b.getValueParameters().get(i)); + } + System.out.println("function " + a.getName()); + } + + private void compareAnything(Class clazz, T a, T b) { + System.out.println("Comparing " + clazz); + Assert.assertNotNull(a); + Assert.assertNotNull(b); + + for (Method method : clazz.getMethods()) { + if (!isGetter(method)) { + continue; + } + if (method.getName().equals("getContainingDeclaration")) { + continue; + } + + if (clazz.equals(ValueParameterDescriptor.class)) { + if (method.getName().equals("isRef") || method.getName().equals("getOriginal")) { + continue; + } + } + + System.out.println(method.getName()); + Object ap = invoke(method, a); + Object bp = invoke(method, b); + Assert.assertEquals(ap, bp); + } + } + + private static boolean isGetter(Method method) { + if (method.getParameterTypes().length > 0) { + return false; + } + if (method.getName().matches("is.+")) { + return method.getReturnType().equals(boolean.class); + } else if (method.getName().matches("get.+")) { + return true; + } else { + return false; + } + } + + private static Object invoke(Method method, Object thiz, Object... args) { + try { + return method.invoke(thiz, args); + } catch (Exception e) { + throw new RuntimeException("failed to invoke " + method + ": " + e); + } + } + + public static Test suite() { + return JetTestCaseBuilder.suiteForDirectory(JetTestCaseBuilder.getTestDataPathBase(), "/readClass", true, new JetTestCaseBuilder.NamedTestFactory() { + @NotNull + @Override + public Test createTest(@NotNull String dataPath, @NotNull String name, @NotNull File file) { + return new ReadClassDataTest(file); + } + }); + } + +}