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 017package org.jetbrains.jet.lang.resolve.java.resolver; 018 019import com.google.common.collect.Sets; 020import com.intellij.psi.PsiEnumConstant; 021import org.jetbrains.annotations.NotNull; 022import org.jetbrains.annotations.Nullable; 023import org.jetbrains.jet.lang.descriptors.*; 024import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 025import org.jetbrains.jet.lang.descriptors.impl.*; 026import org.jetbrains.jet.lang.resolve.BindingContext; 027import org.jetbrains.jet.lang.resolve.BindingTrace; 028import org.jetbrains.jet.lang.resolve.DescriptorUtils; 029import org.jetbrains.jet.lang.resolve.OverrideResolver; 030import org.jetbrains.jet.lang.resolve.java.*; 031import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeFieldSignatureData; 032import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils; 033import org.jetbrains.jet.lang.resolve.java.kt.JetMethodAnnotation; 034import org.jetbrains.jet.lang.resolve.java.provider.NamedMembers; 035import org.jetbrains.jet.lang.resolve.java.provider.PsiDeclarationProvider; 036import org.jetbrains.jet.lang.resolve.java.wrapper.*; 037import org.jetbrains.jet.lang.resolve.name.Name; 038import org.jetbrains.jet.lang.resolve.scopes.JetScope; 039import org.jetbrains.jet.lang.types.JetType; 040import org.jetbrains.jet.lang.types.TypeUtils; 041 042import javax.inject.Inject; 043import java.util.*; 044 045import static org.jetbrains.jet.lang.resolve.java.provider.DeclarationOrigin.JAVA; 046 047public 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}