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.impl.PropertyDescriptorImpl;
022 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
023 import org.jetbrains.jet.lang.resolve.java.descriptor.JavaPropertyDescriptor;
024 import org.jetbrains.jet.lang.resolve.java.scope.NamedMembers;
025 import org.jetbrains.jet.lang.resolve.java.structure.JavaField;
026 import org.jetbrains.jet.lang.resolve.name.Name;
027 import org.jetbrains.jet.lang.types.JetType;
028 import org.jetbrains.jet.lang.types.TypeUtils;
029
030 import javax.inject.Inject;
031 import java.util.*;
032
033 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClass;
034 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClassObject;
035 import static org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils.resolveOverrides;
036
037 public final class JavaPropertyResolver {
038 private JavaTypeTransformer typeTransformer;
039 private JavaResolverCache cache;
040 private JavaAnnotationResolver annotationResolver;
041 private ExternalSignatureResolver externalSignatureResolver;
042 private ErrorReporter errorReporter;
043
044 @Inject
045 public void setTypeTransformer(@NotNull JavaTypeTransformer javaTypeTransformer) {
046 this.typeTransformer = javaTypeTransformer;
047 }
048
049 @Inject
050 public void setCache(JavaResolverCache cache) {
051 this.cache = cache;
052 }
053
054 @Inject
055 public void setAnnotationResolver(JavaAnnotationResolver annotationResolver) {
056 this.annotationResolver = annotationResolver;
057 }
058
059 @Inject
060 public void setExternalSignatureResolver(ExternalSignatureResolver externalSignatureResolver) {
061 this.externalSignatureResolver = externalSignatureResolver;
062 }
063
064 @Inject
065 public void setErrorReporter(ErrorReporter errorReporter) {
066 this.errorReporter = errorReporter;
067 }
068
069 @NotNull
070 public Set<VariableDescriptor> resolveFieldGroup(@NotNull NamedMembers members, @NotNull ClassOrNamespaceDescriptor owner) {
071 if (isEnumClassObject(owner)) {
072 return Collections.emptySet();
073 }
074
075 Name propertyName = members.getName();
076
077 List<JavaField> fields = members.getFields();
078
079 Set<PropertyDescriptor> propertiesFromCurrent = new HashSet<PropertyDescriptor>(1);
080 assert fields.size() <= 1;
081 if (fields.size() == 1) {
082 JavaField field = fields.iterator().next();
083 if (!field.isEnumEntry()) {
084 propertiesFromCurrent.add(resolveProperty(owner, propertyName, field));
085 }
086 }
087
088 Set<PropertyDescriptor> properties = new HashSet<PropertyDescriptor>();
089 if (owner instanceof ClassDescriptor) {
090 ClassDescriptor classDescriptor = (ClassDescriptor) owner;
091
092 Collection<PropertyDescriptor> propertiesFromSupertypes = getPropertiesFromSupertypes(propertyName, classDescriptor);
093
094 properties.addAll(resolveOverrides(propertyName, propertiesFromSupertypes, propertiesFromCurrent, classDescriptor,
095 errorReporter));
096 }
097
098 properties.addAll(propertiesFromCurrent);
099
100 return new HashSet<VariableDescriptor>(properties);
101 }
102
103 @NotNull
104 private PropertyDescriptor resolveProperty(@NotNull ClassOrNamespaceDescriptor owner, @NotNull Name name, @NotNull JavaField field) {
105 assert !field.isEnumEntry() : "Enum entries are resolved into classes, not into properties: " + name;
106
107 boolean isVar = !field.isFinal();
108
109 PropertyDescriptorImpl propertyDescriptor =
110 new JavaPropertyDescriptor(owner, annotationResolver.resolveAnnotations(field), field.getVisibility(), isVar, name);
111 propertyDescriptor.initialize(null, null);
112
113 TypeVariableResolver typeVariableResolver =
114 new TypeVariableResolverImpl(Collections.<TypeParameterDescriptor>emptyList(), propertyDescriptor);
115
116 JetType propertyType = getPropertyType(field, typeVariableResolver);
117
118 ExternalSignatureResolver.AlternativeFieldSignature effectiveSignature =
119 externalSignatureResolver.resolveAlternativeFieldSignature(field, propertyType, isVar);
120 List<String> signatureErrors = effectiveSignature.getErrors();
121 if (!signatureErrors.isEmpty()) {
122 externalSignatureResolver.reportSignatureErrors(propertyDescriptor, signatureErrors);
123 }
124
125 propertyDescriptor.setType(
126 effectiveSignature.getReturnType(),
127 Collections.<TypeParameterDescriptor>emptyList(),
128 DescriptorUtils.getExpectedThisObjectIfNeeded(owner),
129 (JetType) null
130 );
131
132 cache.recordField(field, propertyDescriptor);
133
134 return propertyDescriptor;
135 }
136
137 @NotNull
138 private JetType getPropertyType(@NotNull JavaField field, @NotNull TypeVariableResolver typeVariableResolver) {
139 JetType propertyType = typeTransformer.transformToType(field.getType(), typeVariableResolver);
140
141 if (annotationResolver.hasNotNullAnnotation(field) || isStaticFinalField(field) /* TODO: WTF? */) {
142 return TypeUtils.makeNotNullable(propertyType);
143 }
144
145 return propertyType;
146 }
147
148 @NotNull
149 private static Set<PropertyDescriptor> getPropertiesFromSupertypes(@NotNull Name name, @NotNull ClassDescriptor descriptor) {
150 Set<PropertyDescriptor> result = new HashSet<PropertyDescriptor>();
151 for (JetType supertype : descriptor.getTypeConstructor().getSupertypes()) {
152 for (VariableDescriptor property : supertype.getMemberScope().getProperties(name)) {
153 result.add((PropertyDescriptor) property);
154 }
155 }
156
157 return result;
158 }
159
160 private static boolean isStaticFinalField(@NotNull JavaField field) {
161 return field.isFinal() && field.isStatic();
162 }
163 }