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.context.ContextPackage;
028    import org.jetbrains.jet.context.GlobalContextImpl;
029    import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJs;
030    import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
031    import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
032    import org.jetbrains.jet.lang.descriptors.impl.ModuleDescriptorImpl;
033    import org.jetbrains.jet.lang.psi.JetFile;
034    import org.jetbrains.jet.lang.resolve.*;
035    import org.jetbrains.jet.lang.resolve.name.Name;
036    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
037    import org.jetbrains.k2js.config.Config;
038    
039    import java.util.Collection;
040    import java.util.List;
041    
042    public final class TopDownAnalyzerFacadeForJS {
043        public static final List<ImportPath> DEFAULT_IMPORTS = ImmutableList.of(
044                new ImportPath("java.lang.*"),
045                new ImportPath("kotlin.*"),
046                new ImportPath("kotlin.js.*")
047        );
048    
049        private TopDownAnalyzerFacadeForJS() {
050        }
051    
052        //NOTE: web demo related method
053        @SuppressWarnings("UnusedDeclaration")
054        @NotNull
055        public static BindingContext analyzeFiles(@NotNull Collection<JetFile> files, @NotNull Config config) {
056            return analyzeFiles(files, Predicates.<PsiFile>alwaysTrue(), config).getBindingContext();
057        }
058    
059        //TODO: refactor
060        @NotNull
061        public static AnalyzeExhaust analyzeFiles(
062                @NotNull Collection<JetFile> files,
063                @NotNull Predicate<PsiFile> filesToAnalyzeCompletely,
064                @NotNull Config config
065        ) {
066            Project project = config.getProject();
067    
068            ModuleDescriptorImpl owner = createJsModule("<module>");
069    
070            Predicate<PsiFile> completely = Predicates.and(notLibFiles(config.getLibFiles()), filesToAnalyzeCompletely);
071    
072            GlobalContextImpl globalContext = ContextPackage.GlobalContext();
073            TopDownAnalysisParameters topDownAnalysisParameters = TopDownAnalysisParameters.create(
074                    globalContext.getStorageManager(), globalContext.getExceptionTracker(), completely, false, false);
075    
076            owner.addDependencyOnModule(owner);
077            owner.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule());
078            ModuleDescriptor libraryModule = config.getLibraryModule();
079            if (libraryModule != null) {
080                owner.addDependencyOnModule((ModuleDescriptorImpl) libraryModule); // "import" analyzed library module
081            }
082            owner.seal();
083    
084            BindingContext libraryContext = config.getLibraryContext();
085            BindingTrace trace = libraryContext == null
086                                 ? new BindingTraceContext()
087                                 : new DelegatingBindingTrace(libraryContext, "trace with preanalyzed library");
088            InjectorForTopDownAnalyzerForJs injector = new InjectorForTopDownAnalyzerForJs(project, topDownAnalysisParameters, trace, owner);
089            try {
090                Collection<JetFile> allFiles = libraryModule != null ?
091                                               files :
092                                               Config.withJsLibAdded(files, config);
093                injector.getTopDownAnalyzer().analyzeFiles(topDownAnalysisParameters, allFiles);
094                return AnalyzeExhaust.success(trace.getBindingContext(), owner);
095            }
096            finally {
097                injector.destroy();
098            }
099        }
100    
101        public static void checkForErrors(@NotNull Collection<JetFile> allFiles, @NotNull BindingContext bindingContext) {
102            AnalyzingUtils.throwExceptionOnErrors(bindingContext);
103            for (JetFile file : allFiles) {
104                AnalyzingUtils.checkForSyntacticErrors(file);
105            }
106        }
107    
108        @NotNull
109        private static Predicate<PsiFile> notLibFiles(@NotNull final List<JetFile> jsLibFiles) {
110            return new Predicate<PsiFile>() {
111                @Override
112                public boolean apply(@Nullable PsiFile file) {
113                    assert file instanceof JetFile;
114                    @SuppressWarnings("UnnecessaryLocalVariable") boolean notLibFile = !jsLibFiles.contains(file);
115                    return notLibFile;
116                }
117            };
118        }
119    
120        @NotNull
121        private static ModuleDescriptorImpl createJsModule(@NotNull String name) {
122            return new ModuleDescriptorImpl(Name.special(name), DEFAULT_IMPORTS, PlatformToKotlinClassMap.EMPTY);
123        }
124    
125    }