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.codegen;
018    
019    import com.intellij.util.containers.Stack;
020    import kotlin.Function1;
021    import kotlin.KotlinPackage;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.jet.codegen.binding.CalculatedClosure;
025    import org.jetbrains.jet.codegen.context.CodegenContext;
026    import org.jetbrains.jet.codegen.context.MethodContext;
027    import org.jetbrains.jet.codegen.context.PackageContext;
028    import org.jetbrains.jet.codegen.state.JetTypeMapper;
029    import org.jetbrains.jet.config.IncrementalCompilation;
030    import org.jetbrains.jet.lang.descriptors.*;
031    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
032    import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
033    import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
034    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
035    import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
036    import org.jetbrains.jet.lang.resolve.name.Name;
037    import org.jetbrains.jet.lang.types.JetType;
038    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
039    
040    import java.util.Arrays;
041    import java.util.Collection;
042    import java.util.Collections;
043    import java.util.List;
044    
045    import static org.jetbrains.jet.lang.descriptors.Modality.ABSTRACT;
046    
047    public class JvmCodegenUtil {
048    
049        private JvmCodegenUtil() {
050        }
051    
052        public static boolean isInterface(DeclarationDescriptor descriptor) {
053            if (descriptor instanceof ClassDescriptor) {
054                ClassKind kind = ((ClassDescriptor) descriptor).getKind();
055                return kind == ClassKind.TRAIT || kind == ClassKind.ANNOTATION_CLASS;
056            }
057            return false;
058        }
059    
060        public static boolean isInterface(JetType type) {
061            return isInterface(type.getConstructor().getDeclarationDescriptor());
062        }
063    
064        public static SimpleFunctionDescriptor createInvoke(FunctionDescriptor fd) {
065            int arity = fd.getValueParameters().size();
066            SimpleFunctionDescriptorImpl invokeDescriptor = SimpleFunctionDescriptorImpl.create(
067                    fd.getExpectedThisObject() != null
068                    ? KotlinBuiltIns.getInstance().getExtensionFunction(arity) : KotlinBuiltIns.getInstance().getFunction(arity),
069                    Annotations.EMPTY,
070                    Name.identifier("invoke"),
071                    CallableMemberDescriptor.Kind.DECLARATION
072            );
073    
074            invokeDescriptor.initialize(DescriptorUtils.getReceiverParameterType(fd.getReceiverParameter()),
075                                        fd.getExpectedThisObject(),
076                                        Collections.<TypeParameterDescriptorImpl>emptyList(),
077                                        fd.getValueParameters(),
078                                        fd.getReturnType(),
079                                        Modality.FINAL,
080                                        Visibilities.PUBLIC
081            );
082            return invokeDescriptor;
083        }
084    
085        public static boolean isConst(@NotNull CalculatedClosure closure) {
086            return closure.getCaptureThis() == null && closure.getCaptureReceiverType() == null && closure.getCaptureVariables().isEmpty();
087        }
088    
089        public static <T> T peekFromStack(Stack<T> stack) {
090            return stack.empty() ? null : stack.peek();
091        }
092    
093        public static JetType getSuperClass(ClassDescriptor classDescriptor) {
094            List<ClassDescriptor> superclassDescriptors = DescriptorUtils.getSuperclassDescriptors(classDescriptor);
095            for (ClassDescriptor descriptor : superclassDescriptors) {
096                if (descriptor.getKind() != ClassKind.TRAIT) {
097                    return descriptor.getDefaultType();
098                }
099            }
100            return KotlinBuiltIns.getInstance().getAnyType();
101        }
102    
103        @Nullable
104        public static FunctionDescriptor getDeclaredFunctionByRawSignature(
105                @NotNull ClassDescriptor owner,
106                @NotNull Name name,
107                @NotNull ClassifierDescriptor returnedClassifier,
108                @NotNull ClassifierDescriptor... valueParameterClassifiers
109        ) {
110            Collection<FunctionDescriptor> functions = owner.getDefaultType().getMemberScope().getFunctions(name);
111            for (FunctionDescriptor function : functions) {
112                if (!CallResolverUtil.isOrOverridesSynthesized(function)
113                    && function.getTypeParameters().isEmpty()
114                    && valueParameterClassesMatch(function.getValueParameters(), Arrays.asList(valueParameterClassifiers))
115                    && rawTypeMatches(function.getReturnType(), returnedClassifier)) {
116                    return function;
117                }
118            }
119            return null;
120        }
121    
122        private static boolean valueParameterClassesMatch(
123                @NotNull List<ValueParameterDescriptor> parameters,
124                @NotNull List<ClassifierDescriptor> classifiers) {
125            if (parameters.size() != classifiers.size()) return false;
126            for (int i = 0; i < parameters.size(); i++) {
127                ValueParameterDescriptor parameterDescriptor = parameters.get(i);
128                ClassifierDescriptor classDescriptor = classifiers.get(i);
129                if (!rawTypeMatches(parameterDescriptor.getType(), classDescriptor)) {
130                    return false;
131                }
132            }
133            return true;
134        }
135    
136        private static boolean rawTypeMatches(JetType type, ClassifierDescriptor classifier) {
137            return type.getConstructor().getDeclarationDescriptor().getOriginal() == classifier.getOriginal();
138        }
139    
140        public static boolean isCallInsideSameClassAsDeclared(CallableMemberDescriptor declarationDescriptor, CodegenContext context) {
141            boolean isFakeOverride = declarationDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
142            boolean isDelegate = declarationDescriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION;
143    
144            DeclarationDescriptor containingDeclaration = declarationDescriptor.getContainingDeclaration();
145            containingDeclaration = containingDeclaration.getOriginal();
146    
147            return !isFakeOverride && !isDelegate &&
148                   (((context.hasThisDescriptor() && containingDeclaration == context.getThisDescriptor()) ||
149                     (context.getParentContext() instanceof PackageContext
150                      && isSamePackageInSameModule(context.getParentContext().getContextDescriptor(), containingDeclaration)))
151                    && context.getContextKind() != OwnerKind.TRAIT_IMPL);
152        }
153    
154        private static boolean isSamePackageInSameModule(
155                @NotNull DeclarationDescriptor owner1,
156                @NotNull DeclarationDescriptor owner2
157        ) {
158            if (owner1 instanceof PackageFragmentDescriptor && owner2 instanceof PackageFragmentDescriptor) {
159                PackageFragmentDescriptor fragment1 = (PackageFragmentDescriptor) owner1;
160                PackageFragmentDescriptor fragment2 = (PackageFragmentDescriptor) owner2;
161    
162                if (!IncrementalCompilation.ENABLED) {
163                    return fragment1 == fragment2;
164                }
165    
166                // backing field should be used directly within same module of same package
167                // TODO calls from other modules/libraries should use facade: KT-4590
168                return fragment1.getFqName().equals(fragment2.getFqName()) && DescriptorUtils.areInSameModule(fragment1, fragment2);
169            }
170            return false;
171        }
172    
173        public static boolean isCallInsideSameModuleAsDeclared(CallableMemberDescriptor declarationDescriptor, CodegenContext context) {
174            if (context == CodegenContext.STATIC) {
175                return true;
176            }
177            DeclarationDescriptor contextDescriptor = context.getContextDescriptor();
178            return DescriptorUtils.areInSameModule(declarationDescriptor, contextDescriptor);
179        }
180    
181        public static boolean hasAbstractMembers(@NotNull ClassDescriptor classDescriptor) {
182            return KotlinPackage.any(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors(),
183                                     new Function1<DeclarationDescriptor, Boolean>() {
184                                         @Override
185                                         public Boolean invoke(DeclarationDescriptor descriptor) {
186                                             return descriptor instanceof CallableMemberDescriptor &&
187                                                    ((CallableMemberDescriptor) descriptor).getModality() == ABSTRACT;
188                                         }
189                                     }
190            );
191        }
192    
193        public static boolean couldUseDirectAccessToProperty(
194                @NotNull PropertyDescriptor propertyDescriptor,
195                boolean forGetter,
196                boolean isInsideClass,
197                boolean isDelegated,
198                MethodContext context
199        ) {
200            if (context.isInlineFunction()) {
201                return false;
202            }
203            PropertyAccessorDescriptor accessorDescriptor = forGetter ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
204            boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
205            boolean specialTypeProperty = isDelegated ||
206                                          isExtensionProperty ||
207                                          DescriptorUtils.isClassObject(propertyDescriptor.getContainingDeclaration()) ||
208                                          JetTypeMapper.isAccessor(propertyDescriptor);
209            return isInsideClass &&
210                   !specialTypeProperty &&
211                   (accessorDescriptor == null ||
212                    accessorDescriptor.isDefault() &&
213                    (!isExternallyAccessible(propertyDescriptor) || accessorDescriptor.getModality() == Modality.FINAL));
214        }
215    
216        private static boolean isExternallyAccessible(@NotNull PropertyDescriptor propertyDescriptor) {
217            return propertyDescriptor.getVisibility() != Visibilities.PRIVATE ||
218                   DescriptorUtils.isClassObject(propertyDescriptor.getContainingDeclaration()) ||
219                   DescriptorUtils.isTopLevelDeclaration(propertyDescriptor);
220        }
221    
222        @NotNull
223        public static ImplementationBodyCodegen getParentBodyCodegen(@Nullable MemberCodegen<?> classBodyCodegen) {
224            assert classBodyCodegen != null && classBodyCodegen.getParentCodegen() instanceof ImplementationBodyCodegen
225                    : "Class object should have appropriate parent BodyCodegen";
226    
227            return (ImplementationBodyCodegen) classBodyCodegen.getParentCodegen();
228        }
229    
230        @Nullable
231        public static ClassDescriptor getExpectedThisObjectForConstructorCall(
232                @NotNull ConstructorDescriptor descriptor,
233                @Nullable CalculatedClosure closure
234        ) {
235            //for compilation against sources
236            if (closure != null) {
237                return closure.getCaptureThis();
238            }
239    
240            //for compilation against binaries
241            //TODO: It's best to use this code also for compilation against sources
242            // but sometimes structures that have expectedThisObject (bug?) mapped to static classes
243            ReceiverParameterDescriptor expectedThisObject = descriptor.getExpectedThisObject();
244            if (expectedThisObject != null) {
245                ClassDescriptor expectedThisClass = (ClassDescriptor) expectedThisObject.getContainingDeclaration();
246                if (!expectedThisClass.getKind().isSingleton()) {
247                    return expectedThisClass;
248                }
249            }
250    
251            return null;
252        }
253    }