From 9983a567d4256464515a04f8a046fe5734c7f1c7 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 16 May 2014 14:59:04 +0400 Subject: [PATCH] Multi-module diagnostic tests supported Test added for internal visibility --- .../diagnostics/tests/multimodule/internal.kt | 35 +++++++ .../checkers/AbstractJetDiagnosticsTest.java | 94 ++++++++++++++++--- .../jet/checkers/BaseDiagnosticsTest.java | 77 +++++++++++++-- .../checkers/JetDiagnosticsTestGenerated.java | 16 +++- 4 files changed, 200 insertions(+), 22 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/multimodule/internal.kt diff --git a/compiler/testData/diagnostics/tests/multimodule/internal.kt b/compiler/testData/diagnostics/tests/multimodule/internal.kt new file mode 100644 index 00000000000..ff8362245e4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multimodule/internal.kt @@ -0,0 +1,35 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +// MODULE: m1 +// FILE: a.kt + +package p + +public class A { + val a = A() + var v = A() + fun a() = A() + inner class B +} + +val a = A() +var v = A() +fun a() = A() +class B + +// MODULE: m2(m1) +// FILE: b.kt + +import p.* + +fun test() { + val _a = a + val _v = v + a() + B() + + val inst = A() + val ia = inst.a + val iv = inst.v + inst.a() + inst.B() +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/AbstractJetDiagnosticsTest.java b/compiler/tests/org/jetbrains/jet/checkers/AbstractJetDiagnosticsTest.java index 311aa1f8965..83b3780e720 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/AbstractJetDiagnosticsTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/AbstractJetDiagnosticsTest.java @@ -21,25 +21,27 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import kotlin.Function1; +import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.cli.jvm.compiler.CliLightClassGenerationSupport; +import org.jetbrains.jet.context.ContextPackage; +import org.jetbrains.jet.context.GlobalContext; import org.jetbrains.jet.descriptors.serialization.descriptors.MemberFilter; +import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJvm; +import org.jetbrains.jet.lang.descriptors.DependencyKind; +import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl; import org.jetbrains.jet.lang.diagnostics.*; import org.jetbrains.jet.lang.psi.JetElement; 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.Diagnostics; +import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.calls.model.MutableResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM; import java.io.File; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; @@ -47,27 +49,91 @@ public abstract class AbstractJetDiagnosticsTest extends BaseDiagnosticsTest { @Override protected void analyzeAndCheck(File testDataFile, List testFiles) { - List jetFiles = getJetFiles(testFiles); + Map> groupedByModule = KotlinPackage.groupByTo( + testFiles, + new LinkedHashMap>(), + new Function1() { + @Override + public TestModule invoke(TestFile file) { + return file.getModule(); + } + } + ); CliLightClassGenerationSupport support = CliLightClassGenerationSupport.getInstanceForCli(getProject()); + BindingTrace trace = support.getTrace(); - BindingContext bindingContext = AnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration( - getProject(), jetFiles, support.getTrace(), - Predicates.alwaysTrue(), support.getModule(), - MemberFilter.ALWAYS_TRUE).getBindingContext(); + List allJetFiles = new ArrayList(); + Map modules = createModules(groupedByModule); + + for (Map.Entry> entry : groupedByModule.entrySet()) { + TestModule testModule = entry.getKey(); + List testFilesInModule = entry.getValue(); + + List jetFiles = getJetFiles(testFilesInModule); + allJetFiles.addAll(jetFiles); + + ModuleDescriptorImpl module = modules.get(testModule); + analyzeModule(trace, module == null ? support.getModule() : module, jetFiles); + } boolean ok = true; StringBuilder actualText = new StringBuilder(); for (TestFile testFile : testFiles) { - ok &= testFile.getActualText(bindingContext, actualText); + ok &= testFile.getActualText(trace.getBindingContext(), actualText); } JetTestUtils.assertEqualsToFile(testDataFile, actualText.toString()); assertTrue("Diagnostics mismatch. See the output above", ok); - checkAllResolvedCallsAreCompleted(jetFiles, bindingContext); + checkAllResolvedCallsAreCompleted(allJetFiles, trace.getBindingContext()); + } + + private Map createModules(Map> groupedByModule) { + Map modules = new HashMap(); + + for (TestModule testModule : groupedByModule.keySet()) { + if (testModule == null) continue; + ModuleDescriptorImpl module = AnalyzerFacadeForJVM.createJavaModule("<" + testModule.getName() + ">"); + modules.put(testModule, module); + } + + for (TestModule testModule : groupedByModule.keySet()) { + if (testModule == null) continue; + + ModuleDescriptorImpl module = modules.get(testModule); + for (TestModule dependency : testModule.getDependencies()) { + // Adding other modules as BINARIES here, because in teh reduced dependency ordering model they are equal to binaries + module.addFragmentProvider(DependencyKind.BINARIES, modules.get(dependency).getPackageFragmentProvider()); + } + } + return modules; + } + + private void analyzeModule(BindingTrace trace, ModuleDescriptorImpl module, List jetFiles) { + GlobalContext globalContext = ContextPackage.GlobalContext(); + TopDownAnalysisParameters topDownAnalysisParameters = TopDownAnalysisParameters.create( + globalContext.getStorageManager(), + globalContext.getExceptionTracker(), + Predicates.alwaysTrue(), + false, + false + ); + + // New JavaDescriptorResolver is created for each module, which is good because it emulates different Java libraries for each module, + // albeit with same class names + InjectorForTopDownAnalyzerForJvm + injector = new InjectorForTopDownAnalyzerForJvm(getProject(), topDownAnalysisParameters, trace, module, + MemberFilter.ALWAYS_TRUE); + try { + module.addFragmentProvider(DependencyKind.BINARIES, injector.getJavaDescriptorResolver().getPackageFragmentProvider()); + injector.getTopDownAnalyzer().analyzeFiles(topDownAnalysisParameters, jetFiles); + } + finally { + injector.destroy(); + } } private static void checkAllResolvedCallsAreCompleted(@NotNull List jetFiles, @NotNull BindingContext bindingContext) { diff --git a/compiler/tests/org/jetbrains/jet/checkers/BaseDiagnosticsTest.java b/compiler/tests/org/jetbrains/jet/checkers/BaseDiagnosticsTest.java index d972a2bdd9a..2b03c200a70 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/BaseDiagnosticsTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/BaseDiagnosticsTest.java @@ -29,6 +29,8 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; +import kotlin.Function1; +import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.ConfigurationKind; @@ -45,9 +47,7 @@ import org.junit.Assert; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -107,17 +107,54 @@ public abstract class BaseDiagnosticsTest extends JetLiteFixture { String expectedText = JetTestUtils.doLoadFile(file); + class ModuleAndDependencies { + final TestModule module; + final List dependencies; + + ModuleAndDependencies(TestModule module, List dependencies) { + this.module = module; + this.dependencies = dependencies; + } + } + final Map modules = new HashMap(); + List testFiles = - JetTestUtils.createTestFiles(file.getName(), expectedText, new JetTestUtils.TestFileFactory() { + JetTestUtils.createTestFiles(file.getName(), expectedText, new JetTestUtils.TestFileFactory() { + @Override - public TestFile create(String fileName, String text, Map directives) { + public TestFile createFile(@Nullable TestModule module, String fileName, String text, Map directives) { if (fileName.endsWith(".java")) { writeJavaFile(fileName, text, javaFilesDir); } - return new TestFile(fileName, text, directives); + + return new TestFile(module, fileName, text, directives); + } + + @Override + public TestModule createModule(String name, List dependencies) { + TestModule module = new TestModule(name); + ModuleAndDependencies oldValue = modules.put(name, new ModuleAndDependencies(module, dependencies)); + assert oldValue == null : "Module " + name + " declared more than once"; + + return module; } }); + for (final ModuleAndDependencies moduleAndDependencies : modules.values()) { + List dependencies = KotlinPackage.map( + moduleAndDependencies.dependencies, + new Function1() { + @Override + public TestModule invoke(String name) { + ModuleAndDependencies dependency = modules.get(name); + assert dependency != null : "Dependency not found: " + name + " for module " + moduleAndDependencies.module.getName(); + return dependency.module; + } + } + ); + moduleAndDependencies.module.getDependencies().addAll(dependencies); + } + analyzeAndCheck(file, testFiles); } @@ -126,7 +163,7 @@ public abstract class BaseDiagnosticsTest extends JetLiteFixture { List files ); - protected static List getJetFiles(List testFiles) { + protected static List getJetFiles(List testFiles) { List jetFiles = Lists.newArrayList(); for (TestFile testFile : testFiles) { if (testFile.getJetFile() != null) { @@ -202,19 +239,41 @@ public abstract class BaseDiagnosticsTest extends JetLiteFixture { }); } + protected static class TestModule { + private final String name; + private final List dependencies = new ArrayList(); + + public TestModule(@NotNull String name) { + this.name = name; + } + + @NotNull + public String getName() { + return name; + } + + @NotNull + public List getDependencies() { + return dependencies; + } + } + protected class TestFile { private final List diagnosedRanges = Lists.newArrayList(); private final String expectedText; + private final TestModule module; private final String clearText; private final JetFile jetFile; private final Condition whatDiagnosticsToConsider; private final boolean declareCheckType; public TestFile( + @Nullable TestModule module, String fileName, String textWithMarkers, Map directives ) { + this.module = module; this.whatDiagnosticsToConsider = parseDiagnosticFilterDirective(directives); this.declareCheckType = directives.containsKey(CHECK_TYPE_DIRECTIVE); if (fileName.endsWith(".java")) { @@ -234,6 +293,10 @@ public abstract class BaseDiagnosticsTest extends JetLiteFixture { } } + @Nullable + public TestModule getModule() { + return module; + } @Nullable public JetFile getJetFile() { diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index fe692c12988..d5243441f41 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -33,7 +33,7 @@ import org.jetbrains.jet.checkers.AbstractJetDiagnosticsTest; @InnerTestClasses({JetDiagnosticsTestGenerated.Tests.class, JetDiagnosticsTestGenerated.Script.class, JetDiagnosticsTestGenerated.TailRecursion.class}) public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { @TestMetadata("compiler/testData/diagnostics/tests") - @InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.CallableReference.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ClassObjects.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.CyclicHierarchy.class, Tests.DataClasses.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.DelegatedProperty.class, Tests.Deparenthesize.class, Tests.Enum.class, Tests.Evaluate.class, Tests.Extensions.class, Tests.FunctionLiterals.class, Tests.Generics.class, Tests.Imports.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.Inline.class, Tests.Inner.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.NamedArguments.class, Tests.NullabilityAndAutoCasts.class, Tests.NullableTypes.class, Tests.Numbers.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Recovery.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Resolve.class, Tests.Scopes.class, Tests.SenselessComparison.class, Tests.Shadowing.class, Tests.SmartCasts.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.Suppress.class, Tests.ThisAndSuper.class, Tests.Typedefs.class, Tests.Unit.class, Tests.Varargs.class, Tests.When.class}) + @InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.CallableReference.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ClassObjects.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.CyclicHierarchy.class, Tests.DataClasses.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.DelegatedProperty.class, Tests.Deparenthesize.class, Tests.Enum.class, Tests.Evaluate.class, Tests.Extensions.class, Tests.FunctionLiterals.class, Tests.Generics.class, Tests.Imports.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.Inline.class, Tests.Inner.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.Multimodule.class, Tests.NamedArguments.class, Tests.NullabilityAndAutoCasts.class, Tests.NullableTypes.class, Tests.Numbers.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Recovery.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Resolve.class, Tests.Scopes.class, Tests.SenselessComparison.class, Tests.Shadowing.class, Tests.SmartCasts.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.Suppress.class, Tests.ThisAndSuper.class, Tests.Typedefs.class, Tests.Unit.class, Tests.Varargs.class, Tests.When.class}) public static class Tests extends AbstractJetDiagnosticsTest { @TestMetadata("Abstract.kt") public void testAbstract() throws Exception { @@ -4861,6 +4861,19 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { } + @TestMetadata("compiler/testData/diagnostics/tests/multimodule") + public static class Multimodule extends AbstractJetDiagnosticsTest { + public void testAllFilesPresentInMultimodule() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/tests/multimodule"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("internal.kt") + public void testInternal() throws Exception { + doTest("compiler/testData/diagnostics/tests/multimodule/internal.kt"); + } + + } + @TestMetadata("compiler/testData/diagnostics/tests/namedArguments") public static class NamedArguments extends AbstractJetDiagnosticsTest { public void testAllFilesPresentInNamedArguments() throws Exception { @@ -7251,6 +7264,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { suite.addTestSuite(J_k.class); suite.addTest(Jdk_annotations.innerSuite()); suite.addTestSuite(Library.class); + suite.addTestSuite(Multimodule.class); suite.addTestSuite(NamedArguments.class); suite.addTestSuite(NullabilityAndAutoCasts.class); suite.addTestSuite(NullableTypes.class);