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