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.annotations.Nullable;
021    import org.jetbrains.jet.lang.descriptors.*;
022    import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorParent;
023    import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
024    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
025    import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode;
026    import org.jetbrains.jet.lang.resolve.java.descriptor.JavaMethodDescriptor;
027    import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor;
028    import org.jetbrains.jet.lang.resolve.java.scope.NamedMembers;
029    import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod;
030    import org.jetbrains.jet.lang.resolve.java.structure.JavaType;
031    import org.jetbrains.jet.lang.resolve.name.Name;
032    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
033    import org.jetbrains.jet.lang.types.JetType;
034    import org.jetbrains.jet.lang.types.TypeUtils;
035    
036    import javax.inject.Inject;
037    import java.util.*;
038    
039    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
040    import static org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils.resolveOverrides;
041    import static org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils.*;
042    
043    public final class JavaFunctionResolver {
044        private JavaTypeTransformer typeTransformer;
045        private JavaResolverCache cache;
046        private JavaTypeParameterResolver typeParameterResolver;
047        private JavaValueParameterResolver valueParameterResolver;
048        private JavaAnnotationResolver annotationResolver;
049        private ExternalSignatureResolver externalSignatureResolver;
050        private FakeOverrideVisibilityResolver fakeOverrideVisibilityResolver;
051        private MethodSignatureChecker signatureChecker;
052    
053        @Inject
054        public void setTypeTransformer(JavaTypeTransformer typeTransformer) {
055            this.typeTransformer = typeTransformer;
056        }
057    
058        @Inject
059        public void setCache(JavaResolverCache cache) {
060            this.cache = cache;
061        }
062    
063        @Inject
064        public void setTypeParameterResolver(JavaTypeParameterResolver typeParameterResolver) {
065            this.typeParameterResolver = typeParameterResolver;
066        }
067    
068        @Inject
069        public void setValueParameterResolver(JavaValueParameterResolver valueParameterResolver) {
070            this.valueParameterResolver = valueParameterResolver;
071        }
072    
073        @Inject
074        public void setAnnotationResolver(JavaAnnotationResolver annotationResolver) {
075            this.annotationResolver = annotationResolver;
076        }
077    
078        @Inject
079        public void setExternalSignatureResolver(ExternalSignatureResolver externalSignatureResolver) {
080            this.externalSignatureResolver = externalSignatureResolver;
081        }
082    
083        @Inject
084        public void setFakeOverrideVisibilityResolver(FakeOverrideVisibilityResolver fakeOverrideVisibilityResolver) {
085            this.fakeOverrideVisibilityResolver = fakeOverrideVisibilityResolver;
086        }
087    
088        @Inject
089        public void setSignatureChecker(MethodSignatureChecker signatureChecker) {
090            this.signatureChecker = signatureChecker;
091        }
092    
093        @Nullable
094        SimpleFunctionDescriptor resolveFunctionMutely(@NotNull JavaMethod method, @NotNull ClassOrNamespaceDescriptor owner) {
095            return resolveMethodToFunctionDescriptor(method, owner, false);
096        }
097    
098        @Nullable
099        private SimpleFunctionDescriptor resolveMethodToFunctionDescriptor(
100                @NotNull JavaMethod method,
101                @NotNull ClassOrNamespaceDescriptor ownerDescriptor,
102                boolean record
103        ) {
104            if (!DescriptorResolverUtils.isCorrectOwnerForEnumMember(ownerDescriptor, method)) {
105                return null;
106            }
107    
108            JavaType returnJavaType = method.getReturnType();
109            if (returnJavaType == null) {
110                // This means that the method is a constructor
111                return null;
112            }
113    
114            SimpleFunctionDescriptor alreadyResolved = cache.getMethod(method);
115            if (alreadyResolved != null) {
116                return alreadyResolved;
117            }
118    
119            SimpleFunctionDescriptorImpl functionDescriptorImpl = new JavaMethodDescriptor(
120                    ownerDescriptor,
121                    annotationResolver.resolveAnnotations(method),
122                    method.getName()
123            );
124    
125            JavaTypeParameterResolver.Initializer typeParameterInitializer = typeParameterResolver.resolveTypeParameters(functionDescriptorImpl, method);
126            typeParameterInitializer.initialize();
127            List<TypeParameterDescriptor> methodTypeParameters = typeParameterInitializer.getDescriptors();
128    
129            TypeVariableResolver typeVariableResolver = new TypeVariableResolverImpl(methodTypeParameters, functionDescriptorImpl);
130    
131            List<ValueParameterDescriptor> valueParameters =
132                    valueParameterResolver.resolveValueParameters(functionDescriptorImpl, method, typeVariableResolver);
133            JetType returnType = makeReturnType(returnJavaType, method, typeVariableResolver);
134    
135    
136            List<String> signatureErrors;
137            List<FunctionDescriptor> superFunctions;
138            ExternalSignatureResolver.AlternativeMethodSignature effectiveSignature;
139    
140            if (ownerDescriptor instanceof NamespaceDescriptor) {
141                superFunctions = Collections.emptyList();
142                effectiveSignature = externalSignatureResolver
143                        .resolveAlternativeMethodSignature(method, false, returnType, null, valueParameters, methodTypeParameters);
144                signatureErrors = effectiveSignature.getErrors();
145            }
146            else if (ownerDescriptor instanceof ClassDescriptor) {
147                ExternalSignatureResolver.PropagatedMethodSignature propagated = externalSignatureResolver
148                        .resolvePropagatedSignature(method, (ClassDescriptor) ownerDescriptor, returnType, null, valueParameters,
149                                                    methodTypeParameters);
150    
151                superFunctions = propagated.getSuperMethods();
152    
153                effectiveSignature = externalSignatureResolver
154                        .resolveAlternativeMethodSignature(method, !superFunctions.isEmpty(), propagated.getReturnType(),
155                                                           propagated.getReceiverType(), propagated.getValueParameters(),
156                                                           propagated.getTypeParameters());
157    
158                signatureErrors = new ArrayList<String>(propagated.getErrors());
159                signatureErrors.addAll(effectiveSignature.getErrors());
160            }
161            else {
162                throw new IllegalStateException("Unknown class or namespace descriptor: " + ownerDescriptor);
163            }
164    
165            functionDescriptorImpl.initialize(
166                    effectiveSignature.getReceiverType(),
167                    DescriptorUtils.getExpectedThisObjectIfNeeded(ownerDescriptor),
168                    effectiveSignature.getTypeParameters(),
169                    effectiveSignature.getValueParameters(),
170                    effectiveSignature.getReturnType(),
171                    Modality.convertFromFlags(method.isAbstract(), !method.isFinal()),
172                    method.getVisibility(),
173                    /*isInline = */ false
174            );
175    
176            if (record) {
177                cache.recordMethod(method, functionDescriptorImpl);
178            }
179    
180            signatureChecker.checkSignature(method, record, functionDescriptorImpl, signatureErrors, superFunctions);
181    
182            return functionDescriptorImpl;
183        }
184    
185        @NotNull
186        public Set<FunctionDescriptor> resolveFunctionGroupForClass(@NotNull NamedMembers members, @NotNull ClassOrNamespaceDescriptor owner) {
187            Name methodName = members.getName();
188    
189            Set<SimpleFunctionDescriptor> functionsFromCurrent = new HashSet<SimpleFunctionDescriptor>();
190            for (JavaMethod method : members.getMethods()) {
191                SimpleFunctionDescriptor function = resolveMethodToFunctionDescriptor(method, owner, true);
192                if (function != null) {
193                    functionsFromCurrent.add(function);
194                    SimpleFunctionDescriptor samAdapter = resolveSamAdapter(function);
195                    if (samAdapter != null) {
196                        functionsFromCurrent.add(samAdapter);
197                    }
198                }
199            }
200    
201            if (owner instanceof NamespaceDescriptor) {
202                SamConstructorDescriptor samConstructor = resolveSamConstructor((NamespaceDescriptor) owner, members);
203                if (samConstructor != null) {
204                    functionsFromCurrent.add(samConstructor);
205                }
206            }
207    
208            Set<FunctionDescriptor> functions = new HashSet<FunctionDescriptor>();
209            if (owner instanceof ClassDescriptor) {
210                ClassDescriptor classDescriptor = (ClassDescriptor) owner;
211    
212                Collection<SimpleFunctionDescriptor> functionsFromSupertypes = getFunctionsFromSupertypes(methodName, classDescriptor);
213    
214                functions.addAll(resolveOverrides(methodName, functionsFromSupertypes, functionsFromCurrent, classDescriptor,
215                                                  fakeOverrideVisibilityResolver));
216            }
217    
218            if (isEnumClassObject(owner)) {
219                for (FunctionDescriptor functionDescriptor : functionsFromCurrent) {
220                    if (!(isEnumValueOfMethod(functionDescriptor) || isEnumValuesMethod(functionDescriptor))) {
221                        functions.add(functionDescriptor);
222                    }
223                }
224            }
225            else {
226                functions.addAll(functionsFromCurrent);
227            }
228    
229            return functions;
230        }
231    
232        @Nullable
233        private static ClassDescriptorFromJvmBytecode findClassInScope(@NotNull JetScope memberScope, @NotNull Name name) {
234            ClassifierDescriptor classifier = memberScope.getClassifier(name);
235            if (classifier instanceof ClassDescriptorFromJvmBytecode) {
236                return (ClassDescriptorFromJvmBytecode) classifier;
237            }
238            return null;
239        }
240    
241        // E.g. we have foo.Bar.Baz class declared in Java. It will produce the following descriptors structure:
242        // namespace foo
243        // +-- class Bar
244        // |    +-- class Baz
245        // +-- namespace Bar
246        // We need to find class 'Baz' in namespace 'foo.Bar'.
247        @Nullable
248        private static ClassDescriptorFromJvmBytecode findClassInNamespace(@NotNull NamespaceDescriptor namespace, @NotNull Name name) {
249            // First, try to find in namespace directly
250            ClassDescriptorFromJvmBytecode found = findClassInScope(namespace.getMemberScope(), name);
251            if (found != null) {
252                return found;
253            }
254    
255            // If unsuccessful, try to find class of the same name as current (class 'foo.Bar')
256            NamespaceDescriptorParent parent = namespace.getContainingDeclaration();
257            if (parent instanceof NamespaceDescriptor) {
258                // Calling recursively, looking for 'Bar' in 'foo'
259                ClassDescriptor classForCurrentNamespace = findClassInNamespace((NamespaceDescriptor) parent, namespace.getName());
260                if (classForCurrentNamespace == null) {
261                    return null;
262                }
263    
264                // Try to find nested class 'Baz' in class 'foo.Bar'
265                return findClassInScope(DescriptorUtils.getStaticNestedClassesScope(classForCurrentNamespace), name);
266            }
267            return null;
268        }
269    
270        @Nullable
271        public static SamConstructorDescriptor resolveSamConstructor(@NotNull NamespaceDescriptor owner, @NotNull NamedMembers namedMembers) {
272            if (namedMembers.getSamInterface() != null) {
273                ClassDescriptorFromJvmBytecode klass = findClassInNamespace(owner, namedMembers.getName());
274                if (klass != null) {
275                    return createSamConstructorFunction(owner, klass);
276                }
277            }
278            return null;
279        }
280    
281        @Nullable
282        private static SimpleFunctionDescriptor resolveSamAdapter(@NotNull SimpleFunctionDescriptor original) {
283            return isSamAdapterNecessary(original) ? (SimpleFunctionDescriptor) createSamAdapterFunction(original) : null;
284        }
285    
286        @NotNull
287        private JetType makeReturnType(
288                @NotNull JavaType returnType,
289                @NotNull JavaMethod method,
290                @NotNull TypeVariableResolver typeVariableResolver
291        ) {
292            TypeUsage typeUsage = annotationResolver.hasReadonlyAnnotation(method) && !annotationResolver.hasMutableAnnotation(method)
293                                  ? TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT
294                                  : TypeUsage.MEMBER_SIGNATURE_COVARIANT;
295            JetType transformedType = typeTransformer.transformToType(returnType, typeUsage, typeVariableResolver);
296    
297            if (annotationResolver.hasNotNullAnnotation(method)) {
298                return TypeUtils.makeNotNullable(transformedType);
299            }
300            else {
301                return transformedType;
302            }
303        }
304    
305        @NotNull
306        private static Set<SimpleFunctionDescriptor> getFunctionsFromSupertypes(@NotNull Name name, @NotNull ClassDescriptor descriptor) {
307            Set<SimpleFunctionDescriptor> result = new LinkedHashSet<SimpleFunctionDescriptor>();
308            for (JetType supertype : descriptor.getTypeConstructor().getSupertypes()) {
309                for (FunctionDescriptor function : supertype.getMemberScope().getFunctions(name)) {
310                    result.add((SimpleFunctionDescriptor) function);
311                }
312            }
313            return result;
314        }
315    }