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.resolver; 018 019import com.google.common.collect.Maps; 020import com.google.common.collect.Sets; 021import com.intellij.psi.PsiClass; 022import com.intellij.psi.PsiMember; 023import com.intellij.psi.PsiModifier; 024import com.intellij.psi.PsiPackage; 025import com.intellij.util.containers.ContainerUtil; 026import org.jetbrains.annotations.NotNull; 027import org.jetbrains.annotations.Nullable; 028import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; 029import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl; 030import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; 031import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorParent; 032import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 033import org.jetbrains.jet.lang.resolve.BindingContext; 034import org.jetbrains.jet.lang.resolve.BindingTrace; 035import org.jetbrains.jet.lang.resolve.DescriptorUtils; 036import org.jetbrains.jet.lang.resolve.java.*; 037import org.jetbrains.jet.lang.resolve.java.descriptor.JavaNamespaceDescriptor; 038import org.jetbrains.jet.lang.resolve.java.kt.JetPackageClassAnnotation; 039import org.jetbrains.jet.lang.resolve.java.provider.MembersCache; 040import org.jetbrains.jet.lang.resolve.java.scope.JavaBaseScope; 041import org.jetbrains.jet.lang.resolve.java.scope.JavaClassStaticMembersScope; 042import org.jetbrains.jet.lang.resolve.java.scope.JavaPackageScopeWithoutMembers; 043import org.jetbrains.jet.lang.resolve.java.scope.JavaScopeForKotlinNamespace; 044import org.jetbrains.jet.lang.resolve.name.FqName; 045 046import javax.inject.Inject; 047import java.util.Collections; 048import java.util.Map; 049import java.util.Set; 050 051public 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}