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.intellij.psi.PsiClass;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
023 import org.jetbrains.jet.lang.descriptors.ClassKind;
024 import org.jetbrains.jet.lang.descriptors.Modality;
025 import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
026 import org.jetbrains.jet.lang.resolve.BindingTrace;
027 import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils;
028 import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices;
029 import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode;
030 import org.jetbrains.jet.lang.resolve.java.kt.JetClassObjectAnnotation;
031 import org.jetbrains.jet.lang.resolve.java.provider.ClassPsiDeclarationProvider;
032 import org.jetbrains.jet.lang.resolve.java.scope.JavaClassNonStaticMembersScope;
033 import org.jetbrains.jet.lang.resolve.java.wrapper.PsiClassWrapper;
034 import org.jetbrains.jet.lang.resolve.name.FqName;
035 import org.jetbrains.jet.lang.resolve.name.FqNameBase;
036 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
037 import org.jetbrains.jet.lang.resolve.name.Name;
038 import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler;
039 import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
040 import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
041
042 import javax.inject.Inject;
043 import java.util.Collections;
044
045 import static org.jetbrains.jet.lang.resolve.DescriptorResolver.createEnumClassObjectValueOfMethod;
046 import static org.jetbrains.jet.lang.resolve.DescriptorResolver.createEnumClassObjectValuesMethod;
047 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassObjectName;
048
049 public 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 }