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