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.Condition;
020    import com.intellij.openapi.util.io.FileUtil;
021    import com.intellij.openapi.vfs.VirtualFile;
022    import com.intellij.util.containers.ContainerUtil;
023    import com.intellij.util.containers.Stack;
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.NamespaceContext;
029    import org.jetbrains.jet.codegen.signature.BothSignatureWriter;
030    import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind;
031    import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
032    import org.jetbrains.jet.codegen.state.JetTypeMapper;
033    import org.jetbrains.jet.lang.descriptors.*;
034    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
035    import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
036    import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
037    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
038    import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
039    import org.jetbrains.jet.lang.resolve.name.Name;
040    import org.jetbrains.jet.lang.types.JetType;
041    import org.jetbrains.jet.lang.types.TypeUtils;
042    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
043    
044    import java.util.*;
045    
046    import static org.jetbrains.jet.lang.descriptors.Modality.ABSTRACT;
047    import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
048    
049    public class CodegenUtil {
050    
051        private CodegenUtil() {
052        }
053    
054        private static final Random RANDOM = new Random(55L);
055    
056        public static boolean isInterface(DeclarationDescriptor descriptor) {
057            if (descriptor instanceof ClassDescriptor) {
058                ClassKind kind = ((ClassDescriptor) descriptor).getKind();
059                return kind == ClassKind.TRAIT || kind == ClassKind.ANNOTATION_CLASS;
060            }
061            return false;
062        }
063    
064        public static boolean isInterface(JetType type) {
065            return isInterface(type.getConstructor().getDeclarationDescriptor());
066        }
067    
068        public static SimpleFunctionDescriptor createInvoke(FunctionDescriptor fd) {
069            int arity = fd.getValueParameters().size();
070            SimpleFunctionDescriptorImpl invokeDescriptor = new SimpleFunctionDescriptorImpl(
071                    fd.getExpectedThisObject() != null
072                    ? KotlinBuiltIns.getInstance().getExtensionFunction(arity) : KotlinBuiltIns.getInstance().getFunction(arity),
073                    Collections.<AnnotationDescriptor>emptyList(),
074                    Name.identifier("invoke"),
075                    CallableMemberDescriptor.Kind.DECLARATION);
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 String createTmpVariableName(Collection<String> existingNames) {
089            String prefix = "tmp";
090            int i = RANDOM.nextInt(Integer.MAX_VALUE);
091            String name = prefix + i;
092            while (existingNames.contains(name)) {
093                i++;
094                name = prefix + i;
095            }
096            return name;
097        }
098    
099    
100        public static JvmMethodSignature erasedInvokeSignature(FunctionDescriptor fd) {
101            BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false);
102    
103            boolean isExtensionFunction = fd.getReceiverParameter() != null;
104            int paramCount = fd.getValueParameters().size();
105            if (isExtensionFunction) {
106                paramCount++;
107            }
108    
109            signatureWriter.writeParametersStart();
110    
111            for (int i = 0; i < paramCount; ++i) {
112                signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE);
113                signatureWriter.writeAsmType(OBJECT_TYPE);
114                signatureWriter.writeParameterTypeEnd();
115            }
116    
117            signatureWriter.writeReturnType();
118            signatureWriter.writeAsmType(OBJECT_TYPE);
119            signatureWriter.writeReturnTypeEnd();
120    
121            return signatureWriter.makeJvmMethodSignature("invoke");
122        }
123    
124        public static boolean isConst(CalculatedClosure closure) {
125            return closure.getCaptureThis() == null && closure.getCaptureReceiverType() == null && closure.getCaptureVariables().isEmpty();
126        }
127    
128        public static <T> T peekFromStack(Stack<T> stack) {
129            return stack.empty() ? null : stack.peek();
130        }
131    
132        public static JetType getSuperClass(ClassDescriptor classDescriptor) {
133            List<ClassDescriptor> superclassDescriptors = DescriptorUtils.getSuperclassDescriptors(classDescriptor);
134            for (ClassDescriptor descriptor : superclassDescriptors) {
135                if (descriptor.getKind() != ClassKind.TRAIT) {
136                    return descriptor.getDefaultType();
137                }
138            }
139            return KotlinBuiltIns.getInstance().getAnyType();
140        }
141    
142        @NotNull
143        public static <T extends CallableMemberDescriptor> T unwrapFakeOverride(T member) {
144            while (member.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
145                //noinspection unchecked
146                member = (T) member.getOverriddenDescriptors().iterator().next();
147            }
148            return member;
149        }
150    
151        @Nullable
152        public static FunctionDescriptor getDeclaredFunctionByRawSignature(
153                @NotNull ClassDescriptor owner,
154                @NotNull Name name,
155                @NotNull ClassifierDescriptor returnedClassifier,
156                @NotNull ClassifierDescriptor... valueParameterClassifiers
157        ) {
158            Collection<FunctionDescriptor> functions = owner.getDefaultType().getMemberScope().getFunctions(name);
159            for (FunctionDescriptor function : functions) {
160                if (!CallResolverUtil.isOrOverridesSynthesized(function)
161                    && function.getTypeParameters().isEmpty()
162                    && valueParameterClassesMatch(function.getValueParameters(), Arrays.asList(valueParameterClassifiers))
163                    && rawTypeMatches(function.getReturnType(), returnedClassifier)) {
164                    return function;
165                }
166            }
167            return null;
168        }
169    
170        private static boolean valueParameterClassesMatch(
171                @NotNull List<ValueParameterDescriptor> parameters,
172                @NotNull List<ClassifierDescriptor> classifiers) {
173            if (parameters.size() != classifiers.size()) return false;
174            for (int i = 0; i < parameters.size(); i++) {
175                ValueParameterDescriptor parameterDescriptor = parameters.get(i);
176                ClassifierDescriptor classDescriptor = classifiers.get(i);
177                if (!rawTypeMatches(parameterDescriptor.getType(), classDescriptor)) {
178                    return false;
179                }
180            }
181            return true;
182        }
183    
184        private static boolean rawTypeMatches(JetType type, ClassifierDescriptor classifier) {
185            return type.getConstructor().getDeclarationDescriptor().getOriginal() == classifier.getOriginal();
186        }
187    
188        public static boolean isCallInsideSameClassAsDeclared(CallableMemberDescriptor declarationDescriptor, CodegenContext context) {
189            boolean isFakeOverride = declarationDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
190            boolean isDelegate = declarationDescriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION;
191    
192            DeclarationDescriptor containingDeclaration = declarationDescriptor.getContainingDeclaration();
193            containingDeclaration = containingDeclaration.getOriginal();
194    
195            return !isFakeOverride && !isDelegate &&
196                   (((context.hasThisDescriptor() && containingDeclaration == context.getThisDescriptor()) ||
197                     (context.getParentContext() instanceof NamespaceContext && context.getParentContext().getContextDescriptor() == containingDeclaration))
198                    && context.getContextKind() != OwnerKind.TRAIT_IMPL);
199        }
200    
201        public static boolean isCallInsideSameModuleAsDeclared(CallableMemberDescriptor declarationDescriptor, CodegenContext context) {
202            if (context == CodegenContext.STATIC) {
203                return true;
204            }
205            DeclarationDescriptor contextDescriptor = context.getContextDescriptor();
206            return DescriptorUtils.isInSameModule(declarationDescriptor, contextDescriptor);
207        }
208    
209        public static boolean hasAbstractMembers(@NotNull ClassDescriptor classDescriptor) {
210            return ContainerUtil.exists(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors(),
211                                        new Condition<DeclarationDescriptor>() {
212                                            @Override
213                                            public boolean value(DeclarationDescriptor declaration) {
214                                                if (!(declaration instanceof MemberDescriptor)) {
215                                                    return false;
216                                                }
217                                                return ((MemberDescriptor) declaration).getModality() == ABSTRACT;
218                                            }
219                                        });
220        }
221    
222        /**
223         * A work-around of the generic nullability problem in the type checker
224         * @return true if a value of this type can be null
225         */
226        public static boolean isNullableType(@NotNull JetType type) {
227            if (type.isNullable()) {
228                return true;
229            }
230            if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
231                return TypeUtils.hasNullableSuperType(type);
232            }
233            return false;
234        }
235    
236        public static boolean couldUseDirectAccessToProperty(@NotNull PropertyDescriptor propertyDescriptor, boolean forGetter, boolean isInsideClass, boolean isDelegated) {
237            PropertyAccessorDescriptor accessorDescriptor = forGetter ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
238            boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
239            boolean specialTypeProperty = isDelegated ||
240                                          isExtensionProperty ||
241                                          DescriptorUtils.isClassObject(propertyDescriptor.getContainingDeclaration()) ||
242                                          JetTypeMapper.isAccessor(propertyDescriptor);
243            return isInsideClass &&
244                   !specialTypeProperty &&
245                   (accessorDescriptor == null ||
246                    accessorDescriptor.isDefault() &&
247                    (!isExternallyAccessible(propertyDescriptor) || accessorDescriptor.getModality() == Modality.FINAL));
248        }
249    
250        private static boolean isExternallyAccessible(@NotNull PropertyDescriptor propertyDescriptor) {
251            return propertyDescriptor.getVisibility() != Visibilities.PRIVATE ||
252                   DescriptorUtils.isClassObject(propertyDescriptor.getContainingDeclaration()) ||
253                   DescriptorUtils.isTopLevelDeclaration(propertyDescriptor);
254        }
255    
256        @NotNull
257        public static ImplementationBodyCodegen getParentBodyCodegen(@Nullable MemberCodegen classBodyCodegen) {
258            assert classBodyCodegen != null &&
259                   classBodyCodegen
260                           .getParentCodegen() instanceof ImplementationBodyCodegen : "Class object should have appropriate parent BodyCodegen";
261    
262            return ((ImplementationBodyCodegen) classBodyCodegen.getParentCodegen());
263        }
264    
265        static int getPathHashCode(@NotNull VirtualFile file) {
266            // Conversion to system-dependent name seems to be unnecessary, but it's hard to check now:
267            // it was introduced when fixing KT-2839, which appeared again (KT-3639).
268            // If you try to remove it, run tests on Windows.
269            return FileUtil.toSystemDependentName(file.getPath()).hashCode();
270        }
271    
272        @Nullable
273        public static ClassDescriptor getExpectedThisObjectForConstructorCall(
274                @NotNull ConstructorDescriptor descriptor,
275                @Nullable CalculatedClosure closure
276        ) {
277            //for compilation against sources
278            if (closure != null) {
279                return closure.getCaptureThis();
280            }
281    
282            //for compilation against binaries
283            //TODO: It's best to use this code also for compilation against sources
284            // but sometimes structures that have expectedThisObject (bug?) mapped to static classes
285            ReceiverParameterDescriptor expectedThisObject = descriptor.getExpectedThisObject();
286            if (expectedThisObject != null) {
287                ClassDescriptor expectedThisClass = (ClassDescriptor) expectedThisObject.getContainingDeclaration();
288                if (!expectedThisClass.getKind().isSingleton()) {
289                    return expectedThisClass;
290                }
291            }
292    
293            return null;
294        }
295    }