001/*
002 * Copyright 2010-2013 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.jet.lang.resolve.java;
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.jet.analyzer.AnalyzeExhaust;
025import org.jetbrains.jet.analyzer.AnalyzerFacade;
026import org.jetbrains.jet.analyzer.AnalyzerFacadeForEverything;
027import org.jetbrains.jet.di.InjectorForJavaDescriptorResolver;
028import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJvm;
029import org.jetbrains.jet.lang.ModuleConfiguration;
030import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
031import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl;
032import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
033import org.jetbrains.jet.lang.psi.JetFile;
034import org.jetbrains.jet.lang.resolve.*;
035import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
036import org.jetbrains.jet.lang.resolve.lazy.declarations.FileBasedDeclarationProviderFactory;
037import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager;
038import org.jetbrains.jet.lang.resolve.name.FqName;
039import org.jetbrains.jet.lang.resolve.name.Name;
040import org.jetbrains.jet.lang.resolve.scopes.JetScope;
041import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
042import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
043
044import java.util.Collection;
045import java.util.Collections;
046import java.util.List;
047
048public enum AnalyzerFacadeForJVM implements AnalyzerFacade {
049
050    INSTANCE;
051
052    private AnalyzerFacadeForJVM() {
053    }
054
055    @Override
056    @NotNull
057    public AnalyzeExhaust analyzeFiles(@NotNull Project project,
058            @NotNull Collection<JetFile> files,
059            @NotNull List<AnalyzerScriptParameter> scriptParameters,
060            @NotNull Predicate<PsiFile> filesToAnalyzeCompletely) {
061        return analyzeFilesWithJavaIntegration(project, files, scriptParameters, filesToAnalyzeCompletely, true);
062    }
063
064    @NotNull
065    @Override
066    public AnalyzeExhaust analyzeBodiesInFiles(@NotNull Project project,
067                                               @NotNull List<AnalyzerScriptParameter> scriptParameters,
068                                               @NotNull Predicate<PsiFile> filesForBodiesResolve,
069                                               @NotNull BindingTrace headersTraceContext,
070                                               @NotNull BodiesResolveContext bodiesResolveContext,
071                                               @NotNull ModuleDescriptor module
072    ) {
073        return AnalyzerFacadeForEverything.analyzeBodiesInFilesWithJavaIntegration(
074                project, scriptParameters, filesForBodiesResolve,
075                headersTraceContext, bodiesResolveContext, module);
076    }
077
078    @NotNull
079    @Override
080    public ResolveSession getLazyResolveSession(@NotNull Project fileProject, @NotNull Collection<JetFile> files) {
081        ModuleDescriptorImpl javaModule = createJavaModule("<java module>");
082
083        BindingTraceContext javaResolverTrace = new BindingTraceContext();
084        InjectorForJavaDescriptorResolver injector = new InjectorForJavaDescriptorResolver(fileProject, javaResolverTrace, javaModule);
085
086        final PsiClassFinder psiClassFinder = injector.getPsiClassFinder();
087
088        // TODO: Replace with stub declaration provider
089        LockBasedStorageManager storageManager = new LockBasedStorageManager();
090        FileBasedDeclarationProviderFactory declarationProviderFactory = new FileBasedDeclarationProviderFactory(storageManager, files, new Predicate<FqName>() {
091            @Override
092            public boolean apply(FqName fqName) {
093                return psiClassFinder.findPsiPackage(fqName) != null || new FqName("jet").equals(fqName);
094            }
095        });
096
097        final JavaDescriptorResolver javaDescriptorResolver = injector.getJavaDescriptorResolver();
098
099        ModuleConfiguration moduleConfiguration = new ModuleConfiguration() {
100
101            @Override
102            public void extendNamespaceScope(
103                    @NotNull BindingTrace trace,
104                    @NotNull NamespaceDescriptor namespaceDescriptor,
105                    @NotNull WritableScope namespaceMemberScope
106            ) {
107                FqName fqName = DescriptorUtils.getFQName(namespaceDescriptor).toSafe();
108                if (new FqName("jet").equals(fqName)) {
109                    namespaceMemberScope.importScope(KotlinBuiltIns.getInstance().getBuiltInsScope());
110                }
111                if (psiClassFinder.findPsiPackage(fqName) != null) {
112                    JetScope javaPackageScope = javaDescriptorResolver.getJavaPackageScope(namespaceDescriptor);
113                    assert javaPackageScope != null;
114                    namespaceMemberScope.importScope(javaPackageScope);
115                }
116            }
117        };
118        javaModule.setModuleConfiguration(moduleConfiguration);
119
120        ModuleDescriptorImpl lazyModule = createJavaModule("<lazy module>");
121        lazyModule.setModuleConfiguration(moduleConfiguration);
122
123        return new ResolveSession(fileProject, storageManager, lazyModule, declarationProviderFactory, javaResolverTrace);
124    }
125
126    public static AnalyzeExhaust analyzeOneFileWithJavaIntegrationAndCheckForErrors(
127            JetFile file, List<AnalyzerScriptParameter> scriptParameters) {
128        AnalyzingUtils.checkForSyntacticErrors(file);
129
130        AnalyzeExhaust analyzeExhaust = analyzeOneFileWithJavaIntegration(file, scriptParameters);
131
132        AnalyzingUtils.throwExceptionOnErrors(analyzeExhaust.getBindingContext());
133
134        return analyzeExhaust;
135    }
136
137    public static AnalyzeExhaust analyzeOneFileWithJavaIntegration(
138            JetFile file, List<AnalyzerScriptParameter> scriptParameters) {
139        return analyzeFilesWithJavaIntegration(file.getProject(), Collections.singleton(file), scriptParameters,
140                                               Predicates.<PsiFile>alwaysTrue());
141    }
142
143    public static AnalyzeExhaust analyzeFilesWithJavaIntegrationAndCheckForErrors(
144            Project project,
145            Collection<JetFile> files,
146            List<AnalyzerScriptParameter> scriptParameters,
147            Predicate<PsiFile> filesToAnalyzeCompletely
148    ) {
149        for (JetFile file : files) {
150            AnalyzingUtils.checkForSyntacticErrors(file); 
151        }
152       
153        AnalyzeExhaust analyzeExhaust = analyzeFilesWithJavaIntegration(
154                project, files, scriptParameters, filesToAnalyzeCompletely, false);
155
156        AnalyzingUtils.throwExceptionOnErrors(analyzeExhaust.getBindingContext());
157
158        return analyzeExhaust;
159    }
160
161    public static AnalyzeExhaust analyzeFilesWithJavaIntegration(
162            Project project,
163            Collection<JetFile> files,
164            List<AnalyzerScriptParameter> scriptParameters,
165            Predicate<PsiFile> filesToAnalyzeCompletely
166    ) {
167        return analyzeFilesWithJavaIntegration(
168                project, files, scriptParameters, filesToAnalyzeCompletely, false);
169    }
170
171    public static AnalyzeExhaust analyzeFilesWithJavaIntegration(
172            Project project, Collection<JetFile> files, List<AnalyzerScriptParameter> scriptParameters, Predicate<PsiFile> filesToAnalyzeCompletely,
173            boolean storeContextForBodiesResolve) {
174        BindingTraceContext bindingTraceContext = new BindingTraceContext();
175
176        return analyzeFilesWithJavaIntegration(project, files, bindingTraceContext, scriptParameters, filesToAnalyzeCompletely,
177                                               storeContextForBodiesResolve);
178    }
179
180    public static AnalyzeExhaust analyzeFilesWithJavaIntegration(
181            Project project,
182            Collection<JetFile> files,
183            BindingTrace trace,
184            List<AnalyzerScriptParameter> scriptParameters,
185            Predicate<PsiFile> filesToAnalyzeCompletely,
186            boolean storeContextForBodiesResolve
187    ) {
188        ModuleDescriptorImpl owner = createJavaModule("<module>");
189
190        TopDownAnalysisParameters topDownAnalysisParameters = new TopDownAnalysisParameters(
191                filesToAnalyzeCompletely, false, false, scriptParameters);
192
193        InjectorForTopDownAnalyzerForJvm injector = new InjectorForTopDownAnalyzerForJvm(
194                project, topDownAnalysisParameters,
195                new ObservableBindingTrace(trace), owner);
196        owner.setModuleConfiguration(injector.getJavaBridgeConfiguration());
197        try {
198            injector.getTopDownAnalyzer().analyzeFiles(files, scriptParameters);
199            BodiesResolveContext bodiesResolveContext = storeContextForBodiesResolve ?
200                                                        new CachedBodiesResolveContext(injector.getTopDownAnalysisContext()) :
201                                                        null;
202            return AnalyzeExhaust.success(trace.getBindingContext(), bodiesResolveContext, owner);
203        } finally {
204            injector.destroy();
205        }
206    }
207
208    @NotNull
209    public static ModuleDescriptorImpl createJavaModule(@NotNull String name) {
210        return new ModuleDescriptorImpl(Name.special(name), JavaBridgeConfiguration.ALL_JAVA_IMPORTS, JavaToKotlinClassMap.getInstance());
211    }
212}