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