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.jet.lang.descriptors.*;
021 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
022 import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorImpl;
023 import org.jetbrains.jet.lang.descriptors.impl.PropertyDescriptorImpl;
024 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
025 import org.jetbrains.jet.lang.resolve.java.descriptor.JavaPropertyDescriptor;
026 import org.jetbrains.jet.lang.resolve.java.descriptor.JavaPropertyDescriptorForObject;
027 import org.jetbrains.jet.lang.resolve.java.scope.NamedMembers;
028 import org.jetbrains.jet.lang.resolve.java.structure.JavaField;
029 import org.jetbrains.jet.lang.resolve.name.Name;
030 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
031 import org.jetbrains.jet.lang.types.JetType;
032 import org.jetbrains.jet.lang.types.TypeUtils;
033
034 import javax.inject.Inject;
035 import java.util.*;
036
037 import static org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils.resolveOverrides;
038
039 public final class JavaPropertyResolver {
040 private JavaTypeTransformer typeTransformer;
041 private JavaResolverCache cache;
042 private JavaAnnotationResolver annotationResolver;
043 private ExternalSignatureResolver externalSignatureResolver;
044 private FakeOverrideVisibilityResolver fakeOverrideVisibilityResolver;
045
046 public JavaPropertyResolver() {
047 }
048
049 @Inject
050 public void setTypeTransformer(@NotNull JavaTypeTransformer javaTypeTransformer) {
051 this.typeTransformer = javaTypeTransformer;
052 }
053
054 @Inject
055 public void setCache(JavaResolverCache cache) {
056 this.cache = cache;
057 }
058
059 @Inject
060 public void setAnnotationResolver(JavaAnnotationResolver annotationResolver) {
061 this.annotationResolver = annotationResolver;
062 }
063
064 @Inject
065 public void setExternalSignatureResolver(ExternalSignatureResolver externalSignatureResolver) {
066 this.externalSignatureResolver = externalSignatureResolver;
067 }
068
069 @Inject
070 public void setFakeOverrideVisibilityResolver(FakeOverrideVisibilityResolver fakeOverrideVisibilityResolver) {
071 this.fakeOverrideVisibilityResolver = fakeOverrideVisibilityResolver;
072 }
073
074 @NotNull
075 public Set<VariableDescriptor> resolveFieldGroup(@NotNull NamedMembers members, @NotNull ClassOrNamespaceDescriptor owner) {
076 Name propertyName = members.getName();
077
078 List<JavaField> fields = members.getFields();
079
080 Set<PropertyDescriptor> propertiesFromCurrent = new HashSet<PropertyDescriptor>(1);
081 assert fields.size() <= 1;
082 if (fields.size() == 1) {
083 JavaField field = fields.iterator().next();
084 if (DescriptorResolverUtils.isCorrectOwnerForEnumMember(owner, field)) {
085 propertiesFromCurrent.add(resolveProperty(owner, propertyName, field));
086 }
087 }
088
089 Set<PropertyDescriptor> properties = new HashSet<PropertyDescriptor>();
090 if (owner instanceof ClassDescriptor) {
091 ClassDescriptor classDescriptor = (ClassDescriptor) owner;
092
093 Collection<PropertyDescriptor> propertiesFromSupertypes = getPropertiesFromSupertypes(propertyName, classDescriptor);
094
095 properties.addAll(resolveOverrides(propertyName, propertiesFromSupertypes, propertiesFromCurrent, classDescriptor,
096 fakeOverrideVisibilityResolver));
097 }
098
099 properties.addAll(propertiesFromCurrent);
100
101 return new HashSet<VariableDescriptor>(properties);
102 }
103
104 @NotNull
105 private PropertyDescriptor resolveProperty(@NotNull ClassOrNamespaceDescriptor owner, @NotNull Name name, @NotNull JavaField field) {
106 boolean isVar = !field.isFinal();
107
108 PropertyDescriptorImpl propertyDescriptor = createPropertyDescriptor(owner, name, field, isVar);
109 propertyDescriptor.initialize(null, null);
110
111 TypeVariableResolver typeVariableResolver =
112 new TypeVariableResolverImpl(Collections.<TypeParameterDescriptor>emptyList(), propertyDescriptor);
113
114 JetType propertyType = getPropertyType(field, typeVariableResolver);
115
116 ExternalSignatureResolver.AlternativeFieldSignature effectiveSignature =
117 externalSignatureResolver.resolveAlternativeFieldSignature(field, propertyType, isVar);
118 List<String> signatureErrors = effectiveSignature.getErrors();
119 if (!signatureErrors.isEmpty()) {
120 externalSignatureResolver.reportSignatureErrors(propertyDescriptor, signatureErrors);
121 }
122
123 propertyDescriptor.setType(
124 effectiveSignature.getReturnType(),
125 Collections.<TypeParameterDescriptor>emptyList(),
126 DescriptorUtils.getExpectedThisObjectIfNeeded(owner),
127 (JetType) null
128 );
129
130 cache.recordField(field, propertyDescriptor);
131
132 return propertyDescriptor;
133 }
134
135 @NotNull
136 private PropertyDescriptorImpl createPropertyDescriptor(
137 @NotNull ClassOrNamespaceDescriptor owner,
138 @NotNull Name propertyName,
139 @NotNull JavaField field,
140 boolean isVar
141 ) {
142 List<AnnotationDescriptor> annotations = annotationResolver.resolveAnnotations(field);
143 Visibility visibility = field.getVisibility();
144
145 if (field.isEnumEntry()) {
146 assert !isVar : "Enum entries should be immutable.";
147 assert DescriptorUtils.isEnumClassObject(owner) : "Enum entries should be put into class object of enum only: " + owner;
148 //TODO: this is a hack to indicate that this enum entry is an object
149 // class descriptor for enum entries is not used by backends so for now this should be safe to use
150 ClassDescriptorImpl dummyClassDescriptorForEnumEntryObject =
151 new ClassDescriptorImpl(owner, Collections.<AnnotationDescriptor>emptyList(), Modality.FINAL, propertyName);
152 dummyClassDescriptorForEnumEntryObject.initialize(
153 true,
154 Collections.<TypeParameterDescriptor>emptyList(),
155 Collections.<JetType>emptyList(), JetScope.EMPTY,
156 Collections.<ConstructorDescriptor>emptySet(), null,
157 false);
158 return new JavaPropertyDescriptorForObject(owner, annotations, visibility, propertyName, dummyClassDescriptorForEnumEntryObject);
159 }
160
161 return new JavaPropertyDescriptor(owner, annotations, visibility, isVar, propertyName);
162 }
163
164 @NotNull
165 private JetType getPropertyType(@NotNull JavaField field, @NotNull TypeVariableResolver typeVariableResolver) {
166 JetType propertyType = typeTransformer.transformToType(field.getType(), typeVariableResolver);
167
168 if (annotationResolver.hasNotNullAnnotation(field) || isStaticFinalField(field) /* TODO: WTF? */) {
169 return TypeUtils.makeNotNullable(propertyType);
170 }
171
172 return propertyType;
173 }
174
175 @NotNull
176 private static Set<PropertyDescriptor> getPropertiesFromSupertypes(@NotNull Name name, @NotNull ClassDescriptor descriptor) {
177 Set<PropertyDescriptor> result = new HashSet<PropertyDescriptor>();
178 for (JetType supertype : descriptor.getTypeConstructor().getSupertypes()) {
179 for (VariableDescriptor property : supertype.getMemberScope().getProperties(name)) {
180 result.add((PropertyDescriptor) property);
181 }
182 }
183
184 return result;
185 }
186
187 private static boolean isStaticFinalField(@NotNull JavaField field) {
188 return field.isFinal() && field.isStatic();
189 }
190 }