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