diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/AbstractJetDiagnosticsTestWithJsStdLib.java b/compiler/tests/org/jetbrains/kotlin/checkers/AbstractJetDiagnosticsTestWithJsStdLib.java index 7d8027dd19a..5da39652045 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/AbstractJetDiagnosticsTestWithJsStdLib.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/AbstractJetDiagnosticsTestWithJsStdLib.java @@ -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(); diff --git a/js/js.frontend/js.frontend.iml b/js/js.frontend/js.frontend.iml index 0d9bc35f0f2..8ead2455283 100644 --- a/js/js.frontend/js.frontend.iml +++ b/js/js.frontend/js.frontend.iml @@ -12,5 +12,7 @@ + + \ No newline at end of file diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/analyze/TopDownAnalyzerFacadeForJS.java b/js/js.frontend/src/org/jetbrains/kotlin/js/analyze/TopDownAnalyzerFacadeForJS.java index 871d506ff64..29047d4ada9 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/analyze/TopDownAnalyzerFacadeForJS.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/analyze/TopDownAnalyzerFacadeForJS.java @@ -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 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 allFiles = config.getLibraryModule() != null ? - files : - Config.withJsLibAdded(files, config); - + Collection 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); } - } diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/config/Config.java b/js/js.frontend/src/org/jetbrains/kotlin/js/config/Config.java index adab164e589..c2ea60bf37a 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/config/Config.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/config/Config.java @@ -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 libFiles = null; + @NotNull + private final List sourceFilesFromLibraries = new SmartList(); @NotNull private final EcmaVersion target; @@ -49,6 +53,14 @@ public abstract class Config { private final boolean sourcemap; + @NotNull + protected final List metadata = new SmartList(); + + @Nullable + private List 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 report); - @NotNull - protected abstract List generateLibFiles(); + protected abstract void init(@NotNull List sourceFilesInLibraries, @NotNull List metadata); @NotNull - public final List getLibFiles() { - if (libFiles == null) { - libFiles = generateLibFiles(); + public List getModuleDescriptors() { + init(); + if (moduleDescriptors != null) return moduleDescriptors; + + moduleDescriptors = new SmartList(); + for(KotlinJavascriptMetadata metadataEntry : metadata) { + moduleDescriptors.add(createModuleDescriptor(metadataEntry)); } - return libFiles; + + return moduleDescriptors; } - @Nullable - public BindingContext getLibraryContext() { - return null; + @NotNull + public List 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 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 withJsLibAdded(@NotNull Collection files, @NotNull Config config) { Collection allFiles = Lists.newArrayList(); allFiles.addAll(files); - allFiles.addAll(config.getLibFiles()); + allFiles.addAll(config.getSourceFilesFromLibraries()); return allFiles; } - - public boolean isTestConfig() { - return false; - } } diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/config/LibrarySourcesConfig.java b/js/js.frontend/src/org/jetbrains/kotlin/js/config/LibrarySourcesConfig.java index 063c8f885ee..9e15abab859 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/config/LibrarySourcesConfig.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/config/LibrarySourcesConfig.java @@ -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 generateLibFiles() { - if (files.isEmpty()) { - return Collections.emptyList(); - } + protected void init(@NotNull final List sourceFilesInLibraries, @NotNull final List metadata) { + if (files.isEmpty()) return; - final List jetFiles = new ArrayList(); final PsiManager psiManager = PsiManager.getInstance(getProject()); Function1 report = new Function1() { @@ -92,16 +88,22 @@ public class LibrarySourcesConfig extends Config { Function2 action = new Function2() { @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 jetFiles; private final String moduleName; private final PsiManager psiManager; diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/config/LibrarySourcesConfigWithCaching.java b/js/js.frontend/src/org/jetbrains/kotlin/js/config/LibrarySourcesConfigWithCaching.java index d16d0375024..999c5995be1 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/config/LibrarySourcesConfigWithCaching.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/config/LibrarySourcesConfigWithCaching.java @@ -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 JS_STDLIB = - Arrays.asList(PathUtil.getKotlinPathsForDistDirectory().getJsStdLibJarPath().getAbsolutePath()); + Collections.singletonList(PathUtil.getKotlinPathsForDistDirectory().getJsStdLibJarPath().getAbsolutePath()); - private static List jsLibFiles; - private static AnalysisResult result; - - private BindingContext libraryContext; - private ModuleDescriptor libraryModule; + private static List stdlibMetadata = null; private final boolean isUnitTestConfig; @@ -61,85 +46,19 @@ public class LibrarySourcesConfigWithCaching extends LibrarySourcesConfig { this.isUnitTestConfig = isUnitTestConfig; } - @NotNull @Override - public List generateLibFiles() { - if (jsLibFiles == null) { + protected void init(@NotNull List sourceFilesInLibraries, @NotNull List 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(); + 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 generateLibFiles() { - return Collections.emptyList(); - } - @Override - public boolean checkLibFilesAndReportErrors(@NotNull Function1 report) { - return false; - } - }; - } }