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.JavaClassDescriptor;
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 ErrorReporter errorReporter;
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 setErrorReporter(ErrorReporter errorReporter) {
085            this.errorReporter = errorReporter;
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.isCorrectOwnerForEnumMethod(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                    /*TODO what if user annotate it with inline?*/
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, errorReporter));
215            }
216    
217            if (isEnumClassObject(owner)) {
218                for (FunctionDescriptor functionDescriptor : functionsFromCurrent) {
219                    if (!(isEnumValueOfMethod(functionDescriptor) || isEnumValuesMethod(functionDescriptor))) {
220                        functions.add(functionDescriptor);
221                    }
222                }
223            }
224            else {
225                functions.addAll(functionsFromCurrent);
226            }
227    
228            return functions;
229        }
230    
231        @Nullable
232        private static JavaClassDescriptor findClassInScope(@NotNull JetScope memberScope, @NotNull Name name) {
233            ClassifierDescriptor classifier = memberScope.getClassifier(name);
234            if (classifier instanceof JavaClassDescriptor) {
235                return (JavaClassDescriptor) classifier;
236            }
237            return null;
238        }
239    
240        // E.g. we have foo.Bar.Baz class declared in Java. It will produce the following descriptors structure:
241        // namespace foo
242        // +-- class Bar
243        // |    +-- class Baz
244        // +-- namespace Bar
245        // We need to find class 'Baz' in namespace 'foo.Bar'.
246        @Nullable
247        private static JavaClassDescriptor findClassInNamespace(@NotNull NamespaceDescriptor namespace, @NotNull Name name) {
248            // First, try to find in namespace directly
249            JavaClassDescriptor found = findClassInScope(namespace.getMemberScope(), name);
250            if (found != null) {
251                return found;
252            }
253    
254            // If unsuccessful, try to find class of the same name as current (class 'foo.Bar')
255            NamespaceDescriptorParent parent = namespace.getContainingDeclaration();
256            if (parent instanceof NamespaceDescriptor) {
257                // Calling recursively, looking for 'Bar' in 'foo'
258                ClassDescriptor classForCurrentNamespace = findClassInNamespace((NamespaceDescriptor) parent, namespace.getName());
259                if (classForCurrentNamespace == null) {
260                    return null;
261                }
262    
263                // Try to find nested class 'Baz' in class 'foo.Bar'
264                return findClassInScope(DescriptorUtils.getStaticNestedClassesScope(classForCurrentNamespace), name);
265            }
266            return null;
267        }
268    
269        @Nullable
270        public static SamConstructorDescriptor resolveSamConstructor(@NotNull NamespaceDescriptor owner, @NotNull NamedMembers namedMembers) {
271            if (namedMembers.getSamInterface() != null) {
272                JavaClassDescriptor klass = findClassInNamespace(owner, namedMembers.getName());
273                if (klass != null) {
274                    return createSamConstructorFunction(owner, klass);
275                }
276            }
277            return null;
278        }
279    
280        @Nullable
281        private static SimpleFunctionDescriptor resolveSamAdapter(@NotNull SimpleFunctionDescriptor original) {
282            return isSamAdapterNecessary(original) ? (SimpleFunctionDescriptor) createSamAdapterFunction(original) : null;
283        }
284    
285        @NotNull
286        private JetType makeReturnType(
287                @NotNull JavaType returnType,
288                @NotNull JavaMethod method,
289                @NotNull TypeVariableResolver typeVariableResolver
290        ) {
291            TypeUsage typeUsage = annotationResolver.hasReadonlyAnnotation(method) && !annotationResolver.hasMutableAnnotation(method)
292                                  ? TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT
293                                  : TypeUsage.MEMBER_SIGNATURE_COVARIANT;
294            JetType transformedType = typeTransformer.transformToType(returnType, typeUsage, typeVariableResolver);
295    
296            if (annotationResolver.hasNotNullAnnotation(method)) {
297                return TypeUtils.makeNotNullable(transformedType);
298            }
299            else {
300                return transformedType;
301            }
302        }
303    
304        @NotNull
305        private static Set<SimpleFunctionDescriptor> getFunctionsFromSupertypes(@NotNull Name name, @NotNull ClassDescriptor descriptor) {
306            Set<SimpleFunctionDescriptor> result = new LinkedHashSet<SimpleFunctionDescriptor>();
307            for (JetType supertype : descriptor.getTypeConstructor().getSupertypes()) {
308                for (FunctionDescriptor function : supertype.getMemberScope().getFunctions(name)) {
309                    result.add((SimpleFunctionDescriptor) function);
310                }
311            }
312            return result;
313        }
314    }