001    /*
002     * Copyright 2010-2015 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.kotlin.load.java.descriptors;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.kotlin.descriptors.*;
022    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
023    import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
024    import org.jetbrains.kotlin.name.Name;
025    import org.jetbrains.kotlin.types.KotlinType;
026    import org.jetbrains.kotlin.types.TypeSubstitutor;
027    import org.jetbrains.kotlin.util.OperatorChecks;
028    
029    import java.util.List;
030    
031    public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implements JavaCallableMemberDescriptor {
032        private enum ParameterNamesStatus {
033            NON_STABLE_DECLARED(false, false),
034            STABLE_DECLARED(true, false),
035            NON_STABLE_SYNTHESIZED(false, true),
036            STABLE_SYNTHESIZED(true, true), // TODO: this makes no sense
037            ;
038    
039            public final boolean isStable;
040            public final boolean isSynthesized;
041    
042            ParameterNamesStatus(boolean isStable, boolean isSynthesized) {
043                this.isStable = isStable;
044                this.isSynthesized = isSynthesized;
045            }
046    
047            @NotNull
048            public static ParameterNamesStatus get(boolean stable, boolean synthesized) {
049                return stable ? (synthesized ? STABLE_SYNTHESIZED : STABLE_DECLARED) :
050                       (synthesized ? NON_STABLE_SYNTHESIZED : NON_STABLE_DECLARED);
051            }
052        }
053    
054        private ParameterNamesStatus parameterNamesStatus = null;
055    
056        protected JavaMethodDescriptor(
057                @NotNull DeclarationDescriptor containingDeclaration,
058                @Nullable SimpleFunctionDescriptor original,
059                @NotNull Annotations annotations,
060                @NotNull Name name,
061                @NotNull Kind kind,
062                @NotNull SourceElement source
063        ) {
064            super(containingDeclaration, original, annotations, name, kind, source);
065        }
066    
067        @NotNull
068        public static JavaMethodDescriptor createJavaMethod(
069                @NotNull DeclarationDescriptor containingDeclaration,
070                @NotNull Annotations annotations,
071                @NotNull Name name,
072                @NotNull SourceElement source
073        ) {
074            return new JavaMethodDescriptor(containingDeclaration, null, annotations, name, Kind.DECLARATION, source);
075        }
076    
077        @NotNull
078        @Override
079        public SimpleFunctionDescriptorImpl initialize(
080                @Nullable KotlinType receiverParameterType,
081                @Nullable ReceiverParameterDescriptor dispatchReceiverParameter,
082                @NotNull List<? extends TypeParameterDescriptor> typeParameters,
083                @NotNull List<ValueParameterDescriptor> unsubstitutedValueParameters,
084                @Nullable KotlinType unsubstitutedReturnType,
085                @Nullable Modality modality,
086                @NotNull Visibility visibility
087        ) {
088            SimpleFunctionDescriptorImpl descriptor = super.initialize(
089                    receiverParameterType, dispatchReceiverParameter, typeParameters, unsubstitutedValueParameters,
090                    unsubstitutedReturnType, modality, visibility);
091            setOperator(OperatorChecks.INSTANCE$.canBeOperator(descriptor));
092            return descriptor;
093        }
094    
095        @Override
096        public boolean hasStableParameterNames() {
097            assert parameterNamesStatus != null : "Parameter names status was not set: " + this;
098            return parameterNamesStatus.isStable;
099        }
100    
101        @Override
102        public boolean hasSynthesizedParameterNames() {
103            assert parameterNamesStatus != null : "Parameter names status was not set: " + this;
104            return parameterNamesStatus.isSynthesized;
105        }
106    
107        public void setParameterNamesStatus(boolean hasStableParameterNames, boolean hasSynthesizedParameterNames) {
108            this.parameterNamesStatus = ParameterNamesStatus.get(hasStableParameterNames, hasSynthesizedParameterNames);
109        }
110    
111        @NotNull
112        @Override
113        protected JavaMethodDescriptor createSubstitutedCopy(
114                @NotNull DeclarationDescriptor newOwner,
115                @Nullable FunctionDescriptor original,
116                @NotNull Kind kind,
117                @Nullable Name newName,
118                boolean preserveSource
119        ) {
120            JavaMethodDescriptor result = new JavaMethodDescriptor(
121                    newOwner,
122                    (SimpleFunctionDescriptor) original,
123                    getAnnotations(),
124                    newName != null ? newName : getName(),
125                    kind,
126                    getSourceToUseForCopy(preserveSource, original)
127            );
128            result.setParameterNamesStatus(hasStableParameterNames(), hasSynthesizedParameterNames());
129            return result;
130        }
131    
132        @Override
133        @NotNull
134        public JavaMethodDescriptor enhance(
135                @Nullable KotlinType enhancedReceiverType,
136                @NotNull List<KotlinType> enhancedValueParametersTypes,
137                @NotNull KotlinType enhancedReturnType
138        ) {
139            List<ValueParameterDescriptor> enhancedValueParameters =
140                    UtilKt.copyValueParameters(enhancedValueParametersTypes, getValueParameters(), this);
141    
142            // We use `doSubstitute` here because it does exactly what we need:
143            // 1. creates full copy of descriptor
144            // 2. copies method's type parameters (with new containing declaration) and properly substitute to them in value parameters, return type and etc.
145            JavaMethodDescriptor enhancedMethod = (JavaMethodDescriptor) doSubstitute(
146                    TypeSubstitutor.EMPTY, getContainingDeclaration(), getModality(), getVisibility(),
147                    isOperator(), isInfix(), isExternal(), isInline(), isTailrec(), hasStableParameterNames(), hasSynthesizedParameterNames(),
148                    getOriginal(), /* copyOverrides = */ true, getKind(),
149                    enhancedValueParameters, enhancedReceiverType, enhancedReturnType,
150                    null, /* preserveSource */false, /* signatureChange = */ false);
151    
152            assert enhancedMethod != null : "null after substitution while enhancing " + toString();
153            return enhancedMethod;
154        }
155    }