diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index e40f788a295..760f71eb505 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -24,23 +24,24 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.di.InjectorForJvmCodegen; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor; import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; -import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.jet.lang.psi.JetObjectDeclaration; -import org.jetbrains.jet.lang.psi.JetObjectLiteralExpression; +import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; import org.jetbrains.jet.lang.resolve.java.JvmClassName; +import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.utils.Progress; import org.objectweb.asm.commons.Method; +import java.util.Collection; import java.util.List; +import java.util.Map; public class GenerationState { private final Project project; @@ -123,22 +124,29 @@ public class GenerationState { } public void compileCorrectFiles(@NotNull CompilationErrorHandler errorHandler) { + MultiMap namespaceGrouping = new MultiMap(); for (JetFile file : this.files) { if (file == null) throw new IllegalArgumentException("A null file given for compilation"); - VirtualFile vFile = file.getVirtualFile(); - String path = vFile != null ? vFile.getPath() : "no_virtual_file/" + file.getName(); - progress.log("For source: " + path); - try { - generateNamespace(file); - } - catch (ProcessCanceledException e) { - throw e; - } - catch (Throwable e) { - errorHandler.reportException(e, vFile == null ? "no file" : vFile.getUrl()); - DiagnosticUtils.throwIfRunningOnServer(e); - if (ApplicationManager.getApplication().isInternal()) { - e.printStackTrace(); + namespaceGrouping.putValue(JetPsiUtil.getFQName(file).getFqName(), file); + } + + for (Map.Entry> entry : namespaceGrouping.entrySet()) { + for (JetFile file : entry.getValue()) { + VirtualFile vFile = file.getVirtualFile(); + String path = vFile != null ? vFile.getPath() : "no_virtual_file/" + file.getName(); + progress.log("For source: " + path + "\tFor namespace: " + entry.getKey()); + try { + generateNamespace(file); + } + catch (ProcessCanceledException e) { + throw e; + } + catch (Throwable e) { + errorHandler.reportException(e, vFile == null ? "no file" : vFile.getUrl()); + DiagnosticUtils.throwIfRunningOnServer(e); + if (ApplicationManager.getApplication().isInternal()) { + e.printStackTrace(); + } } } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java index e4d15257626..4ccc5b9f563 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java @@ -92,6 +92,17 @@ public enum AnalyzerFacadeForJVM implements AnalyzerFacade { Predicates.alwaysTrue(), compilerDependencies); } + public static AnalyzeExhaust analyzeFilesWithJavaIntegrationAndCheckForErrors( + Project project, Collection files, List scriptParameters, Predicate filesToAnalyzeCompletely, + @NotNull CompilerDependencies compilerDependencies) { + AnalyzeExhaust analyzeExhaust = analyzeFilesWithJavaIntegration( + project, files, scriptParameters, filesToAnalyzeCompletely, compilerDependencies, false); + + AnalyzingUtils.throwExceptionOnErrors(analyzeExhaust.getBindingContext()); + + return analyzeExhaust; + } + public static AnalyzeExhaust analyzeFilesWithJavaIntegration( Project project, Collection files, List scriptParameters, Predicate filesToAnalyzeCompletely, @NotNull CompilerDependencies compilerDependencies) { diff --git a/compiler/testData/codegen/multi/simple/box.kt b/compiler/testData/codegen/multi/simple/box.kt new file mode 100644 index 00000000000..a334e87b623 --- /dev/null +++ b/compiler/testData/codegen/multi/simple/box.kt @@ -0,0 +1 @@ +fun box() = ok() \ No newline at end of file diff --git a/compiler/testData/codegen/multi/simple/ok.kt b/compiler/testData/codegen/multi/simple/ok.kt new file mode 100644 index 00000000000..654494514f0 --- /dev/null +++ b/compiler/testData/codegen/multi/simple/ok.kt @@ -0,0 +1 @@ +fun ok() = "OK" \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTest.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTest.java index 2876f7fbabb..ea3c9f867bc 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTest.java @@ -206,8 +206,8 @@ public class JetDiagnosticsTest extends JetLiteFixture { // String clearText = pattern.matcher(text).replaceAll(""); // createAndCheckPsiFile(name, clearText); // -// BindingContext bindingContext = AnalyzingUtils.getInstance(ImportingStrategy.NONE).analyzeFileWithCache((JetFile) myFile); -// String expectedText = CheckerTestUtil.addDiagnosticMarkersToText(myFile, bindingContext).toString(); +// BindingContext bindingContext = AnalyzingUtils.getInstance(ImportingStrategy.NONE).analyzeFileWithCache((JetFile) myFiles); +// String expectedText = CheckerTestUtil.addDiagnosticMarkersToText(myFiles, bindingContext).toString(); // // File destFile = new File(dest, file.getName()); // FileWriter fileWriter = new FileWriter(destFile); diff --git a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java index 0bafdce297a..1b5d98eedb7 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java +++ b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java @@ -17,23 +17,20 @@ package org.jetbrains.jet.codegen; import com.google.common.base.Objects; +import com.google.common.base.Predicates; import com.google.common.collect.Lists; import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiFile; import com.intellij.testFramework.UsefulTestCase; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; -import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetPsiUtil; -import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM; import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; -import org.jetbrains.jet.lang.resolve.name.FqName; -import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.types.ref.JetTypeName; import org.jetbrains.jet.parsing.JetParsingTest; import org.objectweb.asm.Type; @@ -48,8 +45,6 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.Collections; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * @author yole @@ -59,7 +54,7 @@ public abstract class CodegenTestCase extends UsefulTestCase { // for environment and classloader protected JetCoreEnvironment myEnvironment; private List extraClasspath = Lists.newArrayList(); - protected CodegenTestFile myFile; + protected CodegenTestFiles myFiles; protected Object scriptInstance; @@ -107,26 +102,30 @@ public abstract class CodegenTestCase extends UsefulTestCase { @Override protected void tearDown() throws Exception { - myFile = null; + myFiles = null; myEnvironment = null; scriptInstance = null; super.tearDown(); } protected void loadText(final String text) { - myFile = CodegenTestFile.create("a.jet", text, myEnvironment.getProject()); + myFiles = CodegenTestFiles.create("a.jet", text, myEnvironment.getProject()); } protected String loadFile(final String name) { try { final String content = JetTestUtils.doLoadFile(JetParsingTest.getTestDataDir() + "/codegen/", name); - myFile = CodegenTestFile.create(name, content, myEnvironment.getProject()); + myFiles = CodegenTestFiles.create(name, content, myEnvironment.getProject()); return content; } catch (IOException e) { throw new RuntimeException(e); } } + protected void loadFiles(final String... names) { + myFiles = CodegenTestFiles.create(myEnvironment.getProject(), names); + } + protected void loadFile() { loadFile(getPrefix() + "/" + getTestName(true) + ".jet"); } @@ -140,6 +139,11 @@ public abstract class CodegenTestCase extends UsefulTestCase { blackBox(); } + protected void blackBoxMultiFile(String... filenames) { + loadFiles(filenames); + blackBox(); + } + @NotNull private Class loadClassFromType(@NotNull Type type) { try { @@ -186,15 +190,15 @@ public abstract class CodegenTestCase extends UsefulTestCase { String r; try { - if (myFile.getPsiFile().isScript()) { + if (myFiles.isScript()) { Class scriptClass = loader.loadClass("Script"); Constructor constructor = getConstructor(scriptClass, state.getScriptConstructorMethod()); - scriptInstance = constructor.newInstance(myFile.getScriptParameterValues().toArray()); + scriptInstance = constructor.newInstance(myFiles.getScriptParameterValues().toArray()); - assertFalse("expecting at least one expectation", myFile.getExpectedValues().isEmpty()); + assertFalse("expecting at least one expectation", myFiles.getExpectedValues().isEmpty()); - for (Pair nameValue : myFile.getExpectedValues()) { + for (Pair nameValue : myFiles.getExpectedValues()) { String fieldName = nameValue.first; String expectedValue = nameValue.second; @@ -215,7 +219,7 @@ public abstract class CodegenTestCase extends UsefulTestCase { } } else { - String fqName = NamespaceCodegen.getJVMClassNameForKotlinNs(JetPsiUtil.getFQName(myFile.getPsiFile())).getFqName().getFqName(); + String fqName = NamespaceCodegen.getJVMClassNameForKotlinNs(JetPsiUtil.getFQName(myFiles.getPsiFiles().get(0))).getFqName().getFqName(); Class namespaceClass = loader.loadClass(fqName); Method method = namespaceClass.getMethod("box"); r = (String) method.invoke(null); @@ -250,12 +254,15 @@ public abstract class CodegenTestCase extends UsefulTestCase { } private GenerationState generateCommon(ClassBuilderFactory classBuilderFactory) { - final AnalyzeExhaust analyzeExhaust = AnalyzerFacadeForJVM.analyzeOneFileWithJavaIntegrationAndCheckForErrors( - myFile.getPsiFile(), myFile.getScriptParameterTypes(), + final AnalyzeExhaust analyzeExhaust = AnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationAndCheckForErrors( + myEnvironment.getProject(), + myFiles.getPsiFiles(), + myFiles.getScriptParameterTypes(), + Predicates.alwaysTrue(), myEnvironment.getCompilerDependencies()); analyzeExhaust.throwIfError(); AnalyzingUtils.throwExceptionOnErrors(analyzeExhaust.getBindingContext()); - GenerationState state = new GenerationState(myEnvironment.getProject(), classBuilderFactory, analyzeExhaust, Collections.singletonList(myFile.getPsiFile())); + GenerationState state = new GenerationState(myEnvironment.getProject(), classBuilderFactory, analyzeExhaust, myFiles.getPsiFiles()); state.compileCorrectFiles(CompilationErrorHandler.THROW_EXCEPTION); return state; } @@ -271,7 +278,7 @@ public abstract class CodegenTestCase extends UsefulTestCase { } protected Class loadRootNamespaceClass(@NotNull ClassFileFactory state) { - String fqName = NamespaceCodegen.getJVMClassNameForKotlinNs(JetPsiUtil.getFQName(myFile.getPsiFile())).getFqName().getFqName(); + String fqName = NamespaceCodegen.getJVMClassNameForKotlinNs(JetPsiUtil.getFQName(myFiles.getPsiFile())).getFqName().getFqName(); try { return createClassLoader(state).loadClass(fqName); } catch (ClassNotFoundException e) { diff --git a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestFile.java b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestFiles.java similarity index 72% rename from compiler/tests/org/jetbrains/jet/codegen/CodegenTestFile.java rename to compiler/tests/org/jetbrains/jet/codegen/CodegenTestFiles.java index c77b450f3fc..48dc5d3e094 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestFile.java +++ b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestFiles.java @@ -23,21 +23,23 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter; -import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.ref.JetTypeName; +import org.jetbrains.jet.parsing.JetParsingTest; -import java.util.List; +import java.io.IOException; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author Stepan Koltsov + * @author alex.tkachman */ -public class CodegenTestFile { +public class CodegenTestFiles { @NotNull - private final JetFile psiFile; + private final List psiFiles; @NotNull private final List> expectedValues; @NotNull @@ -45,12 +47,12 @@ public class CodegenTestFile { @NotNull private final List scriptParameterValues; - private CodegenTestFile( - @NotNull JetFile psiFile, + private CodegenTestFiles( + @NotNull List psiFiles, @NotNull List> expectedValues, @NotNull List scriptParameterTypes, @NotNull List scriptParameterValues) { - this.psiFile = psiFile; + this.psiFiles = psiFiles; this.expectedValues = expectedValues; this.scriptParameterTypes = scriptParameterTypes; this.scriptParameterValues = scriptParameterValues; @@ -58,7 +60,8 @@ public class CodegenTestFile { @NotNull public JetFile getPsiFile() { - return psiFile; + assert psiFiles.size() == 1; + return psiFiles.get(0); } @NotNull @@ -77,7 +80,30 @@ public class CodegenTestFile { } @NotNull - public static CodegenTestFile create(@NotNull String fileName, @NotNull String content, @NotNull Project project) { + public List getPsiFiles() { + return psiFiles; + } + + public boolean isScript() { + return psiFiles.size() == 1 && psiFiles.get(0).isScript(); + } + + public static CodegenTestFiles create(Project project, String[] names) { + ArrayList files = new ArrayList(); + for (String name : names) { + try { + String content = JetTestUtils.doLoadFile(JetParsingTest.getTestDataDir() + "/codegen/", name); + JetFile file = (JetFile) JetTestUtils.createFile(name, content, project); + files.add(file); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return new CodegenTestFiles(files, Collections.>emptyList(), Collections.emptyList(), Collections.emptyList()); + } + + @NotNull + public static CodegenTestFiles create(@NotNull String fileName, @NotNull String content, @NotNull Project project) { JetFile file = (JetFile) JetTestUtils.createFile(fileName, content, project); List> expectedValues = Lists.newArrayList(); @@ -123,6 +149,6 @@ public class CodegenTestFile { } } - return new CodegenTestFile(file, expectedValues, scriptParameterTypes, scriptParameterValues); + return new CodegenTestFiles(Collections.singletonList(file), expectedValues, scriptParameterTypes, scriptParameterValues); } } diff --git a/compiler/tests/org/jetbrains/jet/codegen/MultiFileGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/MultiFileGenTest.java new file mode 100644 index 00000000000..0dfef5f0251 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/codegen/MultiFileGenTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen; + +import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; + +import java.lang.reflect.Method; + +public class MultiFileGenTest extends CodegenTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + createEnvironmentWithMockJdkAndIdeaAnnotations(CompilerSpecialMode.JDK_HEADERS); + } + + public void testSimple() { + blackBoxMultiFile("/multi/simple/box.kt", "/multi/simple/ok.kt"); + System.out.println(generateToText()); + } +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java index 3b4a8c9c151..b46008785f9 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java @@ -150,7 +150,7 @@ public class StdlibTest extends CodegenTestCase { GeneratedClassLoader loader = createClassLoader(codegens); try { - String fqName = NamespaceCodegen.getJVMClassNameForKotlinNs(JetPsiUtil.getFQName(myFile.getPsiFile())).getFqName().getFqName(); + String fqName = NamespaceCodegen.getJVMClassNameForKotlinNs(JetPsiUtil.getFQName(myFiles.getPsiFile())).getFqName().getFqName(); Class namespaceClass = loader.loadClass(fqName); Method method = namespaceClass.getMethod("box", Method.class); method.setAccessible(true);