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.google.common.collect.Sets;
020 import com.intellij.psi.PsiEnumConstant;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.*;
024 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025 import org.jetbrains.jet.lang.descriptors.impl.*;
026 import org.jetbrains.jet.lang.resolve.BindingContext;
027 import org.jetbrains.jet.lang.resolve.BindingTrace;
028 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
029 import org.jetbrains.jet.lang.resolve.OverrideResolver;
030 import org.jetbrains.jet.lang.resolve.java.*;
031 import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeFieldSignatureData;
032 import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils;
033 import org.jetbrains.jet.lang.resolve.java.kt.JetMethodAnnotation;
034 import org.jetbrains.jet.lang.resolve.java.provider.NamedMembers;
035 import org.jetbrains.jet.lang.resolve.java.provider.PsiDeclarationProvider;
036 import org.jetbrains.jet.lang.resolve.java.wrapper.*;
037 import org.jetbrains.jet.lang.resolve.name.Name;
038 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
039 import org.jetbrains.jet.lang.types.JetType;
040 import org.jetbrains.jet.lang.types.TypeUtils;
041
042 import javax.inject.Inject;
043 import java.util.*;
044
045 import static org.jetbrains.jet.lang.resolve.java.provider.DeclarationOrigin.JAVA;
046
047 public final class JavaPropertyResolver {
048
049 private JavaSemanticServices semanticServices;
050 private JavaSignatureResolver javaSignatureResolver;
051 private BindingTrace trace;
052 private JavaAnnotationResolver annotationResolver;
053
054 public JavaPropertyResolver() {
055 }
056
057 @Inject
058 public void setSemanticServices(JavaSemanticServices semanticServices) {
059 this.semanticServices = semanticServices;
060 }
061
062 @Inject
063 public void setTrace(BindingTrace trace) {
064 this.trace = trace;
065 }
066
067 @Inject
068 public void setJavaSignatureResolver(JavaSignatureResolver javaSignatureResolver) {
069 this.javaSignatureResolver = javaSignatureResolver;
070 }
071
072 @Inject
073 public void setAnnotationResolver(JavaAnnotationResolver annotationResolver) {
074 this.annotationResolver = annotationResolver;
075 }
076
077 @NotNull
078 public Set<VariableDescriptor> resolveFieldGroupByName(
079 @NotNull Name fieldName,
080 @NotNull PsiDeclarationProvider scopeData,
081 @NotNull ClassOrNamespaceDescriptor ownerDescriptor
082 ) {
083 NamedMembers namedMembers = scopeData.getMembersCache().get(fieldName);
084 if (namedMembers == null) {
085 return Collections.emptySet();
086 }
087
088 return resolveNamedGroupProperties(ownerDescriptor, scopeData, namedMembers, fieldName,
089 "class or namespace " + DescriptorUtils.getFQName(ownerDescriptor));
090 }
091
092 @NotNull
093 private Set<VariableDescriptor> resolveNamedGroupProperties(
094 @NotNull ClassOrNamespaceDescriptor ownerDescriptor,
095 @NotNull PsiDeclarationProvider scopeData,
096 @NotNull NamedMembers namedMembers,
097 @NotNull Name propertyName,
098 @NotNull String context
099 ) {
100 Collection<PropertyPsiData> psiDataCollection = PropertyPsiData.assemblePropertyPsiDataFromElements(
101 namedMembers.getPropertyPsiDataElements());
102
103 Set<PropertyDescriptor> propertiesFromCurrent = new HashSet<PropertyDescriptor>(1);
104
105 int regularPropertiesCount = getNumberOfNonExtensionProperties(psiDataCollection);
106
107 for (PropertyPsiData propertyPsiData : psiDataCollection) {
108
109 // we cannot have more then one property with given name even if java code
110 // has several fields, getters and setter of different types
111 if (!propertyPsiData.isExtension() && regularPropertiesCount > 1) {
112 continue;
113 }
114
115 if (!DescriptorResolverUtils.isCorrectOwnerForEnumMember(ownerDescriptor, propertyPsiData.getCharacteristicPsi())) {
116 continue;
117 }
118
119 propertiesFromCurrent.add(resolveProperty(ownerDescriptor, scopeData, propertyName, context, propertyPsiData));
120 }
121
122 Set<PropertyDescriptor> propertiesFromSupertypes = getPropertiesFromSupertypes(propertyName, ownerDescriptor);
123 Set<PropertyDescriptor> properties = Sets.newHashSet();
124
125 generateOverrides(ownerDescriptor, propertyName, propertiesFromCurrent, propertiesFromSupertypes, properties);
126 OverrideResolver.resolveUnknownVisibilities(properties, trace);
127
128 properties.addAll(propertiesFromCurrent);
129
130 return Sets.<VariableDescriptor>newHashSet(properties);
131 }
132
133 private static void generateOverrides(
134 @NotNull ClassOrNamespaceDescriptor owner,
135 @NotNull Name propertyName,
136 @NotNull Set<PropertyDescriptor> propertiesFromCurrent,
137 @NotNull Set<PropertyDescriptor> propertiesFromSupertypes,
138 @NotNull final Set<PropertyDescriptor> properties
139 ) {
140 if (!(owner instanceof ClassDescriptor)) {
141 return;
142 }
143 ClassDescriptor classDescriptor = (ClassDescriptor) owner;
144
145 OverrideResolver.generateOverridesInFunctionGroup(
146 propertyName, propertiesFromSupertypes, propertiesFromCurrent, classDescriptor,
147 new OverrideResolver.DescriptorSink() {
148 @Override
149 public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) {
150 properties.add((PropertyDescriptor) fakeOverride);
151 }
152
153 @Override
154 public void conflict(
155 @NotNull CallableMemberDescriptor fromSuper,
156 @NotNull CallableMemberDescriptor fromCurrent
157 ) {
158 // nop
159 }
160 });
161 }
162
163 @NotNull
164 private PropertyDescriptor resolveProperty(
165 @NotNull ClassOrNamespaceDescriptor owner,
166 @NotNull PsiDeclarationProvider scopeData,
167 @NotNull Name propertyName,
168 @NotNull String context,
169 @NotNull PropertyPsiData psiData
170 ) {
171 boolean isFinal = isPropertyFinal(scopeData, psiData);
172 boolean isVar = psiData.isVar();
173
174 PropertyPsiDataElement characteristicMember = psiData.getCharacteristicMember();
175
176 Visibility visibility = DescriptorResolverUtils.resolveVisibility(psiData.getCharacteristicPsi(), null);
177 CallableMemberDescriptor.Kind kind = CallableMemberDescriptor.Kind.DECLARATION;
178
179 PropertyPsiDataElement getter = psiData.getGetter();
180 if (getter != null) {
181 JetMethodAnnotation methodAnnotation = ((PsiMethodWrapper) getter.getMember()).getJetMethodAnnotation();
182 visibility = DescriptorResolverUtils.resolveVisibility(psiData.getCharacteristicPsi(), methodAnnotation);
183 kind = DescriptorKindUtils.flagsToKind(methodAnnotation.kind());
184 }
185
186 boolean isEnumEntry = psiData.getCharacteristicPsi() instanceof PsiEnumConstant;
187 PropertyDescriptorImpl propertyDescriptor = new PropertyDescriptorImpl(
188 owner,
189 annotationResolver.resolveAnnotations(psiData.getCharacteristicPsi()),
190 DescriptorResolverUtils.resolveModality(characteristicMember.getMember(),
191 isFinal || isEnumEntry || psiData.isPropertyForNamedObject()),
192 visibility,
193 isVar,
194 propertyName,
195 kind);
196
197 //TODO: this is a hack to indicate that this enum entry is an object
198 // class descriptor for enum entries is not used by backends so for now this should be safe to use
199 // remove this when JavaDescriptorResolver gets rewritten
200 if (isEnumEntry) {
201 assert DescriptorUtils.isEnumClassObject(owner) : "Enum entries should be put into class object of enum only: " + owner;
202 ClassDescriptorImpl dummyClassDescriptorForEnumEntryObject =
203 new ClassDescriptorImpl(owner, Collections.<AnnotationDescriptor>emptyList(), Modality.FINAL, propertyName);
204 dummyClassDescriptorForEnumEntryObject.initialize(
205 true,
206 Collections.<TypeParameterDescriptor>emptyList(),
207 Collections.<JetType>emptyList(), JetScope.EMPTY,
208 Collections.<ConstructorDescriptor>emptySet(), null,
209 false);
210 trace.record(BindingContext.OBJECT_DECLARATION_CLASS, propertyDescriptor, dummyClassDescriptorForEnumEntryObject);
211 }
212
213 PropertyGetterDescriptorImpl getterDescriptor = resolveGetter(visibility, kind, getter, propertyDescriptor);
214 PropertySetterDescriptorImpl setterDescriptor = resolveSetter(psiData, kind, propertyDescriptor);
215
216 propertyDescriptor.initialize(getterDescriptor, setterDescriptor);
217
218 List<TypeParameterDescriptor> typeParameters = resolvePropertyTypeParameters(psiData, characteristicMember, propertyDescriptor);
219
220 TypeVariableResolver typeVariableResolverForPropertyInternals = TypeVariableResolvers.typeVariableResolverFromTypeParameters(
221 typeParameters, propertyDescriptor, "property " + propertyName + " in " + context);
222
223 JetType propertyType = getPropertyType(psiData, characteristicMember, typeVariableResolverForPropertyInternals);
224 JetType receiverType = getReceiverType(characteristicMember, typeVariableResolverForPropertyInternals);
225
226
227 propertyType = getAlternativeSignatureData(isVar, characteristicMember, propertyDescriptor, propertyType);
228
229 propertyDescriptor.setType(
230 propertyType,
231 typeParameters,
232 DescriptorUtils.getExpectedThisObjectIfNeeded(owner),
233 receiverType
234 );
235 initializeSetterAndGetter(propertyDescriptor, getterDescriptor, setterDescriptor, propertyType, psiData);
236
237 if (kind == CallableMemberDescriptor.Kind.DECLARATION) {
238 trace.record(BindingContext.VARIABLE, psiData.getCharacteristicPsi(), propertyDescriptor);
239 }
240
241 recordObjectDeclarationClassIfNeeded(psiData, owner, propertyDescriptor, propertyType);
242
243 if (scopeData.getDeclarationOrigin() == JAVA) {
244 trace.record(JavaBindingContext.IS_DECLARED_IN_JAVA, propertyDescriptor);
245 }
246 return propertyDescriptor;
247 }
248
249 @NotNull
250 private JetType getAlternativeSignatureData(
251 boolean isVar,
252 PropertyPsiDataElement characteristicMember,
253 PropertyDescriptor propertyDescriptor,
254 JetType propertyType
255 ) {
256 if (!characteristicMember.isField()) {
257 return propertyType;
258 }
259 AlternativeFieldSignatureData signatureData =
260 new AlternativeFieldSignatureData((PsiFieldWrapper) characteristicMember.getMember(), propertyType, isVar);
261 if (!signatureData.hasErrors()) {
262 if (signatureData.isAnnotated()) {
263 return signatureData.getReturnType();
264 }
265 }
266 else {
267 trace.record(JavaBindingContext.LOAD_FROM_JAVA_SIGNATURE_ERRORS, propertyDescriptor,
268 Collections.singletonList(signatureData.getError()));
269 }
270 return propertyType;
271 }
272
273 private static void initializeSetterAndGetter(
274 @NotNull PropertyDescriptor propertyDescriptor,
275 @Nullable PropertyGetterDescriptorImpl getterDescriptor,
276 @Nullable PropertySetterDescriptorImpl setterDescriptor,
277 @NotNull JetType propertyType,
278 @NotNull PropertyPsiData data
279 ) {
280 if (getterDescriptor != null) {
281 getterDescriptor.initialize(propertyType);
282 }
283 if (setterDescriptor != null) {
284 PropertyPsiDataElement setter = data.getSetter();
285 assert setter != null;
286 List<PsiParameterWrapper> parameters = ((PsiMethodWrapper) setter.getMember()).getParameters();
287 assert parameters.size() != 0;
288 int valueIndex = parameters.size() - 1;
289 PsiParameterWrapper valueParameter = parameters.get(valueIndex);
290 setterDescriptor.initialize(new ValueParameterDescriptorImpl(
291 setterDescriptor,
292 0,
293 Collections.<AnnotationDescriptor>emptyList(),
294 Name.identifierNoValidate(valueParameter.getJetValueParameter().name()),
295 propertyDescriptor.getType(),
296 false,
297 null));
298 }
299 }
300
301 private void recordObjectDeclarationClassIfNeeded(
302 PropertyPsiData psiData,
303 DeclarationDescriptor realOwner,
304 PropertyDescriptor propertyDescriptor,
305 JetType propertyType
306 ) {
307 if (!psiData.isPropertyForNamedObject()) {
308 return;
309 }
310 ClassDescriptor objectDescriptor = (ClassDescriptor) propertyType.getConstructor().getDeclarationDescriptor();
311
312 assert objectDescriptor != null;
313 assert objectDescriptor.getKind() == ClassKind.OBJECT;
314 assert objectDescriptor.getContainingDeclaration() == realOwner;
315
316 trace.record(BindingContext.OBJECT_DECLARATION_CLASS, propertyDescriptor, objectDescriptor);
317 }
318
319 @Nullable
320 private PropertyGetterDescriptorImpl resolveGetter(
321 Visibility visibility,
322 CallableMemberDescriptor.Kind kind,
323 PropertyPsiDataElement getter,
324 PropertyDescriptor propertyDescriptor
325 ) {
326 if (getter == null) {
327 return null;
328 }
329 return new PropertyGetterDescriptorImpl(
330 propertyDescriptor,
331 annotationResolver.resolveAnnotations(getter.getMember().getPsiMember()),
332 propertyDescriptor.getModality(),
333 visibility,
334 true,
335 false,
336 kind);
337 }
338
339 @Nullable
340 private PropertySetterDescriptorImpl resolveSetter(
341 PropertyPsiData psiData,
342 CallableMemberDescriptor.Kind kind,
343 PropertyDescriptor propertyDescriptor
344 ) {
345 PropertyPsiDataElement setter = psiData.getSetter();
346 if (setter == null) {
347 return null;
348 }
349 Visibility setterVisibility = DescriptorResolverUtils.resolveVisibility(setter.getMember().getPsiMember(), null);
350 if (setter.getMember() instanceof PsiMethodWrapper) {
351 setterVisibility = DescriptorResolverUtils.resolveVisibility(
352 setter.getMember().getPsiMember(),
353 ((PsiMethodWrapper) setter.getMember())
354 .getJetMethodAnnotation());
355 }
356 return new PropertySetterDescriptorImpl(
357 propertyDescriptor,
358 annotationResolver.resolveAnnotations(setter.getMember().getPsiMember()),
359 propertyDescriptor.getModality(),
360 setterVisibility,
361 true,
362 false,
363 kind);
364 }
365
366 private List<TypeParameterDescriptor> resolvePropertyTypeParameters(
367 @NotNull PropertyPsiData members,
368 @NotNull PropertyPsiDataElement characteristicMember,
369 @NotNull PropertyDescriptor propertyDescriptor
370 ) {
371 // TODO: Can't get type parameters from field - only from accessors
372 if (characteristicMember == members.getSetter() || characteristicMember == members.getGetter()) {
373 PsiMethodWrapper method = (PsiMethodWrapper) characteristicMember.getMember();
374 return javaSignatureResolver.resolveMethodTypeParameters(method, propertyDescriptor);
375 }
376
377 return Collections.emptyList();
378 }
379
380 @NotNull
381 private JetType getPropertyType(
382 PropertyPsiData members,
383 PropertyPsiDataElement characteristicMember,
384 TypeVariableResolver typeVariableResolverForPropertyInternals
385 ) {
386 if (!characteristicMember.getType().getTypeString().isEmpty()) {
387 return semanticServices.getTypeTransformer().transformToType(
388 characteristicMember.getType().getTypeString(), typeVariableResolverForPropertyInternals);
389 }
390 JetType propertyType = semanticServices.getTypeTransformer().transformToType(
391 characteristicMember.getType().getPsiType(), typeVariableResolverForPropertyInternals);
392
393 boolean hasNotNullAnnotation = JavaAnnotationResolver.findAnnotationWithExternal(
394 characteristicMember.getType().getPsiNotNullOwner(),
395 JvmAbi.JETBRAINS_NOT_NULL_ANNOTATION.getFqName().asString()) != null;
396
397 if (hasNotNullAnnotation || members.isStaticFinalField()) {
398 propertyType = TypeUtils.makeNotNullable(propertyType);
399 }
400 return propertyType;
401 }
402
403 @Nullable
404 private JetType getReceiverType(
405 PropertyPsiDataElement characteristicMember,
406 TypeVariableResolver typeVariableResolverForPropertyInternals
407 ) {
408 if (characteristicMember.getReceiverType() == null) {
409 return null;
410 }
411 if (!characteristicMember.getReceiverType().getTypeString().isEmpty()) {
412 return semanticServices.getTypeTransformer().transformToType(characteristicMember.getReceiverType().getTypeString(), typeVariableResolverForPropertyInternals);
413 }
414 return semanticServices.getTypeTransformer().transformToType(characteristicMember.getReceiverType().getPsiType(), typeVariableResolverForPropertyInternals);
415 }
416
417 private static int getNumberOfNonExtensionProperties(@NotNull Collection<PropertyPsiData> propertyPsiDataCollection) {
418 int regularPropertiesCount = 0;
419 for (PropertyPsiData members : propertyPsiDataCollection) {
420 if (!members.isExtension()) {
421 ++regularPropertiesCount;
422 }
423 }
424 return regularPropertiesCount;
425 }
426
427 private static boolean isPropertyFinal(PsiDeclarationProvider scopeData, PropertyPsiData psiData) {
428 if (scopeData.getDeclarationOrigin() == JAVA) {
429 return true;
430 }
431 return psiData.isFinal();
432 }
433
434 @NotNull
435 private static Set<PropertyDescriptor> getPropertiesFromSupertypes(
436 @NotNull Name propertyName, @NotNull ClassOrNamespaceDescriptor ownerDescriptor
437 ) {
438 Set<PropertyDescriptor> r = new HashSet<PropertyDescriptor>();
439 for (JetType supertype : DescriptorResolverUtils.getSupertypes(ownerDescriptor)) {
440 for (VariableDescriptor property : supertype.getMemberScope().getProperties(propertyName)) {
441 r.add((PropertyDescriptor) property);
442 }
443 }
444 return r;
445 }
446 }