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