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