001    /*
002     * Copyright 2010-2016 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.kotlin.load.java;
018    
019    import com.intellij.openapi.project.Project;
020    import com.intellij.openapi.vfs.VirtualFile;
021    import com.intellij.psi.PsiClass;
022    import com.intellij.psi.PsiPackage;
023    import com.intellij.psi.search.DelegatingGlobalSearchScope;
024    import com.intellij.psi.search.GlobalSearchScope;
025    import org.jetbrains.annotations.NotNull;
026    import org.jetbrains.annotations.Nullable;
027    import org.jetbrains.kotlin.asJava.KtLightClassMarker;
028    import org.jetbrains.kotlin.idea.KotlinFileType;
029    import org.jetbrains.kotlin.load.java.structure.JavaClass;
030    import org.jetbrains.kotlin.load.java.structure.JavaPackage;
031    import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl;
032    import org.jetbrains.kotlin.load.java.structure.impl.JavaPackageImpl;
033    import org.jetbrains.kotlin.name.ClassId;
034    import org.jetbrains.kotlin.name.FqName;
035    import org.jetbrains.kotlin.resolve.BindingTrace;
036    import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer;
037    import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade;
038    import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer;
039    
040    import javax.annotation.PostConstruct;
041    import javax.inject.Inject;
042    import java.util.Set;
043    
044    public class JavaClassFinderImpl implements JavaClassFinder {
045        private Project project;
046        private GlobalSearchScope baseScope;
047        private GlobalSearchScope javaSearchScope;
048        private KotlinJavaPsiFacade javaFacade;
049    
050        @Inject
051        public void setProject(@NotNull Project project) {
052            this.project = project;
053        }
054    
055        @Inject
056        public void setScope(@NotNull GlobalSearchScope scope) {
057            this.baseScope = scope;
058        }
059    
060        public class FilterOutKotlinSourceFilesScope extends DelegatingGlobalSearchScope {
061            public FilterOutKotlinSourceFilesScope(@NotNull GlobalSearchScope baseScope) {
062                super(baseScope);
063            }
064    
065            @Override
066            public boolean contains(@NotNull VirtualFile file) {
067                return myBaseScope.contains(file) && (file.isDirectory() || file.getFileType() != KotlinFileType.INSTANCE);
068            }
069    
070            @NotNull
071            public GlobalSearchScope getBase() {
072                return myBaseScope;
073            }
074    
075            //NOTE: expected by class finder to be not null
076            @NotNull
077            @Override
078            public Project getProject() {
079                return project;
080            }
081    
082            @Override
083            public String toString() {
084                return "JCFI: " + myBaseScope;
085            }
086        }
087    
088        @PostConstruct
089        public void initialize(@NotNull BindingTrace trace, @NotNull KotlinCodeAnalyzer codeAnalyzer) {
090            javaSearchScope = new FilterOutKotlinSourceFilesScope(baseScope);
091            javaFacade = KotlinJavaPsiFacade.getInstance(project);
092            CodeAnalyzerInitializer.Companion.getInstance(project).initialize(trace, codeAnalyzer.getModuleDescriptor(), codeAnalyzer);
093        }
094    
095        @Nullable
096        @Override
097        public JavaClass findClass(@NotNull ClassId classId) {
098            PsiClass psiClass = javaFacade.findClass(classId, javaSearchScope);
099            if (psiClass == null) return null;
100    
101            JavaClassImpl javaClass = new JavaClassImpl(psiClass);
102            FqName fqName = classId.asSingleFqName();
103            if (!fqName.equals(javaClass.getFqName())) {
104                throw new IllegalStateException("Requested " + fqName + ", got " + javaClass.getFqName());
105            }
106    
107            if (psiClass instanceof KtLightClassMarker) {
108                throw new IllegalStateException("Kotlin light classes should not be found by JavaPsiFacade, resolving: " + fqName);
109            }
110    
111            return javaClass;
112        }
113    
114        @Nullable
115        @Override
116        public JavaPackage findPackage(@NotNull FqName fqName) {
117            PsiPackage psiPackage = javaFacade.findPackage(fqName.asString(), javaSearchScope);
118            return psiPackage == null ? null : new JavaPackageImpl(psiPackage, javaSearchScope);
119        }
120    
121        @Nullable
122        @Override
123        public Set<String> knownClassNamesInPackage(@NotNull FqName packageFqName) {
124            return javaFacade.knownClassNamesInPackage(packageFqName);
125        }
126    }