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 }