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 }