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