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
017 package org.jetbrains.jet.lang.resolve.java.resolver;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.annotations.Nullable;
021 import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
022 import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl;
023 import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
024 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025 import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorParent;
026 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
027 import org.jetbrains.jet.lang.resolve.java.*;
028 import org.jetbrains.jet.lang.resolve.java.descriptor.JavaNamespaceDescriptor;
029 import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap;
030 import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils;
031 import org.jetbrains.jet.lang.resolve.java.scope.JavaClassStaticMembersScope;
032 import org.jetbrains.jet.lang.resolve.java.scope.JavaPackageScope;
033 import org.jetbrains.jet.lang.resolve.java.structure.JavaClass;
034 import org.jetbrains.jet.lang.resolve.java.structure.JavaField;
035 import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod;
036 import org.jetbrains.jet.lang.resolve.java.structure.JavaPackage;
037 import org.jetbrains.jet.lang.resolve.kotlin.DeserializedDescriptorResolver;
038 import org.jetbrains.jet.lang.resolve.kotlin.KotlinClassFinder;
039 import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass;
040 import org.jetbrains.jet.lang.resolve.name.FqName;
041 import org.jetbrains.jet.lang.resolve.name.Name;
042 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
043
044 import javax.inject.Inject;
045 import java.util.*;
046
047 import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.INCLUDE_KOTLIN_SOURCES;
048
049 public final class JavaNamespaceResolver {
050
051 @NotNull
052 public static final ModuleDescriptor FAKE_ROOT_MODULE = new ModuleDescriptorImpl(JavaDescriptorResolver.JAVA_ROOT,
053 JavaBridgeConfiguration.ALL_JAVA_IMPORTS,
054 JavaToKotlinClassMap.getInstance());
055 @NotNull
056 private final Map<FqName, JetScope> resolvedNamespaceCache = new HashMap<FqName, JetScope>();
057 @NotNull
058 private final Set<FqName> unresolvedCache = new HashSet<FqName>();
059
060 private JavaClassFinder javaClassFinder;
061 private JavaResolverCache cache;
062 private JavaMemberResolver memberResolver;
063
064 private DeserializedDescriptorResolver deserializedDescriptorResolver;
065 private KotlinClassFinder kotlinClassFinder;
066
067 @Inject
068 public void setKotlinClassFinder(KotlinClassFinder kotlinClassFinder) {
069 this.kotlinClassFinder = kotlinClassFinder;
070 }
071
072 @Inject
073 public void setJavaClassFinder(JavaClassFinder javaClassFinder) {
074 this.javaClassFinder = javaClassFinder;
075 }
076
077 @Inject
078 public void setCache(JavaResolverCache cache) {
079 this.cache = cache;
080 }
081
082 @Inject
083 public void setMemberResolver(@NotNull JavaMemberResolver memberResolver) {
084 this.memberResolver = memberResolver;
085 }
086
087 @Inject
088 public void setDeserializedDescriptorResolver(DeserializedDescriptorResolver deserializedDescriptorResolver) {
089 this.deserializedDescriptorResolver = deserializedDescriptorResolver;
090 }
091
092 @Nullable
093 public NamespaceDescriptor resolveNamespace(@NotNull FqName qualifiedName, @NotNull DescriptorSearchRule searchRule) {
094 if (searchRule == INCLUDE_KOTLIN_SOURCES) {
095 NamespaceDescriptor kotlinNamespaceDescriptor = cache.getPackageResolvedFromSource(qualifiedName);
096 if (kotlinNamespaceDescriptor != null) {
097 return kotlinNamespaceDescriptor;
098 }
099 }
100
101 if (unresolvedCache.contains(qualifiedName)) {
102 return null;
103 }
104 JetScope scope = resolvedNamespaceCache.get(qualifiedName);
105 if (scope != null) {
106 return (NamespaceDescriptor) scope.getContainingDeclaration();
107 }
108
109 NamespaceDescriptorParent parentNs = resolveParentNamespace(qualifiedName);
110 if (parentNs == null) {
111 return null;
112 }
113
114 JavaNamespaceDescriptor javaNamespaceDescriptor = new JavaNamespaceDescriptor(
115 parentNs,
116 Collections.<AnnotationDescriptor>emptyList(), // TODO
117 qualifiedName
118 );
119
120 JetScope newScope = createNamespaceScope(qualifiedName, javaNamespaceDescriptor, true);
121 if (newScope == null) {
122 return null;
123 }
124
125 javaNamespaceDescriptor.setMemberScope(newScope);
126
127 return javaNamespaceDescriptor;
128 }
129
130 @Nullable
131 private NamespaceDescriptorParent resolveParentNamespace(@NotNull FqName fqName) {
132 if (fqName.isRoot()) {
133 return FAKE_ROOT_MODULE;
134 }
135 else {
136 return resolveNamespace(fqName.parent(), INCLUDE_KOTLIN_SOURCES);
137 }
138 }
139
140 @Nullable
141 private JetScope createNamespaceScope(@NotNull FqName fqName, @NotNull NamespaceDescriptor namespaceDescriptor, boolean record) {
142 JetScope namespaceScope = doCreateNamespaceScope(fqName, namespaceDescriptor, record);
143 cache(fqName, namespaceScope);
144 return namespaceScope;
145 }
146
147 @Nullable
148 private JetScope doCreateNamespaceScope(
149 @NotNull FqName fqName,
150 @NotNull NamespaceDescriptor namespaceDescriptor,
151 boolean record
152 ) {
153 JavaPackage javaPackage = javaClassFinder.findPackage(fqName);
154 if (javaPackage != null) {
155 FqName packageClassFqName = PackageClassUtils.getPackageClassFqName(fqName);
156 KotlinJvmBinaryClass kotlinClass = kotlinClassFinder.find(packageClassFqName);
157
158 cache.recordProperNamespace(namespaceDescriptor);
159
160 if (kotlinClass != null) {
161 JetScope kotlinPackageScope = deserializedDescriptorResolver.createKotlinPackageScope(namespaceDescriptor, kotlinClass);
162 if (kotlinPackageScope != null) {
163 return kotlinPackageScope;
164 }
165 }
166
167
168 // Otherwise (if psiClass is null or doesn't have a supported Kotlin annotation), it's a Java class and the package is empty
169 if (record) {
170 cache.recordPackage(javaPackage, namespaceDescriptor);
171 }
172
173 return new JavaPackageScope(namespaceDescriptor, javaPackage, fqName, memberResolver);
174 }
175
176 JavaClass javaClass = javaClassFinder.findClass(fqName);
177 if (javaClass == null) {
178 return null;
179 }
180
181 if (DescriptorResolverUtils.isCompiledKotlinClassOrPackageClass(javaClass)) {
182 return null;
183 }
184 if (!hasStaticMembers(javaClass)) {
185 return null;
186 }
187
188 cache.recordClassStaticMembersNamespace(namespaceDescriptor);
189
190 if (record) {
191 cache.recordPackage(javaClass, namespaceDescriptor);
192 }
193
194 return new JavaClassStaticMembersScope(namespaceDescriptor, fqName, javaClass, memberResolver);
195 }
196
197 private void cache(@NotNull FqName fqName, @Nullable JetScope packageScope) {
198 if (packageScope == null) {
199 unresolvedCache.add(fqName);
200 return;
201 }
202 JetScope oldValue = resolvedNamespaceCache.put(fqName, packageScope);
203 if (oldValue != null) {
204 throw new IllegalStateException("rewrite at " + fqName);
205 }
206 }
207
208 @Nullable
209 public JetScope getJavaPackageScopeForExistingNamespaceDescriptor(@NotNull NamespaceDescriptor namespaceDescriptor) {
210 FqName fqName = DescriptorUtils.getFQName(namespaceDescriptor).toSafe();
211 if (unresolvedCache.contains(fqName)) {
212 throw new IllegalStateException(
213 "This means that we are trying to create a Java package, but have a package with the same FQN defined in Kotlin: " +
214 fqName);
215 }
216 JetScope alreadyResolvedScope = resolvedNamespaceCache.get(fqName);
217 if (alreadyResolvedScope != null) {
218 return alreadyResolvedScope;
219 }
220 return createNamespaceScope(fqName, namespaceDescriptor, false);
221 }
222
223 private static boolean hasStaticMembers(@NotNull JavaClass javaClass) {
224 for (JavaMethod method : javaClass.getMethods()) {
225 if (method.isStatic() && !DescriptorResolverUtils.shouldBeInEnumClassObject(method)) {
226 return true;
227 }
228 }
229
230 for (JavaField field : javaClass.getFields()) {
231 if (field.isStatic() && !DescriptorResolverUtils.shouldBeInEnumClassObject(field)) {
232 return true;
233 }
234 }
235
236 for (JavaClass nestedClass : javaClass.getInnerClasses()) {
237 if (SingleAbstractMethodUtils.isSamInterface(nestedClass)) {
238 return true;
239 }
240 if (nestedClass.isStatic() && hasStaticMembers(nestedClass)) {
241 return true;
242 }
243 }
244
245 return false;
246 }
247
248 @NotNull
249 public Collection<Name> getClassNamesInPackage(@NotNull FqName packageName) {
250 JavaPackage javaPackage = javaClassFinder.findPackage(packageName);
251 if (javaPackage == null) return Collections.emptyList();
252
253 Collection<JavaClass> classes = DescriptorResolverUtils.getClassesInPackage(javaPackage);
254 List<Name> result = new ArrayList<Name>(classes.size());
255 for (JavaClass javaClass : classes) {
256 if (DescriptorResolverUtils.isCompiledKotlinClass(javaClass)) {
257 result.add(javaClass.getName());
258 }
259 }
260
261 return result;
262 }
263 }