001    /*
002     * Copyright 2010-2012 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.intellij.openapi.project.Project;
022    import com.intellij.psi.PsiFile;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.jet.analyzer.AnalyzeExhaust;
026    import org.jetbrains.jet.analyzer.AnalyzerFacadeForEverything;
027    import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJs;
028    import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
029    import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
030    import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl;
031    import org.jetbrains.jet.lang.psi.JetFile;
032    import org.jetbrains.jet.lang.resolve.*;
033    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
034    import org.jetbrains.jet.lang.resolve.lazy.declarations.FileBasedDeclarationProviderFactory;
035    import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager;
036    import org.jetbrains.jet.lang.resolve.name.FqName;
037    import org.jetbrains.jet.lang.resolve.name.Name;
038    import org.jetbrains.k2js.config.Config;
039    
040    import java.util.Collection;
041    import java.util.Collections;
042    import java.util.List;
043    
044    public final class AnalyzerFacadeForJS {
045    
046        private AnalyzerFacadeForJS() {
047        }
048    
049        @NotNull
050        public static BindingContext analyzeFilesAndCheckErrors(@NotNull List<JetFile> files,
051                @NotNull Config config) {
052            BindingContext bindingContext = analyzeFiles(files, Predicates.<PsiFile>alwaysTrue(), config).getBindingContext();
053            checkForErrors(Config.withJsLibAdded(files, config), bindingContext);
054            return bindingContext;
055        }
056    
057    
058        //NOTE: web demo related method
059        @SuppressWarnings("UnusedDeclaration")
060        @NotNull
061        public static BindingContext analyzeFiles(@NotNull Collection<JetFile> files, @NotNull Config config) {
062            return analyzeFiles(files, Predicates.<PsiFile>alwaysTrue(), config).getBindingContext();
063        }
064    
065        @NotNull
066        public static AnalyzeExhaust analyzeFiles(
067                @NotNull Collection<JetFile> files,
068                @NotNull Predicate<PsiFile> filesToAnalyzeCompletely, @NotNull Config config) {
069            return analyzeFiles(files, filesToAnalyzeCompletely, config, false);
070        }
071    
072        //TODO: refactor
073        @NotNull
074        public static AnalyzeExhaust analyzeFiles(
075                @NotNull Collection<JetFile> files,
076                @NotNull Predicate<PsiFile> filesToAnalyzeCompletely, @NotNull Config config,
077                boolean storeContextForBodiesResolve) {
078            Project project = config.getProject();
079    
080            ModuleDescriptorImpl owner = createJsModule("<module>");
081    
082            Predicate<PsiFile> completely = Predicates.and(notLibFiles(config.getLibFiles()), filesToAnalyzeCompletely);
083    
084            TopDownAnalysisParameters topDownAnalysisParameters = new TopDownAnalysisParameters(
085                    completely, false, false, Collections.<AnalyzerScriptParameter>emptyList());
086    
087            BindingContext libraryBindingContext = config.getLibraryBindingContext();
088            BindingTrace trace = libraryBindingContext == null ?
089                                 new ObservableBindingTrace(new BindingTraceContext()) :
090                                 new DelegatingBindingTrace(libraryBindingContext, "trace for analyzing library in js");
091            owner.setModuleConfiguration(new JsConfiguration(libraryBindingContext));
092            InjectorForTopDownAnalyzerForJs injector = new InjectorForTopDownAnalyzerForJs(project, topDownAnalysisParameters, trace, owner);
093            try {
094                Collection<JetFile> allFiles = libraryBindingContext != null ?
095                                               files :
096                                               Config.withJsLibAdded(files, config);
097                injector.getTopDownAnalyzer().analyzeFiles(allFiles, Collections.<AnalyzerScriptParameter>emptyList());
098                BodiesResolveContext bodiesResolveContext = storeContextForBodiesResolve ?
099                                                            new CachedBodiesResolveContext(injector.getTopDownAnalysisContext()) :
100                                                            null;
101                return AnalyzeExhaust.success(trace.getBindingContext(), bodiesResolveContext, owner);
102            }
103            finally {
104                injector.destroy();
105            }
106        }
107    
108        @NotNull
109        public static AnalyzeExhaust analyzeBodiesInFiles(
110                @NotNull Predicate<PsiFile> filesToAnalyzeCompletely,
111                @NotNull Config config,
112                @NotNull BindingTrace traceContext,
113                @NotNull BodiesResolveContext bodiesResolveContext,
114                @NotNull ModuleDescriptor module) {
115            Predicate<PsiFile> completely = Predicates.and(notLibFiles(config.getLibFiles()), filesToAnalyzeCompletely);
116    
117            return AnalyzerFacadeForEverything.analyzeBodiesInFilesWithJavaIntegration(
118                    config.getProject(), Collections.<AnalyzerScriptParameter>emptyList(), completely, traceContext, bodiesResolveContext,
119                    module);
120        }
121    
122        public static void checkForErrors(@NotNull Collection<JetFile> allFiles, @NotNull BindingContext bindingContext) {
123            AnalyzingUtils.throwExceptionOnErrors(bindingContext);
124            for (JetFile file : allFiles) {
125                AnalyzingUtils.checkForSyntacticErrors(file);
126            }
127        }
128    
129        @NotNull
130        private static Predicate<PsiFile> notLibFiles(@NotNull final List<JetFile> jsLibFiles) {
131            return new Predicate<PsiFile>() {
132                @Override
133                public boolean apply(@Nullable PsiFile file) {
134                    assert file instanceof JetFile;
135                    @SuppressWarnings("UnnecessaryLocalVariable") boolean notLibFile = !jsLibFiles.contains(file);
136                    return notLibFile;
137                }
138            };
139        }
140    
141        @NotNull
142        public static ResolveSession getLazyResolveSession(Collection<JetFile> files, Config config) {
143            LockBasedStorageManager storageManager = new LockBasedStorageManager();
144            FileBasedDeclarationProviderFactory declarationProviderFactory = new FileBasedDeclarationProviderFactory(
145                    storageManager, Config.withJsLibAdded(files, config), Predicates.<FqName>alwaysFalse());
146            ModuleDescriptorImpl lazyModule = createJsModule("<lazy module>");
147            lazyModule.setModuleConfiguration(new JsConfiguration(null));
148            return new ResolveSession(config.getProject(), storageManager, lazyModule, declarationProviderFactory);
149        }
150    
151        @NotNull
152        private static ModuleDescriptorImpl createJsModule(@NotNull String name) {
153            return new ModuleDescriptorImpl(Name.special(name), JsConfiguration.DEFAULT_IMPORT_PATHS, PlatformToKotlinClassMap.EMPTY);
154        }
155    
156    }