001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.resolve.jvm;
018    
019    import com.intellij.openapi.project.Project;
020    import com.intellij.psi.search.GlobalSearchScope;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.kotlin.analyzer.AnalysisResult;
024    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
025    import org.jetbrains.kotlin.context.ModuleContext;
026    import org.jetbrains.kotlin.context.MutableModuleContext;
027    import org.jetbrains.kotlin.descriptors.ClassDescriptor;
028    import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
029    import org.jetbrains.kotlin.descriptors.ModuleParameters;
030    import org.jetbrains.kotlin.descriptors.PackageFragmentProvider;
031    import org.jetbrains.kotlin.di.InjectorForTopDownAnalyzerForJvm;
032    import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider;
033    import org.jetbrains.kotlin.load.kotlin.incremental.cache.IncrementalCache;
034    import org.jetbrains.kotlin.load.kotlin.incremental.cache.IncrementalCacheProvider;
035    import org.jetbrains.kotlin.name.FqName;
036    import org.jetbrains.kotlin.name.Name;
037    import org.jetbrains.kotlin.platform.JavaToKotlinClassMap;
038    import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap;
039    import org.jetbrains.kotlin.psi.JetFile;
040    import org.jetbrains.kotlin.resolve.*;
041    import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension;
042    import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory;
043    
044    import java.util.ArrayList;
045    import java.util.Collection;
046    import java.util.List;
047    
048    import static org.jetbrains.kotlin.context.ContextPackage.ContextForNewModule;
049    
050    public enum TopDownAnalyzerFacadeForJVM {
051    
052        INSTANCE;
053    
054        public static final List<ImportPath> DEFAULT_IMPORTS = buildDefaultImports();
055    
056        private static List<ImportPath> buildDefaultImports() {
057            List<ImportPath> list = new ArrayList<ImportPath>();
058            list.add(new ImportPath("java.lang.*"));
059            list.add(new ImportPath("kotlin.*"));
060            list.add(new ImportPath("kotlin.jvm.*"));
061            list.add(new ImportPath("kotlin.io.*"));
062            // all classes from package "kotlin" mapped to java classes are imported explicitly so that they take priority over classes from java.lang
063            for (ClassDescriptor descriptor : JavaToKotlinClassMap.INSTANCE.allKotlinClasses()) {
064                FqName fqName = DescriptorUtils.getFqNameSafe(descriptor);
065                if (fqName.parent().equals(new FqName("kotlin"))) {
066                    list.add(new ImportPath(fqName, false));
067                }
068            }
069            return list;
070        }
071    
072        public static ModuleParameters JVM_MODULE_PARAMETERS = new ModuleParameters() {
073            @NotNull
074            @Override
075            public List<ImportPath> getDefaultImports() {
076                return DEFAULT_IMPORTS;
077            }
078    
079            @NotNull
080            @Override
081            public PlatformToKotlinClassMap getPlatformToKotlinClassMap() {
082                return JavaToKotlinClassMap.INSTANCE;
083            }
084        };
085    
086        @NotNull
087        public static AnalysisResult analyzeFilesWithJavaIntegrationNoIncremental(
088                @NotNull ModuleContext moduleContext,
089                @NotNull Collection<JetFile> files,
090                @NotNull BindingTrace trace,
091                @NotNull TopDownAnalysisMode topDownAnalysisMode
092        ) {
093            return analyzeFilesWithJavaIntegration(moduleContext, files, trace, topDownAnalysisMode, null, null);
094        }
095    
096        @NotNull
097        public static AnalysisResult analyzeFilesWithJavaIntegrationWithCustomContext(
098                @NotNull ModuleContext moduleContext,
099                @NotNull Collection<JetFile> files,
100                @NotNull BindingTrace trace,
101                @Nullable List<String> moduleIds,
102                @Nullable IncrementalCacheProvider incrementalCacheProvider
103        ) {
104            return analyzeFilesWithJavaIntegration(
105                    moduleContext, files, trace, TopDownAnalysisMode.TopLevelDeclarations, moduleIds, incrementalCacheProvider
106            );
107        }
108    
109        @NotNull
110        private static AnalysisResult analyzeFilesWithJavaIntegration(
111                @NotNull ModuleContext moduleContext,
112                @NotNull Collection<JetFile> files,
113                @NotNull BindingTrace trace,
114                @NotNull TopDownAnalysisMode topDownAnalysisMode,
115                @Nullable List<String> moduleIds,
116                @Nullable IncrementalCacheProvider incrementalCacheProvider
117        ) {
118            Project project = moduleContext.getProject();
119            List<JetFile> allFiles = JvmAnalyzerFacade.getAllFilesToAnalyze(project, null, files);
120    
121            FileBasedDeclarationProviderFactory providerFactory =
122                    new FileBasedDeclarationProviderFactory(moduleContext.getStorageManager(), allFiles);
123    
124            InjectorForTopDownAnalyzerForJvm injector = new InjectorForTopDownAnalyzerForJvm(
125                    moduleContext,
126                    trace,
127                    providerFactory,
128                    GlobalSearchScope.allScope(project)
129            );
130    
131            try {
132                List<PackageFragmentProvider> additionalProviders = new ArrayList<PackageFragmentProvider>();
133    
134                if (moduleIds != null && incrementalCacheProvider != null) {
135                    for (String moduleId : moduleIds) {
136                        IncrementalCache incrementalCache = incrementalCacheProvider.getIncrementalCache(moduleId);
137    
138                        additionalProviders.add(
139                                new IncrementalPackageFragmentProvider(
140                                        files, moduleContext.getModule(), moduleContext.getStorageManager(),
141                                        injector.getDeserializationComponentsForJava().getComponents(),
142                                        incrementalCache, moduleId
143                                )
144                        );
145                    }
146                }
147                additionalProviders.add(injector.getJavaDescriptorResolver().getPackageFragmentProvider());
148    
149                injector.getLazyTopDownAnalyzerForTopLevel().analyzeFiles(topDownAnalysisMode, allFiles, additionalProviders);
150    
151                BindingContext bindingContext = trace.getBindingContext();
152                ModuleDescriptor module = moduleContext.getModule();
153    
154                Collection<AnalysisCompletedHandlerExtension> analysisCompletedHandlerExtensions =
155                        AnalysisCompletedHandlerExtension.Companion.getInstances(moduleContext.getProject());
156    
157                for (AnalysisCompletedHandlerExtension extension : analysisCompletedHandlerExtensions) {
158                    AnalysisResult result = extension.analysisCompleted(project, module, bindingContext, files);
159                    if (result != null) return result;
160                }
161    
162                return AnalysisResult.success(bindingContext, module);
163            }
164            finally {
165                injector.destroy();
166            }
167        }
168    
169        @NotNull
170        public static MutableModuleContext createContextWithSealedModule(@NotNull Project project) {
171            MutableModuleContext context = ContextForNewModule(
172                    project, Name.special("<shared-module>"), JVM_MODULE_PARAMETERS
173            );
174            context.setDependencies(context.getModule(), KotlinBuiltIns.getInstance().getBuiltInsModule());
175            return context;
176        }
177    }