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