001 /*
002 * Copyright 2010-2014 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.backend.common;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.annotations.Nullable;
021 import org.jetbrains.jet.codegen.bridges.BridgesPackage;
022 import org.jetbrains.jet.lang.descriptors.*;
023 import org.jetbrains.jet.lang.psi.JetDelegationSpecifier;
024 import org.jetbrains.jet.lang.psi.JetExpression;
025 import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
026 import org.jetbrains.jet.lang.resolve.BindingContext;
027 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
028 import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
029 import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
030 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
031 import org.jetbrains.jet.lang.resolve.name.Name;
032 import org.jetbrains.jet.lang.types.JetType;
033 import org.jetbrains.jet.lang.types.TypeUtils;
034 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
035 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
036
037 import java.util.*;
038
039 /**
040 * Backend-independent utility class.
041 */
042 public class CodegenUtil {
043
044 private CodegenUtil() {
045 }
046
047 // TODO: consider putting predefined method signatures here too.
048 public static final String EQUALS_METHOD_NAME = "equals";
049 public static final String TO_STRING_METHOD_NAME = "toString";
050 public static final String HASH_CODE_METHOD_NAME = "hashCode";
051
052 @Nullable
053 public static FunctionDescriptor getDeclaredFunctionByRawSignature(
054 @NotNull ClassDescriptor owner,
055 @NotNull Name name,
056 @NotNull ClassifierDescriptor returnedClassifier,
057 @NotNull ClassifierDescriptor... valueParameterClassifiers
058 ) {
059 Collection<FunctionDescriptor> functions = owner.getDefaultType().getMemberScope().getFunctions(name);
060 for (FunctionDescriptor function : functions) {
061 if (!CallResolverUtil.isOrOverridesSynthesized(function)
062 && function.getTypeParameters().isEmpty()
063 && valueParameterClassesMatch(function.getValueParameters(), Arrays.asList(valueParameterClassifiers))
064 && rawTypeMatches(function.getReturnType(), returnedClassifier)) {
065 return function;
066 }
067 }
068 return null;
069 }
070
071 public static FunctionDescriptor getAnyEqualsMethod() {
072 ClassDescriptor anyClass = KotlinBuiltIns.getInstance().getAny();
073 FunctionDescriptor function =
074 getDeclaredFunctionByRawSignature(anyClass, Name.identifier(EQUALS_METHOD_NAME),
075 KotlinBuiltIns.getInstance().getBoolean(),
076 anyClass);
077 assert function != null;
078 return function;
079 }
080
081 public static FunctionDescriptor getAnyToStringMethod() {
082 ClassDescriptor anyClass = KotlinBuiltIns.getInstance().getAny();
083 FunctionDescriptor function =
084 getDeclaredFunctionByRawSignature(anyClass, Name.identifier(TO_STRING_METHOD_NAME),
085 KotlinBuiltIns.getInstance().getString());
086 assert function != null;
087 return function;
088 }
089
090 public static FunctionDescriptor getAnyHashCodeMethod() {
091 ClassDescriptor anyClass = KotlinBuiltIns.getInstance().getAny();
092 FunctionDescriptor function =
093 getDeclaredFunctionByRawSignature(anyClass, Name.identifier(HASH_CODE_METHOD_NAME),
094 KotlinBuiltIns.getInstance().getInt());
095 assert function != null;
096 return function;
097 }
098
099 @Nullable
100 public static PropertyDescriptor getDelegatePropertyIfAny(JetExpression expression, ClassDescriptor classDescriptor, BindingContext bindingContext) {
101 PropertyDescriptor propertyDescriptor = null;
102 if (expression instanceof JetSimpleNameExpression) {
103 ResolvedCall<?> call = CallUtilPackage.getResolvedCall(expression, bindingContext);
104 if (call != null) {
105 CallableDescriptor callResultingDescriptor = call.getResultingDescriptor();
106 if (callResultingDescriptor instanceof ValueParameterDescriptor) {
107 ValueParameterDescriptor valueParameterDescriptor = (ValueParameterDescriptor) callResultingDescriptor;
108 // constructor parameter
109 if (valueParameterDescriptor.getContainingDeclaration() instanceof ConstructorDescriptor) {
110 // constructor of my class
111 if (valueParameterDescriptor.getContainingDeclaration().getContainingDeclaration() == classDescriptor) {
112 propertyDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, valueParameterDescriptor);
113 }
114 }
115 }
116
117 // todo: when and if frontend will allow properties defined not as constructor parameters to be used in delegation specifier
118 }
119 }
120 return propertyDescriptor;
121 }
122
123 public static boolean isFinalPropertyWithBackingField(PropertyDescriptor propertyDescriptor, BindingContext bindingContext) {
124 return propertyDescriptor != null &&
125 !propertyDescriptor.isVar() &&
126 Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor));
127 }
128
129 @NotNull
130 public static Map<FunctionDescriptor, FunctionDescriptor> getTraitMethods(ClassDescriptor descriptor) {
131 Map<FunctionDescriptor, FunctionDescriptor> result = new LinkedHashMap<FunctionDescriptor, FunctionDescriptor>();
132 for (DeclarationDescriptor declaration : descriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
133 if (!(declaration instanceof CallableMemberDescriptor)) continue;
134
135 CallableMemberDescriptor inheritedMember = (CallableMemberDescriptor) declaration;
136 CallableMemberDescriptor traitMember = BridgesPackage.findTraitImplementation(inheritedMember);
137 if (traitMember == null) continue;
138
139 assert traitMember.getModality() != Modality.ABSTRACT : "Cannot delegate to abstract trait method: " + inheritedMember;
140
141 // inheritedMember can be abstract here. In order for FunctionCodegen to generate the method body, we're creating a copy here
142 // with traitMember's modality
143 CallableMemberDescriptor copy =
144 inheritedMember.copy(inheritedMember.getContainingDeclaration(), traitMember.getModality(), Visibilities.PUBLIC,
145 CallableMemberDescriptor.Kind.DECLARATION, true);
146
147 if (traitMember instanceof SimpleFunctionDescriptor) {
148 result.put((FunctionDescriptor) traitMember, (FunctionDescriptor) copy);
149 }
150 else if (traitMember instanceof PropertyDescriptor) {
151 for (PropertyAccessorDescriptor traitAccessor : ((PropertyDescriptor) traitMember).getAccessors()) {
152 for (PropertyAccessorDescriptor inheritedAccessor : ((PropertyDescriptor) copy).getAccessors()) {
153 if (inheritedAccessor.getClass() == traitAccessor.getClass()) { // same accessor kind
154 result.put(traitAccessor, inheritedAccessor);
155 }
156 }
157 }
158 }
159 }
160 return result;
161 }
162
163 @NotNull
164 public static ClassDescriptor getSuperClassByDelegationSpecifier(@NotNull JetDelegationSpecifier specifier, @NotNull BindingContext bindingContext) {
165 JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
166 assert superType != null : "superType should not be null: " + specifier.getText();
167
168 ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
169 assert superClassDescriptor != null : "superClassDescriptor should not be null: " + specifier.getText();
170 return superClassDescriptor;
171 }
172
173 private static boolean valueParameterClassesMatch(
174 @NotNull List<ValueParameterDescriptor> parameters,
175 @NotNull List<ClassifierDescriptor> classifiers
176 ) {
177 if (parameters.size() != classifiers.size()) return false;
178 for (int i = 0; i < parameters.size(); i++) {
179 ValueParameterDescriptor parameterDescriptor = parameters.get(i);
180 ClassifierDescriptor classDescriptor = classifiers.get(i);
181 if (!rawTypeMatches(parameterDescriptor.getType(), classDescriptor)) {
182 return false;
183 }
184 }
185 return true;
186 }
187
188 private static boolean rawTypeMatches(JetType type, ClassifierDescriptor classifier) {
189 return type.getConstructor().equals(classifier.getTypeConstructor());
190 }
191
192 public static boolean isEnumValueOfMethod(@NotNull FunctionDescriptor functionDescriptor) {
193 List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
194 JetType nullableString = TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getStringType());
195 return DescriptorUtils.ENUM_VALUE_OF.equals(functionDescriptor.getName())
196 && methodTypeParameters.size() == 1
197 && JetTypeChecker.DEFAULT.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString);
198 }
199
200 public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor functionDescriptor) {
201 List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
202 return DescriptorUtils.ENUM_VALUES.equals(functionDescriptor.getName())
203 && methodTypeParameters.isEmpty();
204 }
205 }