Support JS-targeted diagnostic tests

This commit is contained in:
Andrey Breslav
2014-11-25 18:33:56 +03:00
parent 722624f0a4
commit 2a334fc8f5
7 changed files with 125 additions and 49 deletions
+2 -2
View File
@@ -19,6 +19,6 @@
<orderEntry type="module" module-name="serialization.java" /> <orderEntry type="module" module-name="serialization.java" />
<orderEntry type="module" module-name="util" /> <orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="builtins-serializer" /> <orderEntry type="module" module-name="builtins-serializer" />
<orderEntry type="module" module-name="js.frontend" scope="TEST" />
</component> </component>
</module> </module>
@@ -112,7 +112,7 @@ public class JetTestUtils {
* *
* Several files may follow one module * Several files may follow one module
*/ */
public static final Pattern FILE_OR_MODULE_PATTERN = Pattern.compile("(?://\\s*MODULE:\\s*(\\w+)(\\(\\w+(?:, \\w+)*\\))?\\s*)?" + public static final Pattern FILE_OR_MODULE_PATTERN = Pattern.compile("(?://\\s*MODULE(?:\\[(\\w+)\\])?:\\s*(\\w+)(\\(\\w+(?:, \\w+)*\\))?\\s*)?" +
"//\\s*FILE:\\s*(.*)$", Pattern.MULTILINE); "//\\s*FILE:\\s*(.*)$", Pattern.MULTILINE);
public static final Pattern DIRECTIVE_PATTERN = Pattern.compile("^//\\s*!(\\w+)(:\\s*(.*)$)?", Pattern.MULTILINE); public static final Pattern DIRECTIVE_PATTERN = Pattern.compile("^//\\s*!(\\w+)(:\\s*(.*)$)?", Pattern.MULTILINE);
@@ -502,7 +502,7 @@ public class JetTestUtils {
public interface TestFileFactory<M, F> { public interface TestFileFactory<M, F> {
F createFile(@Nullable M module, @NotNull String fileName, @NotNull String text, @NotNull Map<String, String> directives); F createFile(@Nullable M module, @NotNull String fileName, @NotNull String text, @NotNull Map<String, String> directives);
M createModule(@NotNull String name, @NotNull List<String> dependencies); M createModule(@NotNull String name, @Nullable String platform, @NotNull List<String> dependencies);
} }
public static abstract class TestFileFactoryNoModules<F> implements TestFileFactory<Void, F> { public static abstract class TestFileFactoryNoModules<F> implements TestFileFactory<Void, F> {
@@ -520,7 +520,7 @@ public class JetTestUtils {
public abstract F create(@NotNull String fileName, @NotNull String text, @NotNull Map<String, String> directives); public abstract F create(@NotNull String fileName, @NotNull String text, @NotNull Map<String, String> directives);
@Override @Override
public Void createModule(@NotNull String name, @NotNull List<String> dependencies) { public Void createModule(@NotNull String name, @Nullable String platform, @NotNull List<String> dependencies) {
return null; return null;
} }
} }
@@ -540,13 +540,14 @@ public class JetTestUtils {
M module = null; M module = null;
// Many files // Many files
while (true) { while (true) {
String moduleName = matcher.group(1); String platform = matcher.group(1);
String moduleDependencies = matcher.group(2); String moduleName = matcher.group(2);
String moduleDependencies = matcher.group(3);
if (moduleName != null) { if (moduleName != null) {
module = factory.createModule(moduleName, parseDependencies(moduleDependencies)); module = factory.createModule(moduleName, platform, parseDependencies(moduleDependencies));
} }
String fileName = matcher.group(3); String fileName = matcher.group(4);
int start = processedChars; int start = processedChars;
boolean nextFileExists = matcher.find(); boolean nextFileExists = matcher.find();
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiClass;
import com.intellij.psi.impl.compiled.ClsElementImpl; import com.intellij.psi.impl.compiled.ClsElementImpl;
import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.checkers.KotlinMultiFileTestWithWithJava; import org.jetbrains.jet.checkers.KotlinMultiFileTestWithWithJava;
import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
@@ -76,7 +77,7 @@ public abstract class AbstractKotlinLightClassTest extends KotlinMultiFileTestWi
} }
@Override @Override
protected Void createTestModule(String name) { protected Void createTestModule(@NotNull String name, @Nullable String platform) {
return null; return null;
} }
@@ -54,6 +54,9 @@ import org.jetbrains.jet.storage.LockBasedStorageManager;
import org.jetbrains.jet.test.util.DescriptorValidator; import org.jetbrains.jet.test.util.DescriptorValidator;
import org.jetbrains.jet.test.util.RecursiveDescriptorComparator; import org.jetbrains.jet.test.util.RecursiveDescriptorComparator;
import org.jetbrains.jet.utils.UtilsPackage; import org.jetbrains.jet.utils.UtilsPackage;
import org.jetbrains.k2js.analyze.TopDownAnalyzerFacadeForJS;
import org.jetbrains.k2js.config.Config;
import org.jetbrains.k2js.config.EcmaVersion;
import java.io.File; import java.io.File;
import java.util.*; import java.util.*;
@@ -114,8 +117,6 @@ public abstract class AbstractJetDiagnosticsTest extends BaseDiagnosticsTest {
module.seal(); module.seal();
} }
// New JavaDescriptorResolver is created for each module, which is good because it emulates different Java libraries for each module,
// albeit with same class names
ExceptionTracker tracker = new ExceptionTracker(); ExceptionTracker tracker = new ExceptionTracker();
GlobalContext context = new SimpleGlobalContext( GlobalContext context = new SimpleGlobalContext(
new LoggingStorageManager( new LoggingStorageManager(
@@ -124,17 +125,7 @@ public abstract class AbstractJetDiagnosticsTest extends BaseDiagnosticsTest {
), ),
tracker tracker
); );
analyzeModuleContents(context, jetFiles, module, moduleTrace, testModule);
TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext(
getProject(),
context,
jetFiles,
moduleTrace,
Predicates.<PsiFile>alwaysTrue(),
module,
null,
null
);
checkAllResolvedCallsAreCompleted(jetFiles, moduleTrace.getBindingContext()); checkAllResolvedCallsAreCompleted(jetFiles, moduleTrace.getBindingContext());
} }
@@ -209,6 +200,49 @@ public abstract class AbstractJetDiagnosticsTest extends BaseDiagnosticsTest {
return new File(FileUtil.getNameWithoutExtension(testDataFile.getAbsolutePath()) + ".lazy.log"); return new File(FileUtil.getNameWithoutExtension(testDataFile.getAbsolutePath()) + ".lazy.log");
} }
protected void analyzeModuleContents(
GlobalContext context,
List<JetFile> jetFiles,
ModuleDescriptorImpl module,
BindingTrace moduleTrace,
TestModule testModule
) {
String platform = getPlatform(testModule);
if ("jvm".equals(platform)) {
// New JavaDescriptorResolver is created for each module, which is good because it emulates different Java libraries for each module,
// albeit with same class names
TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext(
getProject(),
context,
jetFiles,
moduleTrace,
Predicates.<PsiFile>alwaysTrue(),
module,
null,
null
);
}
else if ("js".equals(platform)) {
TopDownAnalyzerFacadeForJS.analyzeFilesWithGivenTrace(
jetFiles,
moduleTrace,
module,
Predicates.<PsiFile>alwaysTrue(),
new Config(getProject(), "module", EcmaVersion.v5, false, true) {
@NotNull
@Override
protected List<JetFile> generateLibFiles() {
return Collections.emptyList();
}
}
);
}
else {
throw new IllegalStateException("Unknown platform in module " + testModule.getName() + ": " + platform);
}
}
private void validateAndCompareDescriptorWithFile( private void validateAndCompareDescriptorWithFile(
File expectedFile, File expectedFile,
List<TestFile> testFiles, List<TestFile> testFiles,
@@ -281,12 +315,12 @@ public abstract class AbstractJetDiagnosticsTest extends BaseDiagnosticsTest {
return RECURSIVE.filterRecursion(stepIntoFilter).withValidationStrategy(DescriptorValidator.ValidationVisitor.errorTypesAllowed()); return RECURSIVE.filterRecursion(stepIntoFilter).withValidationStrategy(DescriptorValidator.ValidationVisitor.errorTypesAllowed());
} }
public static Map<TestModule, ModuleDescriptorImpl> createModules(Map<TestModule, List<TestFile>> groupedByModule) { private Map<TestModule, ModuleDescriptorImpl> createModules(Map<TestModule, List<TestFile>> groupedByModule) {
Map<TestModule, ModuleDescriptorImpl> modules = new HashMap<TestModule, ModuleDescriptorImpl>(); Map<TestModule, ModuleDescriptorImpl> modules = new HashMap<TestModule, ModuleDescriptorImpl>();
for (TestModule testModule : groupedByModule.keySet()) { for (TestModule testModule : groupedByModule.keySet()) {
if (testModule == null) continue; if (testModule == null) continue;
ModuleDescriptorImpl module = TopDownAnalyzerFacadeForJVM.createJavaModule("<" + testModule.getName() + ">"); ModuleDescriptorImpl module = createModule(testModule);
modules.put(testModule, module); modules.put(testModule, module);
} }
@@ -302,6 +336,28 @@ public abstract class AbstractJetDiagnosticsTest extends BaseDiagnosticsTest {
return modules; return modules;
} }
protected ModuleDescriptorImpl createModule(TestModule testModule) {
String name = "<" + testModule.getName() + ">";
String platform = getPlatform(testModule);
if ("jvm".equals(platform)) {
return TopDownAnalyzerFacadeForJVM.createJavaModule(name);
}
else if ("js".equals(platform)) {
return TopDownAnalyzerFacadeForJS.createJsModule(name);
}
throw new IllegalStateException("Unknown platform in module " + testModule.getName() + ": " + platform);
}
@NotNull
private static String getPlatform(@Nullable TestModule testModule) {
if (testModule == null) return "jvm";
String platform = testModule.getPlatform();
if (platform == null) return "jvm";
return platform;
}
private static void checkAllResolvedCallsAreCompleted(@NotNull List<JetFile> jetFiles, @NotNull BindingContext bindingContext) { private static void checkAllResolvedCallsAreCompleted(@NotNull List<JetFile> jetFiles, @NotNull BindingContext bindingContext) {
for (JetFile file : jetFiles) { for (JetFile file : jetFiles) {
if (!AnalyzingUtils.getSyntaxErrorRanges(file).isEmpty()) { if (!AnalyzingUtils.getSyntaxErrorRanges(file).isEmpty()) {
@@ -79,8 +79,8 @@ public abstract class BaseDiagnosticsTest extends
public static final boolean CHECK_LAZY_LOG_DEFAULT = "true".equals(System.getProperty("check.lazy.logs", "false")); public static final boolean CHECK_LAZY_LOG_DEFAULT = "true".equals(System.getProperty("check.lazy.logs", "false"));
@Override @Override
protected TestModule createTestModule(String name) { protected TestModule createTestModule(@NotNull String name, @Nullable String platform) {
return new TestModule(name); return new TestModule(name, platform);
} }
@Override @Override
@@ -208,10 +208,12 @@ public abstract class BaseDiagnosticsTest extends
protected static class TestModule implements Comparable<TestModule> { protected static class TestModule implements Comparable<TestModule> {
private final String name; private final String name;
private final String platform;
private final List<TestModule> dependencies = new ArrayList<TestModule>(); private final List<TestModule> dependencies = new ArrayList<TestModule>();
public TestModule(@NotNull String name) { public TestModule(@NotNull String name, @Nullable String platform) {
this.name = name; this.name = name;
this.platform = platform;
} }
@NotNull @NotNull
@@ -219,6 +221,11 @@ public abstract class BaseDiagnosticsTest extends
return name; return name;
} }
@Nullable
public String getPlatform() {
return platform;
}
@NotNull @NotNull
public List<TestModule> getDependencies() { public List<TestModule> getDependencies() {
return dependencies; return dependencies;
@@ -126,8 +126,8 @@ public abstract class KotlinMultiFileTestWithWithJava<M, F> extends JetLiteFixtu
} }
@Override @Override
public M createModule(@NotNull String name, @NotNull List<String> dependencies) { public M createModule(@NotNull String name, @Nullable String platform, @NotNull List<String> dependencies) {
M module = createTestModule(name); M module = createTestModule(name, platform);
ModuleAndDependencies oldValue = modules.put(name, new ModuleAndDependencies(module, dependencies)); ModuleAndDependencies oldValue = modules.put(name, new ModuleAndDependencies(module, dependencies));
assert oldValue == null : "Module " + name + " declared more than once"; assert oldValue == null : "Module " + name + " declared more than once";
@@ -138,7 +138,7 @@ public abstract class KotlinMultiFileTestWithWithJava<M, F> extends JetLiteFixtu
doMultiFileTest(file, modules, testFiles); doMultiFileTest(file, modules, testFiles);
} }
protected abstract M createTestModule(String name); protected abstract M createTestModule(@NotNull String name, @Nullable String platform);
protected abstract F createTestFile(M module, String fileName, String text, Map<String, String> directives); protected abstract F createTestFile(M module, String fileName, String text, Map<String, String> directives);
@@ -63,9 +63,32 @@ public final class TopDownAnalyzerFacadeForJS {
@NotNull Predicate<PsiFile> filesToAnalyzeCompletely, @NotNull Predicate<PsiFile> filesToAnalyzeCompletely,
@NotNull Config config @NotNull Config config
) { ) {
Project project = config.getProject(); BindingContext libraryContext = config.getLibraryContext();
BindingTrace trace = libraryContext == null
? new BindingTraceContext()
: new DelegatingBindingTrace(libraryContext, "trace with preanalyzed library");
ModuleDescriptorImpl owner = createJsModule("<module>"); ModuleDescriptorImpl module = createJsModule("<module>");
module.addDependencyOnModule(module);
module.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule());
ModuleDescriptor libraryModule = config.getLibraryModule();
if (libraryModule != null) {
module.addDependencyOnModule((ModuleDescriptorImpl) libraryModule); // "import" analyzed library module
}
module.seal();
return analyzeFilesWithGivenTrace(files, trace, module, filesToAnalyzeCompletely, config);
}
@NotNull
public static AnalysisResult analyzeFilesWithGivenTrace(
@NotNull Collection<JetFile> files,
@NotNull BindingTrace trace,
@NotNull ModuleDescriptorImpl module,
@NotNull Predicate<PsiFile> filesToAnalyzeCompletely,
@NotNull Config config
) {
Project project = config.getProject();
Predicate<PsiFile> completely = Predicates.and(notLibFiles(config.getLibFiles()), filesToAnalyzeCompletely); Predicate<PsiFile> completely = Predicates.and(notLibFiles(config.getLibFiles()), filesToAnalyzeCompletely);
@@ -73,25 +96,13 @@ public final class TopDownAnalyzerFacadeForJS {
TopDownAnalysisParameters topDownAnalysisParameters = TopDownAnalysisParameters.create( TopDownAnalysisParameters topDownAnalysisParameters = TopDownAnalysisParameters.create(
globalContext.getStorageManager(), globalContext.getExceptionTracker(), completely, false, false); globalContext.getStorageManager(), globalContext.getExceptionTracker(), completely, false, false);
owner.addDependencyOnModule(owner); InjectorForTopDownAnalyzerForJs injector = new InjectorForTopDownAnalyzerForJs(project, topDownAnalysisParameters, trace, module);
owner.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule());
ModuleDescriptor libraryModule = config.getLibraryModule();
if (libraryModule != null) {
owner.addDependencyOnModule((ModuleDescriptorImpl) libraryModule); // "import" analyzed library module
}
owner.seal();
BindingContext libraryContext = config.getLibraryContext();
BindingTrace trace = libraryContext == null
? new BindingTraceContext()
: new DelegatingBindingTrace(libraryContext, "trace with preanalyzed library");
InjectorForTopDownAnalyzerForJs injector = new InjectorForTopDownAnalyzerForJs(project, topDownAnalysisParameters, trace, owner);
try { try {
Collection<JetFile> allFiles = libraryModule != null ? Collection<JetFile> allFiles = config.getLibraryModule() != null ?
files : files :
Config.withJsLibAdded(files, config); Config.withJsLibAdded(files, config);
injector.getTopDownAnalyzer().analyzeFiles(topDownAnalysisParameters, allFiles); injector.getTopDownAnalyzer().analyzeFiles(topDownAnalysisParameters, allFiles);
return AnalysisResult.success(trace.getBindingContext(), owner); return AnalysisResult.success(trace.getBindingContext(), module);
} }
finally { finally {
injector.destroy(); injector.destroy();
@@ -118,7 +129,7 @@ public final class TopDownAnalyzerFacadeForJS {
} }
@NotNull @NotNull
private static ModuleDescriptorImpl createJsModule(@NotNull String name) { public static ModuleDescriptorImpl createJsModule(@NotNull String name) {
return new ModuleDescriptorImpl(Name.special(name), DEFAULT_IMPORTS, PlatformToKotlinClassMap.EMPTY); return new ModuleDescriptorImpl(Name.special(name), DEFAULT_IMPORTS, PlatformToKotlinClassMap.EMPTY);
} }