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.io.FileUtil; 020 import com.intellij.openapi.vfs.VirtualFile; 021 import com.intellij.util.containers.Stack; 022 import kotlin.Function1; 023 import kotlin.KotlinPackage; 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.MethodContext; 029 import org.jetbrains.jet.codegen.context.PackageContext; 030 import org.jetbrains.jet.codegen.state.JetTypeMapper; 031 import org.jetbrains.jet.config.IncrementalCompilation; 032 import org.jetbrains.jet.lang.descriptors.*; 033 import org.jetbrains.jet.lang.descriptors.annotations.Annotations; 034 import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl; 035 import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl; 036 import org.jetbrains.jet.lang.resolve.DescriptorUtils; 037 import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil; 038 import org.jetbrains.jet.lang.resolve.name.Name; 039 import org.jetbrains.jet.lang.types.JetType; 040 import org.jetbrains.jet.lang.types.TypeUtils; 041 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 042 043 import java.util.Arrays; 044 import java.util.Collection; 045 import java.util.Collections; 046 import java.util.List; 047 048 import static org.jetbrains.jet.lang.descriptors.Modality.ABSTRACT; 049 050 public class JvmCodegenUtil { 051 052 private JvmCodegenUtil() { 053 } 054 055 public static boolean isInterface(DeclarationDescriptor descriptor) { 056 if (descriptor instanceof ClassDescriptor) { 057 ClassKind kind = ((ClassDescriptor) descriptor).getKind(); 058 return kind == ClassKind.TRAIT || kind == ClassKind.ANNOTATION_CLASS; 059 } 060 return false; 061 } 062 063 public static boolean isInterface(JetType type) { 064 return isInterface(type.getConstructor().getDeclarationDescriptor()); 065 } 066 067 public static SimpleFunctionDescriptor createInvoke(FunctionDescriptor fd) { 068 int arity = fd.getValueParameters().size(); 069 SimpleFunctionDescriptorImpl invokeDescriptor = SimpleFunctionDescriptorImpl.create( 070 fd.getExpectedThisObject() != null 071 ? KotlinBuiltIns.getInstance().getExtensionFunction(arity) : KotlinBuiltIns.getInstance().getFunction(arity), 072 Annotations.EMPTY, 073 Name.identifier("invoke"), 074 CallableMemberDescriptor.Kind.DECLARATION 075 ); 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 boolean isConst(@NotNull CalculatedClosure closure) { 089 return closure.getCaptureThis() == null && closure.getCaptureReceiverType() == null && closure.getCaptureVariables().isEmpty(); 090 } 091 092 public static <T> T peekFromStack(Stack<T> stack) { 093 return stack.empty() ? null : stack.peek(); 094 } 095 096 public static JetType getSuperClass(ClassDescriptor classDescriptor) { 097 List<ClassDescriptor> superclassDescriptors = DescriptorUtils.getSuperclassDescriptors(classDescriptor); 098 for (ClassDescriptor descriptor : superclassDescriptors) { 099 if (descriptor.getKind() != ClassKind.TRAIT) { 100 return descriptor.getDefaultType(); 101 } 102 } 103 return KotlinBuiltIns.getInstance().getAnyType(); 104 } 105 106 @Nullable 107 public static FunctionDescriptor getDeclaredFunctionByRawSignature( 108 @NotNull ClassDescriptor owner, 109 @NotNull Name name, 110 @NotNull ClassifierDescriptor returnedClassifier, 111 @NotNull ClassifierDescriptor... valueParameterClassifiers 112 ) { 113 Collection<FunctionDescriptor> functions = owner.getDefaultType().getMemberScope().getFunctions(name); 114 for (FunctionDescriptor function : functions) { 115 if (!CallResolverUtil.isOrOverridesSynthesized(function) 116 && function.getTypeParameters().isEmpty() 117 && valueParameterClassesMatch(function.getValueParameters(), Arrays.asList(valueParameterClassifiers)) 118 && rawTypeMatches(function.getReturnType(), returnedClassifier)) { 119 return function; 120 } 121 } 122 return null; 123 } 124 125 private static boolean valueParameterClassesMatch( 126 @NotNull List<ValueParameterDescriptor> parameters, 127 @NotNull List<ClassifierDescriptor> classifiers) { 128 if (parameters.size() != classifiers.size()) return false; 129 for (int i = 0; i < parameters.size(); i++) { 130 ValueParameterDescriptor parameterDescriptor = parameters.get(i); 131 ClassifierDescriptor classDescriptor = classifiers.get(i); 132 if (!rawTypeMatches(parameterDescriptor.getType(), classDescriptor)) { 133 return false; 134 } 135 } 136 return true; 137 } 138 139 private static boolean rawTypeMatches(JetType type, ClassifierDescriptor classifier) { 140 return type.getConstructor().getDeclarationDescriptor().getOriginal() == classifier.getOriginal(); 141 } 142 143 public static boolean isCallInsideSameClassAsDeclared(CallableMemberDescriptor declarationDescriptor, CodegenContext context) { 144 boolean isFakeOverride = declarationDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE; 145 boolean isDelegate = declarationDescriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION; 146 147 DeclarationDescriptor containingDeclaration = declarationDescriptor.getContainingDeclaration(); 148 containingDeclaration = containingDeclaration.getOriginal(); 149 150 return !isFakeOverride && !isDelegate && 151 (((context.hasThisDescriptor() && containingDeclaration == context.getThisDescriptor()) || 152 (context.getParentContext() instanceof PackageContext 153 && isSamePackageInSameModule(context.getParentContext().getContextDescriptor(), containingDeclaration))) 154 && context.getContextKind() != OwnerKind.TRAIT_IMPL); 155 } 156 157 private static boolean isSamePackageInSameModule( 158 @NotNull DeclarationDescriptor owner1, 159 @NotNull DeclarationDescriptor owner2 160 ) { 161 if (owner1 instanceof PackageFragmentDescriptor && owner2 instanceof PackageFragmentDescriptor) { 162 PackageFragmentDescriptor fragment1 = (PackageFragmentDescriptor) owner1; 163 PackageFragmentDescriptor fragment2 = (PackageFragmentDescriptor) owner2; 164 165 if (!IncrementalCompilation.ENABLED) { 166 return fragment1 == fragment2; 167 } 168 169 // backing field should be used directly within same module of same package 170 // TODO calls from other modules/libraries should use facade: KT-4590 171 return fragment1.getFqName().equals(fragment2.getFqName()) && DescriptorUtils.areInSameModule(fragment1, fragment2); 172 } 173 return false; 174 } 175 176 public static boolean isCallInsideSameModuleAsDeclared(CallableMemberDescriptor declarationDescriptor, CodegenContext context) { 177 if (context == CodegenContext.STATIC) { 178 return true; 179 } 180 DeclarationDescriptor contextDescriptor = context.getContextDescriptor(); 181 return DescriptorUtils.areInSameModule(declarationDescriptor, contextDescriptor); 182 } 183 184 public static boolean hasAbstractMembers(@NotNull ClassDescriptor classDescriptor) { 185 return KotlinPackage.any(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors(), 186 new Function1<DeclarationDescriptor, Boolean>() { 187 @Override 188 public Boolean invoke(DeclarationDescriptor descriptor) { 189 return descriptor instanceof CallableMemberDescriptor && 190 ((CallableMemberDescriptor) descriptor).getModality() == ABSTRACT; 191 } 192 } 193 ); 194 } 195 196 /** 197 * A work-around of the generic nullability problem in the type checker 198 * @return true if a value of this type can be null 199 */ 200 public static boolean isNullableType(@NotNull JetType type) { 201 if (type.isNullable()) { 202 return true; 203 } 204 if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) { 205 return TypeUtils.hasNullableSuperType(type); 206 } 207 return false; 208 } 209 210 public static boolean couldUseDirectAccessToProperty( 211 @NotNull PropertyDescriptor propertyDescriptor, 212 boolean forGetter, 213 boolean isInsideClass, 214 boolean isDelegated, 215 MethodContext context 216 ) { 217 if (context.isInlineFunction()) { 218 return false; 219 } 220 PropertyAccessorDescriptor accessorDescriptor = forGetter ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter(); 221 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null; 222 boolean specialTypeProperty = isDelegated || 223 isExtensionProperty || 224 DescriptorUtils.isClassObject(propertyDescriptor.getContainingDeclaration()) || 225 JetTypeMapper.isAccessor(propertyDescriptor); 226 return isInsideClass && 227 !specialTypeProperty && 228 (accessorDescriptor == null || 229 accessorDescriptor.isDefault() && 230 (!isExternallyAccessible(propertyDescriptor) || accessorDescriptor.getModality() == Modality.FINAL)); 231 } 232 233 private static boolean isExternallyAccessible(@NotNull PropertyDescriptor propertyDescriptor) { 234 return propertyDescriptor.getVisibility() != Visibilities.PRIVATE || 235 DescriptorUtils.isClassObject(propertyDescriptor.getContainingDeclaration()) || 236 DescriptorUtils.isTopLevelDeclaration(propertyDescriptor); 237 } 238 239 @NotNull 240 public static ImplementationBodyCodegen getParentBodyCodegen(@Nullable MemberCodegen<?> classBodyCodegen) { 241 assert classBodyCodegen != null && classBodyCodegen.getParentCodegen() instanceof ImplementationBodyCodegen 242 : "Class object should have appropriate parent BodyCodegen"; 243 244 return (ImplementationBodyCodegen) classBodyCodegen.getParentCodegen(); 245 } 246 247 @Nullable 248 public static ClassDescriptor getExpectedThisObjectForConstructorCall( 249 @NotNull ConstructorDescriptor descriptor, 250 @Nullable CalculatedClosure closure 251 ) { 252 //for compilation against sources 253 if (closure != null) { 254 return closure.getCaptureThis(); 255 } 256 257 //for compilation against binaries 258 //TODO: It's best to use this code also for compilation against sources 259 // but sometimes structures that have expectedThisObject (bug?) mapped to static classes 260 ReceiverParameterDescriptor expectedThisObject = descriptor.getExpectedThisObject(); 261 if (expectedThisObject != null) { 262 ClassDescriptor expectedThisClass = (ClassDescriptor) expectedThisObject.getContainingDeclaration(); 263 if (!expectedThisClass.getKind().isSingleton()) { 264 return expectedThisClass; 265 } 266 } 267 268 return null; 269 } 270 }