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