001    /*
002     * Copyright 2010-2014 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.k2js.analyze;
018    
019    import com.google.common.base.Predicate;
020    import com.google.common.base.Predicates;
021    import com.google.common.collect.ImmutableList;
022    import com.intellij.openapi.project.Project;
023    import com.intellij.psi.PsiFile;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.annotations.Nullable;
026    import org.jetbrains.jet.analyzer.AnalyzeExhaust;
027    import org.jetbrains.jet.analyzer.AnalyzerFacadeForEverything;
028    import org.jetbrains.jet.context.ContextPackage;
029    import org.jetbrains.jet.context.GlobalContextImpl;
030    import org.jetbrains.jet.di.InjectorForLazyResolve;
031    import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJs;
032    import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
033    import org.jetbrains.jet.lang.descriptors.DependencyKind;
034    import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
035    import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl;
036    import org.jetbrains.jet.lang.psi.JetFile;
037    import org.jetbrains.jet.lang.resolve.*;
038    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
039    import org.jetbrains.jet.lang.resolve.lazy.declarations.FileBasedDeclarationProviderFactory;
040    import org.jetbrains.jet.lang.resolve.name.Name;
041    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
042    import org.jetbrains.k2js.config.Config;
043    
044    import java.util.Collection;
045    import java.util.Collections;
046    import java.util.List;
047    
048    public final class AnalyzerFacadeForJS {
049        public static final List<ImportPath> DEFAULT_IMPORTS = ImmutableList.of(
050                new ImportPath("js.*"),
051                new ImportPath("java.lang.*"),
052                new ImportPath("kotlin.*"));
053    
054        private AnalyzerFacadeForJS() {
055        }
056    
057        @NotNull
058        public static BindingContext analyzeFilesAndCheckErrors(@NotNull List<JetFile> files,
059                @NotNull Config config) {
060            BindingContext bindingContext = analyzeFiles(files, Predicates.<PsiFile>alwaysTrue(), config).getBindingContext();
061            checkForErrors(Config.withJsLibAdded(files, config), bindingContext);
062            return bindingContext;
063        }
064    
065    
066        //NOTE: web demo related method
067        @SuppressWarnings("UnusedDeclaration")
068        @NotNull
069        public static BindingContext analyzeFiles(@NotNull Collection<JetFile> files, @NotNull Config config) {
070            return analyzeFiles(files, Predicates.<PsiFile>alwaysTrue(), config).getBindingContext();
071        }
072    
073        @NotNull
074        public static AnalyzeExhaust analyzeFiles(
075                @NotNull Collection<JetFile> files,
076                @NotNull Predicate<PsiFile> filesToAnalyzeCompletely, @NotNull Config config) {
077            return analyzeFiles(files, filesToAnalyzeCompletely, config, false);
078        }
079    
080        //TODO: refactor
081        @NotNull
082        public static AnalyzeExhaust analyzeFiles(
083                @NotNull Collection<JetFile> files,
084                @NotNull Predicate<PsiFile> filesToAnalyzeCompletely, @NotNull Config config,
085                boolean storeContextForBodiesResolve) {
086            Project project = config.getProject();
087    
088            ModuleDescriptorImpl owner = createJsModule("<module>");
089    
090            Predicate<PsiFile> completely = Predicates.and(notLibFiles(config.getLibFiles()), filesToAnalyzeCompletely);
091    
092            GlobalContextImpl globalContext = ContextPackage.GlobalContext();
093            TopDownAnalysisParameters topDownAnalysisParameters = new TopDownAnalysisParameters(
094                    globalContext.getStorageManager(), globalContext.getExceptionTracker(), completely, false, false, Collections.<AnalyzerScriptParameter>emptyList());
095    
096            ModuleDescriptor libraryModule = config.getLibraryModule();
097            if (libraryModule != null) {
098                owner.addFragmentProvider(DependencyKind.BINARIES, libraryModule.getPackageFragmentProvider()); // "import" analyzed library module
099            }
100    
101            BindingContext libraryContext = config.getLibraryContext();
102            BindingTrace trace = libraryContext == null
103                                 ? new BindingTraceContext()
104                                 : new DelegatingBindingTrace(libraryContext, "trace with preanalyzed library");
105            InjectorForTopDownAnalyzerForJs injector = new InjectorForTopDownAnalyzerForJs(project, topDownAnalysisParameters, trace, owner);
106            try {
107                Collection<JetFile> allFiles = libraryModule != null ?
108                                               files :
109                                               Config.withJsLibAdded(files, config);
110                TopDownAnalysisContext topDownAnalysisContext =
111                        injector.getTopDownAnalyzer().analyzeFiles(topDownAnalysisParameters, allFiles);
112                BodiesResolveContext bodiesResolveContext = storeContextForBodiesResolve ?
113                                                            new CachedBodiesResolveContext(topDownAnalysisContext) :
114                                                            null;
115                return AnalyzeExhaust.success(trace.getBindingContext(), bodiesResolveContext, owner);
116            }
117            finally {
118                injector.destroy();
119            }
120        }
121    
122        @NotNull
123        public static AnalyzeExhaust analyzeBodiesInFiles(
124                @NotNull Predicate<PsiFile> filesToAnalyzeCompletely,
125                @NotNull Config config,
126                @NotNull BindingTrace traceContext,
127                @NotNull BodiesResolveContext bodiesResolveContext,
128                @NotNull ModuleDescriptor module) {
129            Predicate<PsiFile> completely = Predicates.and(notLibFiles(config.getLibFiles()), filesToAnalyzeCompletely);
130    
131            return AnalyzerFacadeForEverything.analyzeBodiesInFilesWithJavaIntegration(
132                    config.getProject(), Collections.<AnalyzerScriptParameter>emptyList(), completely, traceContext, bodiesResolveContext,
133                    module);
134        }
135    
136        public static void checkForErrors(@NotNull Collection<JetFile> allFiles, @NotNull BindingContext bindingContext) {
137            AnalyzingUtils.throwExceptionOnErrors(bindingContext);
138            for (JetFile file : allFiles) {
139                AnalyzingUtils.checkForSyntacticErrors(file);
140            }
141        }
142    
143        @NotNull
144        private static Predicate<PsiFile> notLibFiles(@NotNull final List<JetFile> jsLibFiles) {
145            return new Predicate<PsiFile>() {
146                @Override
147                public boolean apply(@Nullable PsiFile file) {
148                    assert file instanceof JetFile;
149                    @SuppressWarnings("UnnecessaryLocalVariable") boolean notLibFile = !jsLibFiles.contains(file);
150                    return notLibFile;
151                }
152            };
153        }
154    
155        @NotNull
156        public static ResolveSession getLazyResolveSession(Collection<JetFile> files, Config config) {
157            GlobalContextImpl globalContext = ContextPackage.GlobalContext();
158            FileBasedDeclarationProviderFactory declarationProviderFactory = new FileBasedDeclarationProviderFactory(
159                    globalContext.getStorageManager(), Config.withJsLibAdded(files, config));
160            ModuleDescriptorImpl module = createJsModule("<lazy module>");
161            module.addFragmentProvider(DependencyKind.BUILT_INS, KotlinBuiltIns.getInstance().getBuiltInsModule().getPackageFragmentProvider());
162    
163            return new InjectorForLazyResolve(
164                    config.getProject(),
165                    globalContext,
166                    module,
167                    declarationProviderFactory,
168                    new BindingTraceContext()).getResolveSession();
169        }
170    
171        @NotNull
172        private static ModuleDescriptorImpl createJsModule(@NotNull String name) {
173            return new ModuleDescriptorImpl(Name.special(name), DEFAULT_IMPORTS, PlatformToKotlinClassMap.EMPTY);
174        }
175    
176    }