001 /* 002 * Copyright 2010-2015 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.kotlin.codegen; 018 019 import com.intellij.psi.PsiElement; 020 import kotlin.KotlinPackage; 021 import kotlin.jvm.functions.Function1; 022 import org.jetbrains.annotations.NotNull; 023 import org.jetbrains.annotations.Nullable; 024 import org.jetbrains.kotlin.codegen.binding.CalculatedClosure; 025 import org.jetbrains.kotlin.codegen.context.CodegenContext; 026 import org.jetbrains.kotlin.codegen.context.MethodContext; 027 import org.jetbrains.kotlin.codegen.context.PackageContext; 028 import org.jetbrains.kotlin.codegen.context.RootContext; 029 import org.jetbrains.kotlin.codegen.state.JetTypeMapper; 030 import org.jetbrains.kotlin.descriptors.*; 031 import org.jetbrains.kotlin.load.java.JvmAbi; 032 import org.jetbrains.kotlin.load.java.JvmAnnotationNames; 033 import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor; 034 import org.jetbrains.kotlin.load.kotlin.ModuleMapping; 035 import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityUtilsKt; 036 import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider; 037 import org.jetbrains.kotlin.psi.JetFile; 038 import org.jetbrains.kotlin.psi.JetFunction; 039 import org.jetbrains.kotlin.psi.codeFragmentUtil.CodeFragmentUtilPackage; 040 import org.jetbrains.kotlin.resolve.BindingContext; 041 import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; 042 import org.jetbrains.kotlin.resolve.DescriptorUtils; 043 import org.jetbrains.kotlin.resolve.inline.InlineUtil; 044 import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor; 045 import org.jetbrains.kotlin.types.JetType; 046 import org.jetbrains.org.objectweb.asm.AnnotationVisitor; 047 048 import java.io.File; 049 050 import static org.jetbrains.kotlin.descriptors.Modality.ABSTRACT; 051 import static org.jetbrains.kotlin.descriptors.Modality.FINAL; 052 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isTrait; 053 054 public class JvmCodegenUtil { 055 056 private JvmCodegenUtil() { 057 } 058 059 public static boolean isInterface(DeclarationDescriptor descriptor) { 060 if (descriptor instanceof ClassDescriptor) { 061 ClassKind kind = ((ClassDescriptor) descriptor).getKind(); 062 return kind == ClassKind.INTERFACE || 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 boolean isConst(@NotNull CalculatedClosure closure) { 072 return closure.getCaptureThis() == null && closure.getCaptureReceiverType() == null && closure.getCaptureVariables().isEmpty(); 073 } 074 075 private static boolean isCallInsideSameClassAsDeclared(@NotNull CallableMemberDescriptor descriptor, @NotNull CodegenContext context) { 076 boolean isFakeOverride = descriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE; 077 boolean isDelegate = descriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION; 078 079 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration().getOriginal(); 080 081 return !isFakeOverride && !isDelegate && 082 (((context.hasThisDescriptor() && containingDeclaration == context.getThisDescriptor()) || 083 (context.getParentContext() instanceof PackageContext 084 && isSamePackageInSameModule(context.getParentContext().getContextDescriptor(), containingDeclaration))) 085 && context.getContextKind() != OwnerKind.TRAIT_IMPL); 086 } 087 088 private static boolean isSamePackageInSameModule( 089 @NotNull DeclarationDescriptor callerOwner, 090 @NotNull DeclarationDescriptor calleeOwner 091 ) { 092 if (callerOwner instanceof PackageFragmentDescriptor && calleeOwner instanceof PackageFragmentDescriptor) { 093 PackageFragmentDescriptor callerFragment = (PackageFragmentDescriptor) callerOwner; 094 PackageFragmentDescriptor calleeFragment = (PackageFragmentDescriptor) calleeOwner; 095 096 // backing field should be used directly within same module of same package 097 if (callerFragment == calleeFragment) { 098 return true; 099 } 100 return callerFragment.getFqName().equals(calleeFragment.getFqName()) 101 && calleeFragment instanceof IncrementalPackageFragmentProvider.IncrementalPackageFragment; 102 } 103 return false; 104 } 105 106 public static boolean isCallInsideSameModuleAsDeclared( 107 @NotNull CallableMemberDescriptor declarationDescriptor, 108 @NotNull CodegenContext context, 109 @Nullable File outDirectory 110 ) { 111 if (context instanceof RootContext) { 112 return true; 113 } 114 DeclarationDescriptor contextDescriptor = context.getContextDescriptor(); 115 116 CallableMemberDescriptor directMember = getDirectMember(declarationDescriptor); 117 if (directMember instanceof DeserializedCallableMemberDescriptor) { 118 return ModuleVisibilityUtilsKt.isContainedByCompiledPartOfOurModule(directMember, outDirectory); 119 } 120 else { 121 return DescriptorUtils.areInSameModule(directMember, contextDescriptor); 122 } 123 } 124 125 public static boolean hasAbstractMembers(@NotNull ClassDescriptor classDescriptor) { 126 return KotlinPackage.any(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors(), 127 new Function1<DeclarationDescriptor, Boolean>() { 128 @Override 129 public Boolean invoke(DeclarationDescriptor descriptor) { 130 return descriptor instanceof CallableMemberDescriptor && 131 ((CallableMemberDescriptor) descriptor).getModality() == ABSTRACT; 132 } 133 } 134 ); 135 } 136 137 public static boolean couldUseDirectAccessToProperty( 138 @NotNull PropertyDescriptor property, 139 boolean forGetter, 140 boolean isDelegated, 141 @NotNull MethodContext context 142 ) { 143 if (JetTypeMapper.isAccessor(property)) return false; 144 145 // Inline functions can't use direct access because a field may not be visible at the call site 146 if (context.isInlineFunction() && 147 (!Visibilities.isPrivate(property.getVisibility()) || DescriptorUtils.isTopLevelDeclaration(property))) { 148 return false; 149 } 150 151 // Only properties of the same class can be directly accessed, except when we are evaluating expressions in the debugger 152 if (!isCallInsideSameClassAsDeclared(property, context) && !isDebuggerContext(context)) return false; 153 154 // Delegated and extension properties have no backing fields 155 if (isDelegated || property.getExtensionReceiverParameter() != null) return false; 156 157 // Companion object properties cannot be accessed directly because their backing fields are stored in the containing class 158 if (DescriptorUtils.isCompanionObject(property.getContainingDeclaration())) return false; 159 160 PropertyAccessorDescriptor accessor = forGetter ? property.getGetter() : property.getSetter(); 161 162 // If there's no accessor declared we can use direct access 163 if (accessor == null) return true; 164 165 // If the accessor is non-default (i.e. it has some code) we should call that accessor and not use direct access 166 if (accessor.hasBody()) return false; 167 168 // If the accessor is private or final, it can't be overridden in the subclass and thus we can use direct access 169 return Visibilities.isPrivate(property.getVisibility()) || accessor.getModality() == FINAL; 170 } 171 172 private static boolean isDebuggerContext(@NotNull MethodContext context) { 173 JetFile file = DescriptorToSourceUtils.getContainingFile(context.getContextDescriptor()); 174 return file != null && CodeFragmentUtilPackage.getSuppressDiagnosticsInDebugMode(file); 175 } 176 177 @Nullable 178 public static ClassDescriptor getDispatchReceiverParameterForConstructorCall( 179 @NotNull ConstructorDescriptor descriptor, 180 @Nullable CalculatedClosure closure 181 ) { 182 //for compilation against sources 183 if (closure != null) { 184 return closure.getCaptureThis(); 185 } 186 187 //for compilation against binaries 188 //TODO: It's best to use this code also for compilation against sources 189 // but sometimes structures that have dispatchReceiver (bug?) mapped to static classes 190 ReceiverParameterDescriptor dispatchReceiver = descriptor.getDispatchReceiverParameter(); 191 if (dispatchReceiver != null) { 192 ClassDescriptor expectedThisClass = (ClassDescriptor) dispatchReceiver.getContainingDeclaration(); 193 if (!expectedThisClass.getKind().isSingleton()) { 194 return expectedThisClass; 195 } 196 } 197 198 return null; 199 } 200 201 @NotNull 202 public static CallableMemberDescriptor getDirectMember(@NotNull CallableMemberDescriptor descriptor) { 203 return descriptor instanceof PropertyAccessorDescriptor 204 ? ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty() 205 : descriptor; 206 } 207 208 public static boolean isArgumentWhichWillBeInlined(@NotNull BindingContext bindingContext, @NotNull DeclarationDescriptor descriptor) { 209 PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor); 210 return InlineUtil.canBeInlineArgument(declaration) && 211 InlineUtil.isInlinedArgument((JetFunction) declaration, bindingContext, false); 212 } 213 214 public static boolean shouldUseJavaClassForClassLiteral(@NotNull ClassifierDescriptor descriptor) { 215 ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor); 216 return descriptor instanceof JavaClassDescriptor || 217 module == module.getBuiltIns().getBuiltInsModule() || 218 DescriptorUtils.isAnnotationClass(descriptor); 219 } 220 221 @NotNull 222 public static String getModuleName(ModuleDescriptor module) { 223 return KotlinPackage.removeSurrounding(module.getName().asString(), "<", ">"); 224 } 225 226 @NotNull 227 public static String getMappingFileName(@NotNull String moduleName) { 228 return "META-INF/" + moduleName + "." + ModuleMapping.MAPPING_FILE_EXT; 229 } 230 231 public static void writeAbiVersion(@NotNull AnnotationVisitor av) { 232 av.visit(JvmAnnotationNames.VERSION_FIELD_NAME, JvmAbi.VERSION.toArray()); 233 234 // TODO: drop after some time 235 av.visit(JvmAnnotationNames.OLD_ABI_VERSION_FIELD_NAME, JvmAbi.VERSION.getMinor()); 236 } 237 }