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