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
017package org.jetbrains.k2js.analyze;
018
019import com.google.common.base.Predicate;
020import com.google.common.base.Predicates;
021import com.intellij.openapi.project.Project;
022import com.intellij.psi.PsiFile;
023import org.jetbrains.annotations.NotNull;
024import org.jetbrains.annotations.Nullable;
025import org.jetbrains.jet.analyzer.AnalyzeExhaust;
026import org.jetbrains.jet.analyzer.AnalyzerFacadeForEverything;
027import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJs;
028import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
029import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
030import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl;
031import org.jetbrains.jet.lang.psi.JetFile;
032import org.jetbrains.jet.lang.resolve.*;
033import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
034import org.jetbrains.jet.lang.resolve.lazy.declarations.FileBasedDeclarationProviderFactory;
035import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager;
036import org.jetbrains.jet.lang.resolve.name.FqName;
037import org.jetbrains.jet.lang.resolve.name.Name;
038import org.jetbrains.k2js.config.Config;
039
040import java.util.Collection;
041import java.util.Collections;
042import java.util.List;
043
044public 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}