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.Lists;
020    import com.google.common.collect.Sets;
021    import com.intellij.openapi.diagnostic.Logger;
022    import com.intellij.psi.PsiClass;
023    import com.intellij.psi.PsiMethod;
024    import com.intellij.psi.PsiType;
025    import com.intellij.psi.util.PsiFormatUtil;
026    import com.intellij.util.containers.ContainerUtil;
027    import org.jetbrains.annotations.NotNull;
028    import org.jetbrains.annotations.Nullable;
029    import org.jetbrains.jet.lang.descriptors.*;
030    import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorParent;
031    import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
032    import org.jetbrains.jet.lang.resolve.*;
033    import org.jetbrains.jet.lang.resolve.java.*;
034    import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode;
035    import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeMethodSignatureData;
036    import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesPropagationData;
037    import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils;
038    import org.jetbrains.jet.lang.resolve.java.provider.*;
039    import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
040    import org.jetbrains.jet.lang.resolve.name.Name;
041    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
042    import org.jetbrains.jet.lang.types.*;
043    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
044    
045    import javax.inject.Inject;
046    import java.util.Collections;
047    import java.util.HashSet;
048    import java.util.List;
049    import java.util.Set;
050    
051    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
052    import static org.jetbrains.jet.lang.resolve.OverridingUtil.*;
053    import static org.jetbrains.jet.lang.resolve.java.provider.DeclarationOrigin.JAVA;
054    import static org.jetbrains.jet.lang.resolve.java.provider.DeclarationOrigin.KOTLIN;
055    import static org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils.*;
056    
057    public final class JavaFunctionResolver {
058        private static final Logger LOG = Logger.getInstance(JavaFunctionResolver.class);
059    
060        private JavaTypeTransformer typeTransformer;
061        private BindingTrace trace;
062        private JavaSignatureResolver signatureResolver;
063        private JavaValueParameterResolver parameterResolver;
064        private JavaAnnotationResolver annotationResolver;
065    
066        public JavaFunctionResolver() {
067        }
068    
069        @Inject
070        public void setTypeTransformer(JavaTypeTransformer typeTransformer) {
071            this.typeTransformer = typeTransformer;
072        }
073    
074        @Inject
075        public void setTrace(BindingTrace trace) {
076            this.trace = trace;
077        }
078    
079        @Inject
080        public void setSignatureResolver(JavaSignatureResolver signatureResolver) {
081            this.signatureResolver = signatureResolver;
082        }
083    
084        @Inject
085        public void setParameterResolver(JavaValueParameterResolver parameterResolver) {
086            this.parameterResolver = parameterResolver;
087        }
088    
089        @Inject
090        public void setAnnotationResolver(JavaAnnotationResolver annotationResolver) {
091            this.annotationResolver = annotationResolver;
092        }
093    
094        @Nullable
095        SimpleFunctionDescriptor resolveFunctionMutely(
096                @NotNull PsiMethodWrapper method,
097                @NotNull ClassOrNamespaceDescriptor ownerDescriptor
098        ) {
099            PsiClass containingClass = method.getPsiMethod().getContainingClass();
100            assert containingClass != null : "containing class is null for " + method;
101            return resolveMethodToFunctionDescriptor(containingClass, method, DeclarationOrigin.JAVA, ownerDescriptor, false);
102        }
103    
104        @Nullable
105        private SimpleFunctionDescriptor resolveMethodToFunctionDescriptor(
106                @NotNull PsiClass psiClass, PsiMethodWrapper method,
107                @NotNull DeclarationOrigin declarationOrigin, @NotNull ClassOrNamespaceDescriptor ownerDescriptor, boolean record
108        ) {
109            if (!DescriptorResolverUtils.isCorrectOwnerForEnumMember(ownerDescriptor, method.getPsiMember())) {
110                return null;
111            }
112    
113            PsiType returnPsiType = method.getReturnType();
114            if (returnPsiType == null) {
115                return null;
116            }
117    
118            // TODO: ugly
119            if (method.getJetMethodAnnotation().hasPropertyFlag()) {
120                return null;
121            }
122    
123            PsiMethod psiMethod = method.getPsiMethod();
124            PsiClass containingClass = psiMethod.getContainingClass();
125            if (declarationOrigin == KOTLIN) {
126                // TODO: unless maybe class explicitly extends Object
127                assert containingClass != null;
128                String ownerClassName = containingClass.getQualifiedName();
129                if (DescriptorResolverUtils.OBJECT_FQ_NAME.asString().equals(ownerClassName)) {
130                    return null;
131                }
132            }
133    
134            if (trace.get(BindingContext.FUNCTION, psiMethod) != null) {
135                return trace.get(BindingContext.FUNCTION, psiMethod);
136            }
137    
138            SimpleFunctionDescriptorImpl functionDescriptorImpl = new SimpleFunctionDescriptorImpl(
139                    ownerDescriptor,
140                    annotationResolver.resolveAnnotations(psiMethod),
141                    Name.identifier(method.getName()),
142                    DescriptorKindUtils.flagsToKind(method.getJetMethodAnnotation().kind())
143            );
144    
145            String context = "method " + method.getName() + " in class " + psiClass.getQualifiedName();
146    
147            List<TypeParameterDescriptor> methodTypeParameters =
148                    signatureResolver.resolveMethodTypeParameters(method,
149                                                                  functionDescriptorImpl);
150    
151            TypeVariableResolver methodTypeVariableResolver = TypeVariableResolvers.typeVariableResolverFromTypeParameters(methodTypeParameters,
152                                                                                                                           functionDescriptorImpl,
153                                                                                                                           context);
154    
155            JavaDescriptorResolver.ValueParameterDescriptors valueParameterDescriptors = parameterResolver
156                    .resolveParameterDescriptors(functionDescriptorImpl, method.getParameters(), methodTypeVariableResolver);
157            JetType returnType = makeReturnType(returnPsiType, method, methodTypeVariableResolver);
158    
159            List<String> signatureErrors = Lists.newArrayList();
160    
161            List<FunctionDescriptor> superFunctions;
162            if (ownerDescriptor instanceof ClassDescriptor && !method.getJetMethodAnnotation().isDefined()) { // don't propagate for Kotlin functions
163                SignaturesPropagationData signaturesPropagationData = new SignaturesPropagationData(
164                        (ClassDescriptor) ownerDescriptor, returnType, valueParameterDescriptors, methodTypeParameters, method, trace);
165                superFunctions = signaturesPropagationData.getSuperFunctions();
166    
167                returnType = signaturesPropagationData.getModifiedReturnType();
168                valueParameterDescriptors = signaturesPropagationData.getModifiedValueParameters();
169                methodTypeParameters = signaturesPropagationData.getModifiedTypeParameters();
170    
171                signatureErrors.addAll(signaturesPropagationData.getSignatureErrors());
172            }
173            else {
174                superFunctions = Collections.emptyList();
175            }
176    
177            AlternativeMethodSignatureData alternativeMethodSignatureData =
178                    new AlternativeMethodSignatureData(method, valueParameterDescriptors, returnType, methodTypeParameters,
179                                                       !superFunctions.isEmpty());
180            if (alternativeMethodSignatureData.isAnnotated() && !alternativeMethodSignatureData.hasErrors()) {
181                valueParameterDescriptors = alternativeMethodSignatureData.getValueParameters();
182                returnType = alternativeMethodSignatureData.getReturnType();
183                methodTypeParameters = alternativeMethodSignatureData.getTypeParameters();
184            }
185            else if (alternativeMethodSignatureData.hasErrors()) {
186                signatureErrors.add(alternativeMethodSignatureData.getError());
187            }
188    
189            functionDescriptorImpl.initialize(
190                    valueParameterDescriptors.getReceiverType(),
191                    DescriptorUtils.getExpectedThisObjectIfNeeded(ownerDescriptor),
192                    methodTypeParameters,
193                    valueParameterDescriptors.getDescriptors(),
194                    returnType,
195                    DescriptorResolverUtils.resolveModality(method, method.isFinal()),
196                    DescriptorResolverUtils.resolveVisibility(psiMethod, method.getJetMethodAnnotation()),
197                    /*isInline = */ false
198            );
199    
200            if (functionDescriptorImpl.getKind() == CallableMemberDescriptor.Kind.DECLARATION && record) {
201                BindingContextUtils.recordFunctionDeclarationToDescriptor(trace, psiMethod, functionDescriptorImpl);
202            }
203    
204            if (declarationOrigin == JAVA && record) {
205                trace.record(JavaBindingContext.IS_DECLARED_IN_JAVA, functionDescriptorImpl);
206            }
207    
208            if (containingClass != psiClass && !method.isStatic()) {
209                throw new IllegalStateException("non-static method in subclass");
210            }
211    
212            if (!RawTypesCheck.hasRawTypesInHierarchicalSignature(psiMethod)
213                    && JavaMethodSignatureUtil.isMethodReturnTypeCompatible(psiMethod)
214                    && !containsErrorType(superFunctions, functionDescriptorImpl)) {
215                if (signatureErrors.isEmpty()) {
216                    checkFunctionsOverrideCorrectly(method, superFunctions, functionDescriptorImpl);
217                }
218                else {
219                    if (record) {
220                        trace.record(JavaBindingContext.LOAD_FROM_JAVA_SIGNATURE_ERRORS, functionDescriptorImpl, signatureErrors);
221                    }
222                }
223            }
224    
225            return functionDescriptorImpl;
226        }
227    
228        private static void checkFunctionsOverrideCorrectly(
229                PsiMethodWrapper method,
230                List<FunctionDescriptor> superFunctions,
231                FunctionDescriptor functionDescriptor
232        ) {
233            for (FunctionDescriptor superFunction : superFunctions) {
234                ClassDescriptor klass = (ClassDescriptor) functionDescriptor.getContainingDeclaration();
235                List<TypeSubstitution> substitutions = Lists.newArrayList();
236                while (true) {
237                    substitutions.add(SubstitutionUtils.buildDeepSubstitutor(klass.getDefaultType()).getSubstitution());
238                    if (!klass.isInner()) {
239                        break;
240                    }
241                    klass = (ClassDescriptor) klass.getContainingDeclaration();
242                }
243                TypeSubstitutor substitutor = TypeSubstitutor.create(substitutions.toArray(new TypeSubstitution[substitutions.size()]));
244                FunctionDescriptor superFunctionSubstituted = superFunction.substitute(substitutor);
245    
246                assert superFunctionSubstituted != null :
247                        "Couldn't substitute super function: " + superFunction + ", substitutor = " + substitutor;
248    
249                OverrideCompatibilityInfo.Result overridableResult =
250                        isOverridableBy(superFunctionSubstituted, functionDescriptor).getResult();
251                boolean paramsOk = overridableResult == OverrideCompatibilityInfo.Result.OVERRIDABLE;
252                boolean returnTypeOk =
253                        isReturnTypeOkForOverride(JetTypeChecker.INSTANCE, superFunctionSubstituted, functionDescriptor);
254                if (!paramsOk || !returnTypeOk) {
255                    LOG.error("Loaded Java method overrides another, but resolved as Kotlin function, doesn't.\n"
256                              + "super function = " + superFunction + "\n"
257                              + "super class = " + superFunction.getContainingDeclaration() + "\n"
258                              + "sub function = " + functionDescriptor + "\n"
259                              + "sub class = " + functionDescriptor.getContainingDeclaration() + "\n"
260                              + "sub method = " + PsiFormatUtil.getExternalName(method.getPsiMethod()) + "\n"
261                              + "@KotlinSignature = " + method.getSignatureAnnotation().signature());
262                }
263            }
264        }
265    
266        @NotNull
267        private Set<FunctionDescriptor> resolveNamedGroupFunctions(
268                @NotNull ClassOrNamespaceDescriptor owner, @NotNull PsiClass psiClass,
269                NamedMembers namedMembers, Name methodName, PsiDeclarationProvider scopeData
270        ) {
271    
272            Set<SimpleFunctionDescriptor> functionsFromSupertypes = null;
273            if (owner instanceof ClassDescriptor) {
274                functionsFromSupertypes = getFunctionsFromSupertypes(methodName, owner);
275            }
276    
277            Set<SimpleFunctionDescriptor> functionsFromCurrent = Sets.newHashSet();
278            for (PsiMethodWrapper method : namedMembers.getMethods()) {
279                SimpleFunctionDescriptor function = resolveMethodToFunctionDescriptor(psiClass, method, scopeData.getDeclarationOrigin(), owner, true);
280                if (function != null) {
281                    functionsFromCurrent.add(function);
282    
283                    if (!DescriptorResolverUtils.isKotlinClass(psiClass)) {
284                        ContainerUtil.addIfNotNull(functionsFromCurrent, resolveSamAdapter(function));
285                    }
286                }
287            }
288    
289            if (owner instanceof NamespaceDescriptor) {
290                ContainerUtil.addIfNotNull(functionsFromCurrent, resolveSamConstructor((NamespaceDescriptor) owner, namedMembers));
291            }
292    
293    
294            final Set<FunctionDescriptor> fakeOverrides = new HashSet<FunctionDescriptor>();
295            if (owner instanceof ClassDescriptor) {
296                ClassDescriptor classDescriptor = (ClassDescriptor) owner;
297    
298                OverrideResolver.generateOverridesInFunctionGroup(methodName, functionsFromSupertypes, functionsFromCurrent, classDescriptor,
299                      new OverrideResolver.DescriptorSink() {
300                          @Override
301                          public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) {
302                              fakeOverrides.add((FunctionDescriptor) fakeOverride);
303                          }
304    
305                          @Override
306                          public void conflict(
307                                  @NotNull CallableMemberDescriptor fromSuper,
308                                  @NotNull CallableMemberDescriptor fromCurrent
309                          ) {
310                              // nop
311                          }
312                      });
313            }
314    
315            OverrideResolver.resolveUnknownVisibilities(fakeOverrides, trace);
316    
317            Set<FunctionDescriptor> functions = Sets.newHashSet(fakeOverrides);
318            if (isEnumClassObject(owner)) {
319                for (FunctionDescriptor functionDescriptor : functionsFromCurrent) {
320                    if (!(isEnumValueOfMethod(functionDescriptor) || isEnumValuesMethod(functionDescriptor))) {
321                        functions.add(functionDescriptor);
322                    }
323                }
324            }
325            else {
326                functions.addAll(functionsFromCurrent);
327            }
328    
329            return functions;
330        }
331    
332        @Nullable
333        private static ClassDescriptorFromJvmBytecode findClassInScope(@NotNull JetScope memberScope, @NotNull Name name) {
334            ClassifierDescriptor classifier = memberScope.getClassifier(name);
335            if (classifier instanceof ClassDescriptorFromJvmBytecode) {
336                return (ClassDescriptorFromJvmBytecode) classifier;
337            }
338            return null;
339        }
340    
341        // E.g. we have foo.Bar.Baz class declared in Java. It will produce the following descriptors structure:
342        // namespace foo
343        // +-- class Bar
344        // |    +-- class Baz
345        // +-- namespace Bar
346        // We need to find class 'Baz' in namespace 'foo.Bar'.
347        @Nullable
348        private static ClassDescriptorFromJvmBytecode findClassInNamespace(@NotNull NamespaceDescriptor namespace, @NotNull Name name) {
349            // First, try to find in namespace directly
350            ClassDescriptorFromJvmBytecode found = findClassInScope(namespace.getMemberScope(), name);
351            if (found != null) {
352                return found;
353            }
354    
355            // If unsuccessful, try to find class of the same name as current (class 'foo.Bar')
356            NamespaceDescriptorParent parent = namespace.getContainingDeclaration();
357            if (parent instanceof NamespaceDescriptor) {
358                // Calling recursively, looking for 'Bar' in 'foo'
359                ClassDescriptor classForCurrentNamespace = findClassInNamespace((NamespaceDescriptor) parent, namespace.getName());
360                if (classForCurrentNamespace == null) {
361                    return null;
362                }
363    
364                // Try to find nested class 'Baz' in class 'foo.Bar'
365                return findClassInScope(DescriptorUtils.getStaticNestedClassesScope(classForCurrentNamespace), name);
366            }
367            return null;
368        }
369    
370        @Nullable
371        private SimpleFunctionDescriptor resolveSamConstructor(
372                @NotNull NamespaceDescriptor ownerDescriptor,
373                @NotNull NamedMembers namedMembers
374        ) {
375            PsiClass samInterface = namedMembers.getSamInterface();
376            if (samInterface != null) {
377                ClassDescriptorFromJvmBytecode klass = findClassInNamespace(ownerDescriptor, namedMembers.getName());
378                if (klass != null) {
379                    return recordSamConstructor(klass, createSamConstructorFunction(ownerDescriptor, klass), trace);
380                }
381            }
382            return null;
383        }
384    
385        @Nullable
386        private SimpleFunctionDescriptor resolveSamAdapter(@NotNull SimpleFunctionDescriptor original) {
387            return isSamAdapterNecessary(original)
388                   ? recordSamAdapter(original, createSamAdapterFunction(original), trace)
389                   : null;
390        }
391    
392        @NotNull
393        public Set<FunctionDescriptor> resolveFunctionGroup(
394                @NotNull Name methodName,
395                @NotNull ClassPsiDeclarationProvider scopeData,
396                @NotNull ClassOrNamespaceDescriptor ownerDescriptor
397        ) {
398    
399            NamedMembers namedMembers = scopeData.getMembersCache().get(methodName);
400            if (namedMembers == null) {
401                return Collections.emptySet();
402            }
403            PsiClass psiClass = scopeData.getPsiClass();
404            return resolveNamedGroupFunctions(ownerDescriptor, psiClass, namedMembers, methodName, scopeData);
405        }
406    
407        @NotNull
408        public Set<FunctionDescriptor> resolveFunctionGroup(
409                @NotNull Name functionName,
410                @NotNull PackagePsiDeclarationProvider scopeData,
411                @NotNull NamespaceDescriptor ownerDescriptor
412        ) {
413            NamedMembers namedMembers = scopeData.getMembersCache().get(functionName);
414            if (namedMembers != null) {
415                SimpleFunctionDescriptor samConstructor = resolveSamConstructor(ownerDescriptor, namedMembers);
416                if (samConstructor != null) {
417                    return Collections.<FunctionDescriptor>singleton(samConstructor);
418                }
419            }
420            return Collections.emptySet();
421        }
422    
423        @NotNull
424        private JetType makeReturnType(
425                PsiType returnType, PsiMethodWrapper method,
426                @NotNull TypeVariableResolver typeVariableResolver
427        ) {
428    
429            String returnTypeFromAnnotation = method.getJetMethodAnnotation().returnType();
430    
431            JetType transformedType;
432            if (returnTypeFromAnnotation.length() > 0) {
433                transformedType = typeTransformer.transformToType(returnTypeFromAnnotation, typeVariableResolver);
434            }
435            else {
436                TypeUsage typeUsage = JavaTypeTransformer.adjustTypeUsageWithMutabilityAnnotations(method.getPsiMethod(), TypeUsage.MEMBER_SIGNATURE_COVARIANT);
437                transformedType = typeTransformer.transformToType(returnType, typeUsage, typeVariableResolver);
438            }
439    
440            if (JavaAnnotationResolver.findAnnotationWithExternal(method.getPsiMethod(), JvmAbi.JETBRAINS_NOT_NULL_ANNOTATION.getFqName().asString()) !=
441                null) {
442                return TypeUtils.makeNullableAsSpecified(transformedType, false);
443            }
444            else {
445                return transformedType;
446            }
447        }
448    
449        @NotNull
450        private static Set<SimpleFunctionDescriptor> getFunctionsFromSupertypes(
451                @NotNull Name methodName, @NotNull ClassOrNamespaceDescriptor classOrNamespaceDescriptor
452        ) {
453            Set<SimpleFunctionDescriptor> r = Sets.newLinkedHashSet();
454            for (JetType supertype : DescriptorResolverUtils.getSupertypes(classOrNamespaceDescriptor)) {
455                for (FunctionDescriptor function : supertype.getMemberScope().getFunctions(methodName)) {
456                    r.add((SimpleFunctionDescriptor) function);
457                }
458            }
459            return r;
460        }
461    
462        private static boolean containsErrorType(@NotNull List<FunctionDescriptor> superFunctions, @NotNull FunctionDescriptor function) {
463            if (containsErrorType(function)) {
464                return true;
465            }
466    
467            for (FunctionDescriptor superFunction : superFunctions) {
468                if (containsErrorType(superFunction)) {
469                    return true;
470                }
471            }
472    
473            return false;
474        }
475    
476        private static boolean containsErrorType(@NotNull FunctionDescriptor function) {
477            if (ErrorUtils.containsErrorType(function.getReturnType())) {
478                return true;
479            }
480            for (ValueParameterDescriptor parameter : function.getValueParameters()) {
481                if (ErrorUtils.containsErrorType(parameter.getType())) {
482                    return true;
483                }
484            }
485            for (TypeParameterDescriptor parameter : function.getTypeParameters()) {
486                for (JetType upperBound : parameter.getUpperBounds()) {
487                    if (ErrorUtils.containsErrorType(upperBound)) {
488                        return true;
489                    }
490                }
491            }
492    
493            return false;
494        }
495    
496        private static SimpleFunctionDescriptor recordSamConstructor(ClassDescriptorFromJvmBytecode klass, SimpleFunctionDescriptor constructorFunction, BindingTrace trace) {
497            trace.record(JavaBindingContext.SAM_CONSTRUCTOR_TO_INTERFACE, constructorFunction, klass);
498            trace.record(BindingContext.SOURCE_DESCRIPTOR_FOR_SYNTHESIZED, constructorFunction, klass);
499            return constructorFunction;
500        }
501    
502        static <F extends FunctionDescriptor> F recordSamAdapter(F original, F adapterFunction, BindingTrace trace) {
503            trace.record(JavaBindingContext.SAM_ADAPTER_FUNCTION_TO_ORIGINAL, adapterFunction, original);
504            trace.record(BindingContext.SOURCE_DESCRIPTOR_FOR_SYNTHESIZED, adapterFunction, original);
505            return adapterFunction;
506        }
507    }