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