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 com.google.common.collect.Maps;
020 import com.google.common.collect.Sets;
021 import com.intellij.psi.PsiClass;
022 import com.intellij.psi.PsiMember;
023 import com.intellij.psi.PsiModifier;
024 import com.intellij.psi.PsiPackage;
025 import com.intellij.util.containers.ContainerUtil;
026 import org.jetbrains.annotations.NotNull;
027 import org.jetbrains.annotations.Nullable;
028 import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
029 import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl;
030 import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
031 import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorParent;
032 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
033 import org.jetbrains.jet.lang.resolve.BindingContext;
034 import org.jetbrains.jet.lang.resolve.BindingTrace;
035 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
036 import org.jetbrains.jet.lang.resolve.java.*;
037 import org.jetbrains.jet.lang.resolve.java.descriptor.JavaNamespaceDescriptor;
038 import org.jetbrains.jet.lang.resolve.java.kt.JetPackageClassAnnotation;
039 import org.jetbrains.jet.lang.resolve.java.provider.MembersCache;
040 import org.jetbrains.jet.lang.resolve.java.scope.JavaBaseScope;
041 import org.jetbrains.jet.lang.resolve.java.scope.JavaClassStaticMembersScope;
042 import org.jetbrains.jet.lang.resolve.java.scope.JavaPackageScopeWithoutMembers;
043 import org.jetbrains.jet.lang.resolve.java.scope.JavaScopeForKotlinNamespace;
044 import org.jetbrains.jet.lang.resolve.name.FqName;
045
046 import javax.inject.Inject;
047 import java.util.Collections;
048 import java.util.Map;
049 import java.util.Set;
050
051 public final class JavaNamespaceResolver {
052
053 @NotNull
054 public static final ModuleDescriptor FAKE_ROOT_MODULE = new ModuleDescriptorImpl(JavaDescriptorResolver.JAVA_ROOT,
055 JavaBridgeConfiguration.ALL_JAVA_IMPORTS,
056 JavaToKotlinClassMap.getInstance());
057 @NotNull
058 private final Map<FqName, JavaBaseScope> resolvedNamespaceCache = Maps.newHashMap();
059 @NotNull
060 private final Set<FqName> unresolvedCache = Sets.newHashSet();
061
062 private PsiClassFinder psiClassFinder;
063 private BindingTrace trace;
064 private JavaSemanticServices javaSemanticServices;
065
066 public JavaNamespaceResolver() {
067 }
068
069 @Inject
070 public void setPsiClassFinder(PsiClassFinder psiClassFinder) {
071 this.psiClassFinder = psiClassFinder;
072 }
073
074 @Inject
075 public void setTrace(BindingTrace trace) {
076 this.trace = trace;
077 }
078
079 @Inject
080 public void setJavaSemanticServices(JavaSemanticServices javaSemanticServices) {
081 this.javaSemanticServices = javaSemanticServices;
082 }
083
084 @Nullable
085 public NamespaceDescriptor resolveNamespace(@NotNull FqName qualifiedName, @NotNull DescriptorSearchRule searchRule) {
086 // First, let's check that there is no Kotlin package:
087 NamespaceDescriptor kotlinNamespaceDescriptor = javaSemanticServices.getKotlinNamespaceDescriptor(qualifiedName);
088 if (kotlinNamespaceDescriptor != null) {
089 return searchRule.processFoundInKotlin(kotlinNamespaceDescriptor);
090 }
091
092 if (unresolvedCache.contains(qualifiedName)) {
093 return null;
094 }
095 JavaBaseScope scope = resolvedNamespaceCache.get(qualifiedName);
096 if (scope != null) {
097 return (NamespaceDescriptor) scope.getContainingDeclaration();
098 }
099
100 NamespaceDescriptorParent parentNs = resolveParentNamespace(qualifiedName);
101 if (parentNs == null) {
102 return null;
103 }
104
105 JavaNamespaceDescriptor javaNamespaceDescriptor = new JavaNamespaceDescriptor(
106 parentNs,
107 Collections.<AnnotationDescriptor>emptyList(), // TODO
108 qualifiedName
109 );
110
111 JavaBaseScope newScope = createNamespaceScope(qualifiedName, javaNamespaceDescriptor);
112 if (newScope == null) {
113 return null;
114 }
115
116 trace.record(BindingContext.NAMESPACE, newScope.getPsiElement(), javaNamespaceDescriptor);
117
118 javaNamespaceDescriptor.setMemberScope(newScope);
119
120 return javaNamespaceDescriptor;
121 }
122
123 @Nullable
124 public NamespaceDescriptor resolveNamespace(@NotNull FqName qualifiedName) {
125 return resolveNamespace(qualifiedName, DescriptorSearchRule.ERROR_IF_FOUND_IN_KOTLIN);
126 }
127
128 @Nullable
129 private NamespaceDescriptorParent resolveParentNamespace(@NotNull FqName fqName) {
130 if (fqName.isRoot()) {
131 return FAKE_ROOT_MODULE;
132 }
133 else {
134 return resolveNamespace(fqName.parent(), DescriptorSearchRule.INCLUDE_KOTLIN);
135 }
136 }
137
138 @Nullable
139 private JavaBaseScope createNamespaceScope(
140 @NotNull FqName fqName,
141 @NotNull NamespaceDescriptor namespaceDescriptor
142 ) {
143 JavaBaseScope namespaceScope = doCreateNamespaceScope(fqName, namespaceDescriptor);
144 cache(fqName, namespaceScope);
145 return namespaceScope;
146 }
147
148 @Nullable
149 private JavaBaseScope doCreateNamespaceScope(
150 @NotNull FqName fqName,
151 @NotNull NamespaceDescriptor namespaceDescriptor
152 ) {
153 PsiPackage psiPackage = psiClassFinder.findPsiPackage(fqName);
154 if (psiPackage != null) {
155 PsiClass psiClass = getPsiClassForJavaPackageScope(fqName);
156 trace.record(JavaBindingContext.JAVA_NAMESPACE_KIND, namespaceDescriptor, JavaNamespaceKind.PROPER);
157 if (psiClass == null) {
158 return new JavaPackageScopeWithoutMembers(
159 namespaceDescriptor,
160 javaSemanticServices.getPsiDeclarationProviderFactory().createDeclarationProviderForNamespaceWithoutMembers(psiPackage),
161 fqName, javaSemanticServices);
162 }
163
164 AbiVersionUtil.checkAbiVersion(psiClass, JetPackageClassAnnotation.get(psiClass), trace);
165 return new JavaScopeForKotlinNamespace(
166 namespaceDescriptor,
167 javaSemanticServices.getPsiDeclarationProviderFactory().createDeclarationForKotlinNamespace(psiPackage, psiClass),
168 fqName, javaSemanticServices);
169 }
170
171 PsiClass psiClass = psiClassFinder.findPsiClass(fqName, PsiClassFinder.RuntimeClassesHandleMode.IGNORE);
172 if (psiClass == null) {
173 return null;
174 }
175 if (DescriptorResolverUtils.isKotlinClass(psiClass)) {
176 return null;
177 }
178 if (!hasStaticMembers(psiClass)) {
179 return null;
180 }
181 trace.record(JavaBindingContext.JAVA_NAMESPACE_KIND, namespaceDescriptor, JavaNamespaceKind.CLASS_STATICS);
182 return new JavaClassStaticMembersScope(
183 namespaceDescriptor,
184 javaSemanticServices.getPsiDeclarationProviderFactory().createDeclarationProviderForClassStaticMembers(psiClass),
185 fqName, javaSemanticServices);
186 }
187
188 private void cache(@NotNull FqName fqName, @Nullable JavaBaseScope packageScope) {
189 if (packageScope == null) {
190 unresolvedCache.add(fqName);
191 return;
192 }
193 JavaBaseScope oldValue = resolvedNamespaceCache.put(fqName, packageScope);
194 if (oldValue != null) {
195 throw new IllegalStateException("rewrite at " + fqName);
196 }
197 }
198
199 @Nullable
200 public JavaBaseScope getJavaPackageScopeForExistingNamespaceDescriptor(@NotNull NamespaceDescriptor namespaceDescriptor) {
201 FqName fqName = DescriptorUtils.getFQName(namespaceDescriptor).toSafe();
202 if (unresolvedCache.contains(fqName)) {
203 throw new IllegalStateException(
204 "This means that we are trying to create a Java package, but have a package with the same FQN defined in Kotlin: " +
205 fqName);
206 }
207 JavaBaseScope alreadyResolvedScope = resolvedNamespaceCache.get(fqName);
208 if (alreadyResolvedScope != null) {
209 return alreadyResolvedScope;
210 }
211 return createNamespaceScope(fqName, namespaceDescriptor);
212 }
213
214 @Nullable
215 private PsiClass getPsiClassForJavaPackageScope(@NotNull FqName packageFQN) {
216 return psiClassFinder.findPsiClass(PackageClassUtils.getPackageClassFqName(packageFQN), PsiClassFinder.RuntimeClassesHandleMode.IGNORE);
217 }
218
219 private static boolean hasStaticMembers(@NotNull PsiClass psiClass) {
220 for (PsiMember member : ContainerUtil.concat(psiClass.getMethods(), psiClass.getFields())) {
221 if (member.hasModifierProperty(PsiModifier.STATIC) && !DescriptorResolverUtils.shouldBeInEnumClassObject(member)) {
222 return true;
223 }
224 }
225
226 for (PsiClass nestedClass : psiClass.getInnerClasses()) {
227 if (MembersCache.isSamInterface(nestedClass)) {
228 return true;
229 }
230 if (nestedClass.hasModifierProperty(PsiModifier.STATIC) && hasStaticMembers(nestedClass)) {
231 return true;
232 }
233 }
234
235 return false;
236 }
237 }