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 }