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.intellij.psi.PsiClass; 020import org.jetbrains.annotations.NotNull; 021import org.jetbrains.annotations.Nullable; 022import org.jetbrains.jet.lang.descriptors.ClassDescriptor; 023import org.jetbrains.jet.lang.descriptors.ClassKind; 024import org.jetbrains.jet.lang.descriptors.Modality; 025import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; 026import org.jetbrains.jet.lang.resolve.BindingTrace; 027import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils; 028import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; 029import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode; 030import org.jetbrains.jet.lang.resolve.java.kt.JetClassObjectAnnotation; 031import org.jetbrains.jet.lang.resolve.java.provider.ClassPsiDeclarationProvider; 032import org.jetbrains.jet.lang.resolve.java.scope.JavaClassNonStaticMembersScope; 033import org.jetbrains.jet.lang.resolve.java.wrapper.PsiClassWrapper; 034import org.jetbrains.jet.lang.resolve.name.FqName; 035import org.jetbrains.jet.lang.resolve.name.FqNameBase; 036import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; 037import org.jetbrains.jet.lang.resolve.name.Name; 038import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler; 039import org.jetbrains.jet.lang.resolve.scopes.WritableScope; 040import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; 041 042import javax.inject.Inject; 043import java.util.Collections; 044 045import static org.jetbrains.jet.lang.resolve.DescriptorResolver.createEnumClassObjectValueOfMethod; 046import static org.jetbrains.jet.lang.resolve.DescriptorResolver.createEnumClassObjectValuesMethod; 047import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassObjectName; 048 049public final class JavaClassObjectResolver { 050 051 private BindingTrace trace; 052 private JavaSemanticServices semanticServices; 053 private JavaSupertypeResolver supertypesResolver; 054 055 @Inject 056 public void setSupertypesResolver(JavaSupertypeResolver supertypesResolver) { 057 this.supertypesResolver = supertypesResolver; 058 } 059 060 @Inject 061 public void setTrace(BindingTrace trace) { 062 this.trace = trace; 063 } 064 065 @Inject 066 public void setSemanticServices(JavaSemanticServices semanticServices) { 067 this.semanticServices = semanticServices; 068 } 069 070 @Nullable 071 public ClassDescriptorFromJvmBytecode createClassObjectDescriptor( 072 @NotNull ClassDescriptor containing, 073 @NotNull PsiClass psiClass 074 ) { 075 DescriptorResolverUtils.checkPsiClassIsNotJet(psiClass); 076 077 if (psiClass.isEnum()) { 078 return createClassObjectDescriptorForEnum(containing, psiClass); 079 } 080 081 if (!DescriptorResolverUtils.isKotlinClass(psiClass)) { 082 return null; 083 } 084 085 PsiClass classObjectPsiClass = getClassObjectPsiClass(psiClass); 086 if (classObjectPsiClass == null) { 087 return null; 088 } 089 090 return createClassObjectFromPsi(containing, classObjectPsiClass); 091 } 092 093 @NotNull 094 private ClassDescriptorFromJvmBytecode createClassObjectFromPsi( 095 @NotNull ClassDescriptor containing, 096 @NotNull PsiClass classObjectPsiClass 097 ) { 098 String qualifiedName = classObjectPsiClass.getQualifiedName(); 099 assert qualifiedName != null; 100 FqName fqName = new FqName(qualifiedName); 101 ClassPsiDeclarationProvider classObjectData = semanticServices.getPsiDeclarationProviderFactory().createBinaryClassData(classObjectPsiClass); 102 ClassDescriptorFromJvmBytecode classObjectDescriptor 103 = new ClassDescriptorFromJvmBytecode(containing, ClassKind.CLASS_OBJECT, false); 104 classObjectDescriptor.setSupertypes(supertypesResolver.getSupertypes(classObjectDescriptor, 105 new PsiClassWrapper(classObjectPsiClass), 106 classObjectData, 107 Collections.<TypeParameterDescriptor>emptyList())); 108 setUpClassObjectDescriptor(classObjectDescriptor, containing, fqName, classObjectData, getClassObjectName(containing.getName())); 109 return classObjectDescriptor; 110 } 111 112 @NotNull 113 private ClassDescriptorFromJvmBytecode createClassObjectDescriptorForEnum( 114 @NotNull ClassDescriptor containing, 115 @NotNull PsiClass psiClass 116 ) { 117 ClassDescriptorFromJvmBytecode classObjectDescriptor = createSyntheticClassObject(containing, psiClass); 118 119 classObjectDescriptor.getBuilder().addFunctionDescriptor(createEnumClassObjectValuesMethod(classObjectDescriptor, trace)); 120 classObjectDescriptor.getBuilder().addFunctionDescriptor(createEnumClassObjectValueOfMethod(classObjectDescriptor, trace)); 121 122 return classObjectDescriptor; 123 } 124 125 @NotNull 126 private ClassDescriptorFromJvmBytecode createSyntheticClassObject( 127 @NotNull ClassDescriptor containing, 128 @NotNull PsiClass psiClass 129 ) { 130 FqNameUnsafe fqName = DescriptorResolverUtils.getFqNameForClassObject(psiClass); 131 ClassDescriptorFromJvmBytecode classObjectDescriptor = 132 new ClassDescriptorFromJvmBytecode(containing, ClassKind.CLASS_OBJECT, false); 133 ClassPsiDeclarationProvider data = semanticServices.getPsiDeclarationProviderFactory().createSyntheticClassObjectClassData(psiClass); 134 setUpClassObjectDescriptor(classObjectDescriptor, containing, fqName, data, getClassObjectName(containing.getName().asString())); 135 return classObjectDescriptor; 136 } 137 138 private void setUpClassObjectDescriptor( 139 @NotNull ClassDescriptorFromJvmBytecode classObjectDescriptor, 140 @NotNull ClassDescriptor containing, 141 @NotNull FqNameBase fqName, 142 @NotNull ClassPsiDeclarationProvider data, 143 @NotNull Name classObjectName 144 ) { 145 classObjectDescriptor.setName(classObjectName); 146 classObjectDescriptor.setModality(Modality.FINAL); 147 classObjectDescriptor.setVisibility(containing.getVisibility()); 148 classObjectDescriptor.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList()); 149 classObjectDescriptor.createTypeConstructor(); 150 JavaClassNonStaticMembersScope classMembersScope = new JavaClassNonStaticMembersScope(classObjectDescriptor, data, semanticServices); 151 WritableScopeImpl writableScope = 152 new WritableScopeImpl(classMembersScope, classObjectDescriptor, RedeclarationHandler.THROW_EXCEPTION, "Member lookup scope"); 153 writableScope.changeLockLevel(WritableScope.LockLevel.BOTH); 154 classObjectDescriptor.setScopeForMemberLookup(writableScope); 155 classObjectDescriptor.setScopeForConstructorResolve(classMembersScope); 156 } 157 158 159 @Nullable 160 private static PsiClass getClassObjectPsiClass(@NotNull PsiClass ownerClass) { 161 for (PsiClass inner : ownerClass.getInnerClasses()) { 162 if (JetClassObjectAnnotation.get(inner).isDefined()) { 163 return inner; 164 } 165 } 166 return null; 167 } 168}