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