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 static int getPathHashCode(@NotNull VirtualFile file) {
248 // Conversion to system-dependent name seems to be unnecessary, but it's hard to check now:
249 // it was introduced when fixing KT-2839, which appeared again (KT-3639).
250 // If you try to remove it, run tests on Windows.
251 return FileUtil.toSystemDependentName(file.getPath()).hashCode();
252 }
253
254 @Nullable
255 public static ClassDescriptor getExpectedThisObjectForConstructorCall(
256 @NotNull ConstructorDescriptor descriptor,
257 @Nullable CalculatedClosure closure
258 ) {
259 //for compilation against sources
260 if (closure != null) {
261 return closure.getCaptureThis();
262 }
263
264 //for compilation against binaries
265 //TODO: It's best to use this code also for compilation against sources
266 // but sometimes structures that have expectedThisObject (bug?) mapped to static classes
267 ReceiverParameterDescriptor expectedThisObject = descriptor.getExpectedThisObject();
268 if (expectedThisObject != null) {
269 ClassDescriptor expectedThisClass = (ClassDescriptor) expectedThisObject.getContainingDeclaration();
270 if (!expectedThisClass.getKind().isSingleton()) {
271 return expectedThisClass;
272 }
273 }
274
275 return null;
276 }
277 }