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.Condition;
020 import com.intellij.openapi.util.io.FileUtil;
021 import com.intellij.openapi.vfs.VirtualFile;
022 import com.intellij.util.ArrayUtil;
023 import com.intellij.util.Function;
024 import com.intellij.util.containers.ContainerUtil;
025 import com.intellij.util.containers.Stack;
026 import org.jetbrains.annotations.NotNull;
027 import org.jetbrains.annotations.Nullable;
028 import org.jetbrains.jet.codegen.binding.CalculatedClosure;
029 import org.jetbrains.jet.codegen.context.CodegenContext;
030 import org.jetbrains.jet.codegen.context.MethodContext;
031 import org.jetbrains.jet.codegen.context.PackageContext;
032 import org.jetbrains.jet.codegen.state.JetTypeMapper;
033 import org.jetbrains.jet.lang.descriptors.*;
034 import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
035 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
036 import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
037 import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
038 import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
039 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
040 import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
041 import org.jetbrains.jet.lang.resolve.constants.*;
042 import org.jetbrains.jet.lang.resolve.name.FqName;
043 import org.jetbrains.jet.lang.resolve.name.Name;
044 import org.jetbrains.jet.lang.types.JetType;
045 import org.jetbrains.jet.lang.types.TypeUtils;
046 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
047
048 import java.util.Arrays;
049 import java.util.Collection;
050 import java.util.Collections;
051 import java.util.List;
052
053 import static org.jetbrains.jet.lang.descriptors.Modality.ABSTRACT;
054
055 public class CodegenUtil {
056
057 private CodegenUtil() {
058 }
059
060 public static boolean isInterface(DeclarationDescriptor descriptor) {
061 if (descriptor instanceof ClassDescriptor) {
062 ClassKind kind = ((ClassDescriptor) descriptor).getKind();
063 return kind == ClassKind.TRAIT || kind == ClassKind.ANNOTATION_CLASS;
064 }
065 return false;
066 }
067
068 public static boolean isInterface(JetType type) {
069 return isInterface(type.getConstructor().getDeclarationDescriptor());
070 }
071
072 public static SimpleFunctionDescriptor createInvoke(FunctionDescriptor fd) {
073 int arity = fd.getValueParameters().size();
074 SimpleFunctionDescriptorImpl invokeDescriptor = new SimpleFunctionDescriptorImpl(
075 fd.getExpectedThisObject() != null
076 ? KotlinBuiltIns.getInstance().getExtensionFunction(arity) : KotlinBuiltIns.getInstance().getFunction(arity),
077 Annotations.EMPTY,
078 Name.identifier("invoke"),
079 CallableMemberDescriptor.Kind.DECLARATION);
080
081 invokeDescriptor.initialize(DescriptorUtils.getReceiverParameterType(fd.getReceiverParameter()),
082 fd.getExpectedThisObject(),
083 Collections.<TypeParameterDescriptorImpl>emptyList(),
084 fd.getValueParameters(),
085 fd.getReturnType(),
086 Modality.FINAL,
087 Visibilities.PUBLIC
088 );
089 return invokeDescriptor;
090 }
091
092 public static boolean isConst(@NotNull CalculatedClosure closure) {
093 return closure.getCaptureThis() == null && closure.getCaptureReceiverType() == null && closure.getCaptureVariables().isEmpty();
094 }
095
096 public static <T> T peekFromStack(Stack<T> stack) {
097 return stack.empty() ? null : stack.peek();
098 }
099
100 public static JetType getSuperClass(ClassDescriptor classDescriptor) {
101 List<ClassDescriptor> superclassDescriptors = DescriptorUtils.getSuperclassDescriptors(classDescriptor);
102 for (ClassDescriptor descriptor : superclassDescriptors) {
103 if (descriptor.getKind() != ClassKind.TRAIT) {
104 return descriptor.getDefaultType();
105 }
106 }
107 return KotlinBuiltIns.getInstance().getAnyType();
108 }
109
110 @NotNull
111 public static <T extends CallableMemberDescriptor> T unwrapFakeOverride(T member) {
112 while (member.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
113 //noinspection unchecked
114 member = (T) member.getOverriddenDescriptors().iterator().next();
115 }
116 return member;
117 }
118
119 @Nullable
120 public static FunctionDescriptor getDeclaredFunctionByRawSignature(
121 @NotNull ClassDescriptor owner,
122 @NotNull Name name,
123 @NotNull ClassifierDescriptor returnedClassifier,
124 @NotNull ClassifierDescriptor... valueParameterClassifiers
125 ) {
126 Collection<FunctionDescriptor> functions = owner.getDefaultType().getMemberScope().getFunctions(name);
127 for (FunctionDescriptor function : functions) {
128 if (!CallResolverUtil.isOrOverridesSynthesized(function)
129 && function.getTypeParameters().isEmpty()
130 && valueParameterClassesMatch(function.getValueParameters(), Arrays.asList(valueParameterClassifiers))
131 && rawTypeMatches(function.getReturnType(), returnedClassifier)) {
132 return function;
133 }
134 }
135 return null;
136 }
137
138 private static boolean valueParameterClassesMatch(
139 @NotNull List<ValueParameterDescriptor> parameters,
140 @NotNull List<ClassifierDescriptor> classifiers) {
141 if (parameters.size() != classifiers.size()) return false;
142 for (int i = 0; i < parameters.size(); i++) {
143 ValueParameterDescriptor parameterDescriptor = parameters.get(i);
144 ClassifierDescriptor classDescriptor = classifiers.get(i);
145 if (!rawTypeMatches(parameterDescriptor.getType(), classDescriptor)) {
146 return false;
147 }
148 }
149 return true;
150 }
151
152 private static boolean rawTypeMatches(JetType type, ClassifierDescriptor classifier) {
153 return type.getConstructor().getDeclarationDescriptor().getOriginal() == classifier.getOriginal();
154 }
155
156 public static boolean isCallInsideSameClassAsDeclared(CallableMemberDescriptor declarationDescriptor, CodegenContext context) {
157 boolean isFakeOverride = declarationDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
158 boolean isDelegate = declarationDescriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION;
159
160 DeclarationDescriptor containingDeclaration = declarationDescriptor.getContainingDeclaration();
161 containingDeclaration = containingDeclaration.getOriginal();
162
163 return !isFakeOverride && !isDelegate &&
164 (((context.hasThisDescriptor() && containingDeclaration == context.getThisDescriptor()) ||
165 (context.getParentContext() instanceof PackageContext && context.getParentContext().getContextDescriptor() == containingDeclaration))
166 && context.getContextKind() != OwnerKind.TRAIT_IMPL);
167 }
168
169 public static boolean isCallInsideSameModuleAsDeclared(CallableMemberDescriptor declarationDescriptor, CodegenContext context) {
170 if (context == CodegenContext.STATIC) {
171 return true;
172 }
173 DeclarationDescriptor contextDescriptor = context.getContextDescriptor();
174 return DescriptorUtils.areInSameModule(declarationDescriptor, contextDescriptor);
175 }
176
177 public static boolean hasAbstractMembers(@NotNull ClassDescriptor classDescriptor) {
178 return ContainerUtil.exists(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors(),
179 new Condition<DeclarationDescriptor>() {
180 @Override
181 public boolean value(DeclarationDescriptor declaration) {
182 if (!(declaration instanceof MemberDescriptor)) {
183 return false;
184 }
185 return ((MemberDescriptor) declaration).getModality() == ABSTRACT;
186 }
187 });
188 }
189
190 /**
191 * A work-around of the generic nullability problem in the type checker
192 * @return true if a value of this type can be null
193 */
194 public static boolean isNullableType(@NotNull JetType type) {
195 if (type.isNullable()) {
196 return true;
197 }
198 if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
199 return TypeUtils.hasNullableSuperType(type);
200 }
201 return false;
202 }
203
204 public static boolean couldUseDirectAccessToProperty(
205 @NotNull PropertyDescriptor propertyDescriptor,
206 boolean forGetter,
207 boolean isInsideClass,
208 boolean isDelegated,
209 MethodContext context
210 ) {
211 if (context.isInlineFunction()) {
212 return false;
213 }
214 PropertyAccessorDescriptor accessorDescriptor = forGetter ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
215 boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
216 boolean specialTypeProperty = isDelegated ||
217 isExtensionProperty ||
218 DescriptorUtils.isClassObject(propertyDescriptor.getContainingDeclaration()) ||
219 JetTypeMapper.isAccessor(propertyDescriptor);
220 return isInsideClass &&
221 !specialTypeProperty &&
222 (accessorDescriptor == null ||
223 accessorDescriptor.isDefault() &&
224 (!isExternallyAccessible(propertyDescriptor) || accessorDescriptor.getModality() == Modality.FINAL));
225 }
226
227 private static boolean isExternallyAccessible(@NotNull PropertyDescriptor propertyDescriptor) {
228 return propertyDescriptor.getVisibility() != Visibilities.PRIVATE ||
229 DescriptorUtils.isClassObject(propertyDescriptor.getContainingDeclaration()) ||
230 DescriptorUtils.isTopLevelDeclaration(propertyDescriptor);
231 }
232
233 @NotNull
234 public static ImplementationBodyCodegen getParentBodyCodegen(@Nullable MemberCodegen classBodyCodegen) {
235 assert classBodyCodegen != null &&
236 classBodyCodegen
237 .getParentCodegen() instanceof ImplementationBodyCodegen : "Class object should have appropriate parent BodyCodegen";
238
239 return ((ImplementationBodyCodegen) classBodyCodegen.getParentCodegen());
240 }
241
242 static int getPathHashCode(@NotNull VirtualFile file) {
243 // Conversion to system-dependent name seems to be unnecessary, but it's hard to check now:
244 // it was introduced when fixing KT-2839, which appeared again (KT-3639).
245 // If you try to remove it, run tests on Windows.
246 return FileUtil.toSystemDependentName(file.getPath()).hashCode();
247 }
248
249 @Nullable
250 public static ClassDescriptor getExpectedThisObjectForConstructorCall(
251 @NotNull ConstructorDescriptor descriptor,
252 @Nullable CalculatedClosure closure
253 ) {
254 //for compilation against sources
255 if (closure != null) {
256 return closure.getCaptureThis();
257 }
258
259 //for compilation against binaries
260 //TODO: It's best to use this code also for compilation against sources
261 // but sometimes structures that have expectedThisObject (bug?) mapped to static classes
262 ReceiverParameterDescriptor expectedThisObject = descriptor.getExpectedThisObject();
263 if (expectedThisObject != null) {
264 ClassDescriptor expectedThisClass = (ClassDescriptor) expectedThisObject.getContainingDeclaration();
265 if (!expectedThisClass.getKind().isSingleton()) {
266 return expectedThisClass;
267 }
268 }
269
270 return null;
271 }
272
273 @NotNull
274 public static String[] getExceptions(@NotNull Annotated annotatedDescriptor, @NotNull final JetTypeMapper mapper) {
275 // Can't say 'throws.class', because 'throws' is a reserved work in Java
276 AnnotationDescriptor annotation = annotatedDescriptor.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
277 if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY;
278
279 Collection<CompileTimeConstant<?>> values = annotation.getAllValueArguments().values();
280 if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY;
281
282 Object value = values.iterator().next();
283 if (!(value instanceof ArrayValue)) return ArrayUtil.EMPTY_STRING_ARRAY;
284 ArrayValue arrayValue = (ArrayValue) value;
285
286 List<String> strings = ContainerUtil.mapNotNull(
287 arrayValue.getValue(),
288 new Function<CompileTimeConstant<?>, String>() {
289 @Override
290 public String fun(CompileTimeConstant<?> constant) {
291 if (constant instanceof JavaClassValue) {
292 JavaClassValue classValue = (JavaClassValue) constant;
293 ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue());
294 return mapper.mapClass(classDescriptor).getInternalName();
295 }
296 return null;
297 }
298 }
299 );
300 return strings.toArray(new String[strings.size()]);
301 }
302 }