JS backend: support for reading metadata

This commit is contained in:
Michael Nedzelsky
2015-02-17 04:48:53 +03:00
parent 3bf14518e8
commit 7ebfd37c33
6 changed files with 110 additions and 166 deletions
@@ -23,22 +23,19 @@ import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles;
import org.jetbrains.kotlin.cli.jvm.compiler.JetCoreEnvironment;
import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.context.GlobalContext;
import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS;
import org.jetbrains.kotlin.js.config.EcmaVersion;
import org.jetbrains.kotlin.js.config.LibrarySourcesConfig;
import org.jetbrains.kotlin.js.config.LibrarySourcesConfigWithCaching;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace;
import java.util.List;
import java.util.Map;
public abstract class AbstractJetDiagnosticsTestWithJsStdLib extends AbstractJetDiagnosticsTest {
private LibrarySourcesConfigWithCaching config;
private LibrarySourcesConfig config;
@Override
protected void setUp() throws Exception {
@@ -65,12 +62,7 @@ public abstract class AbstractJetDiagnosticsTestWithJsStdLib extends AbstractJet
ModuleDescriptorImpl module,
BindingTrace moduleTrace
) {
BindingContext libraryContext = config.getLibraryContext();
DelegatingBindingTrace trace = new DelegatingBindingTrace(libraryContext, "trace with preanalyzed library");
TopDownAnalyzerFacadeForJS.analyzeFilesWithGivenTrace(jetFiles, moduleTrace, module, config);
trace.addAllMyDataTo(moduleTrace);
}
@Override
@@ -93,9 +85,9 @@ public abstract class AbstractJetDiagnosticsTestWithJsStdLib extends AbstractJet
module.addDependencyOnModule(module);
module.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule());
ModuleDescriptor libraryModule = config.getLibraryModule();
assert libraryModule instanceof ModuleDescriptorImpl;
module.addDependencyOnModule((ModuleDescriptorImpl) libraryModule);
for(ModuleDescriptorImpl moduleDescriptor : config.getModuleDescriptors()) {
module.addDependencyOnModule(moduleDescriptor);
}
module.seal();
+2
View File
@@ -12,5 +12,7 @@
<orderEntry type="module" module-name="js.dart-ast" exported="" />
<orderEntry type="module" module-name="js.parser" exported="" />
<orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="serialization" />
<orderEntry type="module" module-name="serialization.js" />
</component>
</module>
@@ -19,11 +19,9 @@ package org.jetbrains.kotlin.js.analyze;
import com.google.common.collect.ImmutableList;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.analyzer.AnalysisResult;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.context.ContextPackage;
import org.jetbrains.kotlin.context.GlobalContextImpl;
import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider;
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
import org.jetbrains.kotlin.di.InjectorForTopDownAnalyzerForJs;
@@ -55,18 +53,16 @@ public final class TopDownAnalyzerFacadeForJS {
@NotNull Collection<JetFile> files,
@NotNull Config config
) {
BindingContext libraryContext = config.getLibraryContext();
BindingTrace trace = libraryContext == null
? new BindingTraceContext()
: new DelegatingBindingTrace(libraryContext, "trace with preanalyzed library");
BindingTrace trace = new BindingTraceContext();
ModuleDescriptorImpl module = createJsModule("<" + config.getModuleId() + ">");
module.addDependencyOnModule(module);
module.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule());
ModuleDescriptor libraryModule = config.getLibraryModule();
if (libraryModule != null) {
module.addDependencyOnModule((ModuleDescriptorImpl) libraryModule); // "import" analyzed library module
for(ModuleDescriptorImpl moduleDescriptor : config.getModuleDescriptors()) {
module.addDependencyOnModule(moduleDescriptor);
}
module.seal();
return analyzeFilesWithGivenTrace(files, trace, module, config);
@@ -85,10 +81,8 @@ public final class TopDownAnalyzerFacadeForJS {
TopDownAnalysisParameters topDownAnalysisParameters = TopDownAnalysisParameters.create(
globalContext.getStorageManager(), globalContext.getExceptionTracker(), false, false);
Collection<JetFile> allFiles = config.getLibraryModule() != null ?
files :
Config.withJsLibAdded(files, config);
Collection<JetFile> allFiles = Config.withJsLibAdded(files, config);
InjectorForTopDownAnalyzerForJs injector = new InjectorForTopDownAnalyzerForJs(
project, topDownAnalysisParameters, trace, module,
new FileBasedDeclarationProviderFactory(topDownAnalysisParameters.getStorageManager(), allFiles));
@@ -113,5 +107,4 @@ public final class TopDownAnalyzerFacadeForJS {
public static ModuleDescriptorImpl createJsModule(@NotNull String name) {
return new ModuleDescriptorImpl(Name.special(name), DEFAULT_IMPORTS, PlatformToKotlinClassMap.EMPTY);
}
}
@@ -18,15 +18,19 @@ package org.jetbrains.kotlin.js.config;
import com.google.common.collect.Lists;
import com.intellij.openapi.project.Project;
import com.intellij.util.SmartList;
import kotlin.Function1;
import kotlin.Unit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider;
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider;
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.BindingTraceContext;
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil;
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadata;
import java.util.Collection;
import java.util.List;
@@ -39,8 +43,8 @@ public abstract class Config {
@NotNull
private final Project project;
@Nullable
private List<JetFile> libFiles = null;
@NotNull
private final List<JetFile> sourceFilesFromLibraries = new SmartList<JetFile>();
@NotNull
private final EcmaVersion target;
@@ -49,6 +53,14 @@ public abstract class Config {
private final boolean sourcemap;
@NotNull
protected final List<KotlinJavascriptMetadata> metadata = new SmartList<KotlinJavascriptMetadata>();
@Nullable
private List<ModuleDescriptorImpl> moduleDescriptors = null;
private boolean initialized = false;
public Config(
@NotNull Project project,
@NotNull String moduleId,
@@ -88,36 +100,59 @@ public abstract class Config {
public abstract boolean checkLibFilesAndReportErrors(@NotNull Function1<String, Unit> report);
@NotNull
protected abstract List<JetFile> generateLibFiles();
protected abstract void init(@NotNull List<JetFile> sourceFilesInLibraries, @NotNull List<KotlinJavascriptMetadata> metadata);
@NotNull
public final List<JetFile> getLibFiles() {
if (libFiles == null) {
libFiles = generateLibFiles();
public List<ModuleDescriptorImpl> getModuleDescriptors() {
init();
if (moduleDescriptors != null) return moduleDescriptors;
moduleDescriptors = new SmartList<ModuleDescriptorImpl>();
for(KotlinJavascriptMetadata metadataEntry : metadata) {
moduleDescriptors.add(createModuleDescriptor(metadataEntry));
}
return libFiles;
return moduleDescriptors;
}
@Nullable
public BindingContext getLibraryContext() {
return null;
@NotNull
public List<JetFile> getSourceFilesFromLibraries() {
init();
return sourceFilesFromLibraries;
}
@Nullable
public ModuleDescriptor getLibraryModule() {
return null;
public boolean isTestConfig() {
return false;
}
private void init() {
if (initialized) return;
init(sourceFilesFromLibraries, metadata);
initialized = true;
}
private static ModuleDescriptorImpl createModuleDescriptor(KotlinJavascriptMetadata metadata) {
ModuleDescriptorImpl moduleDescriptor = TopDownAnalyzerFacadeForJS.createJsModule("<" + metadata.getModuleName() + ">");
List<PackageFragmentProvider> providers = KotlinJavascriptSerializationUtil
.getPackageFragmentProviders(moduleDescriptor, metadata.getBody());
CompositePackageFragmentProvider compositePackageFragmentProvider = new CompositePackageFragmentProvider(providers);
moduleDescriptor.initialize(compositePackageFragmentProvider);
moduleDescriptor.addDependencyOnModule(moduleDescriptor);
moduleDescriptor.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule());
moduleDescriptor.seal();
return moduleDescriptor;
}
@NotNull
public static Collection<JetFile> withJsLibAdded(@NotNull Collection<JetFile> files, @NotNull Config config) {
Collection<JetFile> allFiles = Lists.newArrayList();
allFiles.addAll(files);
allFiles.addAll(config.getLibFiles());
allFiles.addAll(config.getSourceFilesFromLibraries());
return allFiles;
}
public boolean isTestConfig() {
return false;
}
}
@@ -22,24 +22,24 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.PathUtil;
import com.intellij.util.io.URLUtil;
import kotlin.Function1;
import kotlin.Function2;
import kotlin.Unit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.js.JavaScript;
import org.jetbrains.kotlin.idea.JetFileType;
import org.jetbrains.kotlin.js.JavaScript;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadata;
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils;
import org.jetbrains.kotlin.utils.LibraryUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.kotlin.utils.LibraryUtils.isKotlinJavascriptLibrary;
import static org.jetbrains.kotlin.utils.LibraryUtils.isKotlinJavascriptStdLibrary;
import static org.jetbrains.kotlin.utils.LibraryUtils.*;
public class LibrarySourcesConfig extends Config {
@NotNull
@@ -72,14 +72,10 @@ public class LibrarySourcesConfig extends Config {
return files;
}
@NotNull
@Override
protected List<JetFile> generateLibFiles() {
if (files.isEmpty()) {
return Collections.emptyList();
}
protected void init(@NotNull final List<JetFile> sourceFilesInLibraries, @NotNull final List<KotlinJavascriptMetadata> metadata) {
if (files.isEmpty()) return;
final List<JetFile> jetFiles = new ArrayList<JetFile>();
final PsiManager psiManager = PsiManager.getInstance(getProject());
Function1<String, Unit> report = new Function1<String, Unit>() {
@@ -92,16 +88,22 @@ public class LibrarySourcesConfig extends Config {
Function2<String, VirtualFile, Unit> action = new Function2<String, VirtualFile, Unit>() {
@Override
public Unit invoke(String moduleName, VirtualFile file) {
JetFileCollector jetFileCollector = new JetFileCollector(jetFiles, moduleName, psiManager);
VfsUtilCore.visitChildrenRecursively(file, jetFileCollector);
if (moduleName != null) {
JetFileCollector jetFileCollector = new JetFileCollector(sourceFilesInLibraries, moduleName, psiManager);
VfsUtilCore.visitChildrenRecursively(file, jetFileCollector);
}
else {
String libraryPath = PathUtil.getLocalPath(file);
assert libraryPath != null : "libraryPath for " + file + " should not be null";
metadata.addAll(KotlinJavascriptMetadataUtils.loadMetadata(libraryPath));
}
return Unit.INSTANCE$;
}
};
boolean hasErrors = checkLibFilesAndReportErrors(report, action);
assert !hasErrors : "hasErrors should be false";
return jetFiles;
}
@Override
@@ -121,7 +123,6 @@ public class LibrarySourcesConfig extends Config {
for (String path : files) {
VirtualFile file;
String actualModuleName = moduleName;
if (path.charAt(0) == '@') {
moduleName = path.substring(1);
continue;
@@ -145,20 +146,22 @@ public class LibrarySourcesConfig extends Config {
return true;
}
else {
if (isKotlinJavascriptStdLibrary(filePath)) {
actualModuleName = STDLIB_JS_MODULE_NAME;
String actualModuleName;
if (moduleName != null) {
actualModuleName = moduleName;
}
else if (isKotlinJavascriptLibrary(filePath)) {
else if (isOldKotlinJavascriptLibrary(filePath)) {
actualModuleName = LibraryUtils.getKotlinJsModuleName(filePath);
}
else if (actualModuleName == null) {
else if (isKotlinJavascriptLibraryWithMetadata(filePath)) {
actualModuleName = null;
}
else {
report.invoke("'" + path + "' is not a valid Kotlin Javascript library");
return true;
}
if (actualModuleName == null) {
report.invoke("Could not find " + LibraryUtils.KOTLIN_JS_MODULE_NAME + " for '" + path + "'");
return true;
}
if (action != null) {
action.invoke(actualModuleName, file);
}
@@ -169,7 +172,7 @@ public class LibrarySourcesConfig extends Config {
return false;
}
protected JetFile getJetFileByVirtualFile(VirtualFile file, String moduleName, PsiManager psiManager) {
protected static JetFile getJetFileByVirtualFile(VirtualFile file, String moduleName, PsiManager psiManager) {
PsiFile psiFile = psiManager.findFile(file);
assert psiFile != null;
@@ -181,7 +184,7 @@ public class LibrarySourcesConfig extends Config {
psiFile.putUserData(EXTERNAL_MODULE_NAME, moduleName);
}
private class JetFileCollector extends VirtualFileVisitor {
private static class JetFileCollector extends VirtualFileVisitor {
private final List<JetFile> jetFiles;
private final String moduleName;
private final PsiManager psiManager;
@@ -17,35 +17,20 @@
package org.jetbrains.kotlin.js.config;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiManager;
import kotlin.Function1;
import kotlin.Unit;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.analyzer.AnalysisResult;
import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.psi.JetPsiFactory;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadata;
import org.jetbrains.kotlin.utils.PathUtil;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class LibrarySourcesConfigWithCaching extends LibrarySourcesConfig {
public static final List<String> JS_STDLIB =
Arrays.asList(PathUtil.getKotlinPathsForDistDirectory().getJsStdLibJarPath().getAbsolutePath());
Collections.singletonList(PathUtil.getKotlinPathsForDistDirectory().getJsStdLibJarPath().getAbsolutePath());
private static List<JetFile> jsLibFiles;
private static AnalysisResult result;
private BindingContext libraryContext;
private ModuleDescriptor libraryModule;
private static List<KotlinJavascriptMetadata> stdlibMetadata = null;
private final boolean isUnitTestConfig;
@@ -61,85 +46,19 @@ public class LibrarySourcesConfigWithCaching extends LibrarySourcesConfig {
this.isUnitTestConfig = isUnitTestConfig;
}
@NotNull
@Override
public List<JetFile> generateLibFiles() {
if (jsLibFiles == null) {
protected void init(@NotNull List<JetFile> sourceFilesInLibraries, @NotNull List<KotlinJavascriptMetadata> metadata) {
if (stdlibMetadata == null) {
//noinspection AssignmentToStaticFieldFromInstanceMethod
jsLibFiles = super.generateLibFiles();
}
return jsLibFiles;
}
@Nullable
@Override
public ModuleDescriptor getLibraryModule() {
if (libraryModule == null) {
libraryModule = getResult().getModuleDescriptor();
stdlibMetadata = new SmartList<KotlinJavascriptMetadata>();
super.init(sourceFilesInLibraries, stdlibMetadata);
}
return libraryModule;
}
@Nullable
@Override
public BindingContext getLibraryContext() {
if (libraryContext == null) {
//TODO check errors?
// TopDownAnalyzerFacadeForJS.checkForErrors(allLibFiles, result.getBindingContext());
libraryContext = getResult().getBindingContext();
}
return libraryContext;
metadata.addAll(stdlibMetadata);
}
@Override
public boolean isTestConfig() {
return isUnitTestConfig;
}
@Override
protected JetFile getJetFileByVirtualFile(VirtualFile file, String moduleName, PsiManager psiManager) {
JetFile jetFile;
try {
String text = StringUtil.convertLineSeparators(new String(file.contentsToByteArray(false), file.getCharset()));
jetFile = new JetPsiFactory(getProject()).createPhysicalFile(file.getName(), text);
}
catch (IOException e) {
JetFile jetFileByVirtualFile = super.getJetFileByVirtualFile(file, moduleName, psiManager);
jetFile = new JetPsiFactory(getProject()).createPhysicalFile(file.getPath(), jetFileByVirtualFile.getText());
}
setupPsiFile(jetFile, moduleName);
return jetFile;
}
private AnalysisResult getResult() {
if (result == null) {
//noinspection AssignmentToStaticFieldFromInstanceMethod
result = TopDownAnalyzerFacadeForJS.analyzeFiles(
generateLibFiles(),
createConfigWithoutLibFiles(getProject(), getModuleId(), getTarget())
);
}
return result;
}
@NotNull
private static Config createConfigWithoutLibFiles(@NotNull Project project, @NotNull String moduleId, @NotNull EcmaVersion ecmaVersion) {
return new Config(project, moduleId, ecmaVersion, /* generate sourcemaps = */ false, /* inlineEnabled = */ false) {
@NotNull
@Override
protected List<JetFile> generateLibFiles() {
return Collections.emptyList();
}
@Override
public boolean checkLibFilesAndReportErrors(@NotNull Function1<String, Unit> report) {
return false;
}
};
}
}