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 }