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    }