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.InjectorForLazyResolve;
030    import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJs;
031    import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
032    import org.jetbrains.jet.lang.descriptors.DependencyKind;
033    import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
034    import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl;
035    import org.jetbrains.jet.lang.psi.JetFile;
036    import org.jetbrains.jet.lang.resolve.*;
037    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
038    import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProviderFactory;
039    import org.jetbrains.jet.lang.resolve.name.Name;
040    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
041    import org.jetbrains.k2js.config.Config;
042    
043    import java.util.Collection;
044    import java.util.List;
045    
046    import static org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProviderFactoryService.createDeclarationProviderFactory;
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                new ImportPath("kotlin.reflect.*")
054        );
055    
056        private AnalyzerFacadeForJS() {
057        }
058    
059        @NotNull
060        public static BindingContext analyzeFilesAndCheckErrors(@NotNull List<JetFile> files,
061                @NotNull Config config) {
062            BindingContext bindingContext = analyzeFiles(files, Predicates.<PsiFile>alwaysTrue(), config).getBindingContext();
063            checkForErrors(Config.withJsLibAdded(files, config), bindingContext);
064            return bindingContext;
065        }
066    
067    
068        //NOTE: web demo related method
069        @SuppressWarnings("UnusedDeclaration")
070        @NotNull
071        public static BindingContext analyzeFiles(@NotNull Collection<JetFile> files, @NotNull Config config) {
072            return analyzeFiles(files, Predicates.<PsiFile>alwaysTrue(), config).getBindingContext();
073        }
074    
075        //TODO: refactor
076        @NotNull
077        public static AnalyzeExhaust analyzeFiles(
078                @NotNull Collection<JetFile> files,
079                @NotNull Predicate<PsiFile> filesToAnalyzeCompletely,
080                @NotNull Config config
081        ) {
082            Project project = config.getProject();
083    
084            ModuleDescriptorImpl owner = createJsModule("<module>");
085    
086            Predicate<PsiFile> completely = Predicates.and(notLibFiles(config.getLibFiles()), filesToAnalyzeCompletely);
087    
088            GlobalContextImpl globalContext = ContextPackage.GlobalContext();
089            TopDownAnalysisParameters topDownAnalysisParameters = TopDownAnalysisParameters.create(
090                    globalContext.getStorageManager(), globalContext.getExceptionTracker(), completely, false, false);
091    
092            ModuleDescriptor libraryModule = config.getLibraryModule();
093            if (libraryModule != null) {
094                owner.addFragmentProvider(DependencyKind.BINARIES, libraryModule.getPackageFragmentProvider()); // "import" analyzed library module
095            }
096    
097            BindingContext libraryContext = config.getLibraryContext();
098            BindingTrace trace = libraryContext == null
099                                 ? new BindingTraceContext()
100                                 : new DelegatingBindingTrace(libraryContext, "trace with preanalyzed library");
101            InjectorForTopDownAnalyzerForJs injector = new InjectorForTopDownAnalyzerForJs(project, topDownAnalysisParameters, trace, owner);
102            try {
103                Collection<JetFile> allFiles = libraryModule != null ?
104                                               files :
105                                               Config.withJsLibAdded(files, config);
106                injector.getTopDownAnalyzer().analyzeFiles(topDownAnalysisParameters, allFiles);
107                return AnalyzeExhaust.success(trace.getBindingContext(), owner);
108            }
109            finally {
110                injector.destroy();
111            }
112        }
113    
114        public static void checkForErrors(@NotNull Collection<JetFile> allFiles, @NotNull BindingContext bindingContext) {
115            AnalyzingUtils.throwExceptionOnErrors(bindingContext);
116            for (JetFile file : allFiles) {
117                AnalyzingUtils.checkForSyntacticErrors(file);
118            }
119        }
120    
121        @NotNull
122        private static Predicate<PsiFile> notLibFiles(@NotNull final List<JetFile> jsLibFiles) {
123            return new Predicate<PsiFile>() {
124                @Override
125                public boolean apply(@Nullable PsiFile file) {
126                    assert file instanceof JetFile;
127                    @SuppressWarnings("UnnecessaryLocalVariable") boolean notLibFile = !jsLibFiles.contains(file);
128                    return notLibFile;
129                }
130            };
131        }
132    
133        @NotNull
134        public static ResolveSession getLazyResolveSession(Collection<JetFile> files, Config config) {
135            GlobalContextImpl globalContext = ContextPackage.GlobalContext();
136            DeclarationProviderFactory declarationProviderFactory =
137                    createDeclarationProviderFactory(config.getProject(), globalContext.getStorageManager(),
138                                                     Config.withJsLibAdded(files, config));
139            ModuleDescriptorImpl module = createJsModule("<lazy module>");
140            module.addFragmentProvider(DependencyKind.BUILT_INS, KotlinBuiltIns.getInstance().getBuiltInsModule().getPackageFragmentProvider());
141    
142            return new InjectorForLazyResolve(
143                    config.getProject(),
144                    globalContext,
145                    module,
146                    declarationProviderFactory,
147                    new BindingTraceContext()).getResolveSession();
148        }
149    
150        @NotNull
151        private static ModuleDescriptorImpl createJsModule(@NotNull String name) {
152            return new ModuleDescriptorImpl(Name.special(name), DEFAULT_IMPORTS, PlatformToKotlinClassMap.EMPTY);
153        }
154    
155    }