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.Lists;
020import com.google.common.collect.Sets;
021import com.intellij.openapi.diagnostic.Logger;
022import com.intellij.psi.PsiClass;
023import com.intellij.psi.PsiMethod;
024import com.intellij.psi.PsiType;
025import com.intellij.psi.util.PsiFormatUtil;
026import com.intellij.util.containers.ContainerUtil;
027import org.jetbrains.annotations.NotNull;
028import org.jetbrains.annotations.Nullable;
029import org.jetbrains.jet.lang.descriptors.*;
030import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorParent;
031import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
032import org.jetbrains.jet.lang.resolve.*;
033import org.jetbrains.jet.lang.resolve.java.*;
034import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode;
035import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeMethodSignatureData;
036import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesPropagationData;
037import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils;
038import org.jetbrains.jet.lang.resolve.java.provider.*;
039import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
040import org.jetbrains.jet.lang.resolve.name.Name;
041import org.jetbrains.jet.lang.resolve.scopes.JetScope;
042import org.jetbrains.jet.lang.types.*;
043import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
044
045import javax.inject.Inject;
046import java.util.Collections;
047import java.util.HashSet;
048import java.util.List;
049import java.util.Set;
050
051import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
052import static org.jetbrains.jet.lang.resolve.OverridingUtil.*;
053import static org.jetbrains.jet.lang.resolve.java.provider.DeclarationOrigin.JAVA;
054import static org.jetbrains.jet.lang.resolve.java.provider.DeclarationOrigin.KOTLIN;
055import static org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils.*;
056
057public 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}