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.lang.resolve;
018
019 import com.google.common.base.Predicate;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.jet.lang.descriptors.*;
023 import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
024 import org.jetbrains.jet.lang.resolve.name.FqName;
025 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
026 import org.jetbrains.jet.lang.resolve.name.Name;
027 import org.jetbrains.jet.lang.resolve.name.SpecialNames;
028 import org.jetbrains.jet.lang.resolve.scopes.FilteringScope;
029 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
030 import org.jetbrains.jet.lang.types.*;
031 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
032 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
033
034 import java.util.ArrayList;
035 import java.util.Collection;
036 import java.util.List;
037 import java.util.Set;
038
039 import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
040
041 public class DescriptorUtils {
042 private DescriptorUtils() {
043 }
044
045 @Nullable
046 public static ReceiverParameterDescriptor getExpectedThisObjectIfNeeded(@NotNull DeclarationDescriptor containingDeclaration) {
047 if (containingDeclaration instanceof ClassDescriptor) {
048 ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
049 return classDescriptor.getThisAsReceiverParameter();
050 }
051 else if (containingDeclaration instanceof ScriptDescriptor) {
052 ScriptDescriptor scriptDescriptor = (ScriptDescriptor) containingDeclaration;
053 return scriptDescriptor.getThisAsReceiverParameter();
054 }
055 return NO_RECEIVER_PARAMETER;
056 }
057
058 /**
059 * Descriptor may be local itself or have a local ancestor
060 */
061 public static boolean isLocal(@NotNull DeclarationDescriptor descriptor) {
062 DeclarationDescriptor current = descriptor;
063 while (current instanceof MemberDescriptor) {
064 if (isAnonymousObject(current) || ((DeclarationDescriptorWithVisibility) current).getVisibility() == Visibilities.LOCAL) {
065 return true;
066 }
067 current = current.getContainingDeclaration();
068 }
069 return false;
070 }
071
072 @NotNull
073 public static FqNameUnsafe getFqName(@NotNull DeclarationDescriptor descriptor) {
074 FqName safe = getFqNameSafeIfPossible(descriptor);
075 return safe != null ? safe.toUnsafe() : getFqNameUnsafe(descriptor);
076 }
077
078 @NotNull
079 public static FqName getFqNameSafe(@NotNull DeclarationDescriptor descriptor) {
080 FqName safe = getFqNameSafeIfPossible(descriptor);
081 return safe != null ? safe : getFqNameUnsafe(descriptor).toSafe();
082 }
083
084
085 @Nullable
086 private static FqName getFqNameSafeIfPossible(@NotNull DeclarationDescriptor descriptor) {
087 if (descriptor instanceof ModuleDescriptor || ErrorUtils.isError(descriptor)) {
088 return FqName.ROOT;
089 }
090
091 if (descriptor instanceof PackageViewDescriptor) {
092 return ((PackageViewDescriptor) descriptor).getFqName();
093 }
094 else if (descriptor instanceof PackageFragmentDescriptor) {
095 return ((PackageFragmentDescriptor) descriptor).getFqName();
096 }
097
098 return null;
099 }
100
101 @NotNull
102 private static FqNameUnsafe getFqNameUnsafe(@NotNull DeclarationDescriptor descriptor) {
103 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
104
105 if (containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).getKind() == ClassKind.CLASS_OBJECT) {
106 DeclarationDescriptor classOfClassObject = containingDeclaration.getContainingDeclaration();
107 assert classOfClassObject != null;
108 return getFqName(classOfClassObject).child(descriptor.getName());
109 }
110
111 return getFqName(containingDeclaration).child(descriptor.getName());
112 }
113
114 public static boolean isTopLevelDeclaration(@NotNull DeclarationDescriptor descriptor) {
115 return descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor;
116 }
117
118 public static boolean areInSameModule(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) {
119 return getContainingModule(first).equals(getContainingModule(second));
120 }
121
122 @Nullable
123 public static <D extends DeclarationDescriptor> D getParentOfType(
124 @Nullable DeclarationDescriptor descriptor,
125 @NotNull Class<D> aClass
126 ) {
127 return getParentOfType(descriptor, aClass, true);
128 }
129
130 @Nullable
131 public static <D extends DeclarationDescriptor> D getParentOfType(
132 @Nullable DeclarationDescriptor descriptor,
133 @NotNull Class<D> aClass,
134 boolean strict
135 ) {
136 if (descriptor == null) return null;
137 if (strict) {
138 descriptor = descriptor.getContainingDeclaration();
139 }
140 while (descriptor != null) {
141 if (aClass.isInstance(descriptor)) {
142 //noinspection unchecked
143 return (D) descriptor;
144 }
145 descriptor = descriptor.getContainingDeclaration();
146 }
147 return null;
148 }
149
150 @NotNull
151 public static ModuleDescriptor getContainingModule(@NotNull DeclarationDescriptor descriptor) {
152 ModuleDescriptor module = getParentOfType(descriptor, ModuleDescriptor.class, false);
153 assert module != null : "Descriptor without a containing module: " + descriptor;
154 return module;
155 }
156
157 public static boolean isAncestor(
158 @Nullable DeclarationDescriptor ancestor,
159 @NotNull DeclarationDescriptor declarationDescriptor,
160 boolean strict
161 ) {
162 if (ancestor == null) return false;
163 DeclarationDescriptor descriptor = strict ? declarationDescriptor.getContainingDeclaration() : declarationDescriptor;
164 while (descriptor != null) {
165 if (ancestor == descriptor) return true;
166 descriptor = descriptor.getContainingDeclaration();
167 }
168 return false;
169 }
170
171 public static boolean isSubclass(@NotNull ClassDescriptor subClass, @NotNull ClassDescriptor superClass) {
172 return isSubtypeOfClass(subClass.getDefaultType(), superClass.getOriginal());
173 }
174
175 private static boolean isSubtypeOfClass(@NotNull JetType type, @NotNull DeclarationDescriptor superClass) {
176 DeclarationDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
177 if (descriptor != null) {
178 DeclarationDescriptor originalDescriptor = descriptor.getOriginal();
179 if (originalDescriptor instanceof ClassifierDescriptor
180 && superClass instanceof ClassifierDescriptor
181 && ((ClassifierDescriptor) superClass).getTypeConstructor().equals(((ClassifierDescriptor) originalDescriptor).getTypeConstructor())) {
182 return true;
183 }
184 }
185
186 for (JetType superType : type.getConstructor().getSupertypes()) {
187 if (isSubtypeOfClass(superType, superClass)) {
188 return true;
189 }
190 }
191 return false;
192 }
193
194 public static boolean isFunctionLiteral(@NotNull FunctionDescriptor descriptor) {
195 return descriptor instanceof AnonymousFunctionDescriptor;
196 }
197
198 public static boolean isClassObject(@NotNull DeclarationDescriptor descriptor) {
199 return isKindOf(descriptor, ClassKind.CLASS_OBJECT);
200 }
201
202 public static boolean isAnonymousObject(@NotNull DeclarationDescriptor descriptor) {
203 return isClass(descriptor) && descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED);
204 }
205
206 public static boolean isObject(@NotNull DeclarationDescriptor descriptor) {
207 return isKindOf(descriptor, ClassKind.OBJECT);
208 }
209
210 public static boolean isEnumEntry(@NotNull DeclarationDescriptor descriptor) {
211 return isKindOf(descriptor, ClassKind.ENUM_ENTRY);
212 }
213
214 public static boolean isSingleton(@Nullable DeclarationDescriptor classifier) {
215 if (classifier instanceof ClassDescriptor) {
216 ClassDescriptor clazz = (ClassDescriptor) classifier;
217 return clazz.getKind().isSingleton();
218 }
219 return false;
220 }
221
222 public static boolean isEnumClass(@NotNull DeclarationDescriptor descriptor) {
223 return isKindOf(descriptor, ClassKind.ENUM_CLASS);
224 }
225
226 public static boolean isAnnotationClass(@Nullable DeclarationDescriptor descriptor) {
227 return isKindOf(descriptor, ClassKind.ANNOTATION_CLASS);
228 }
229
230 public static boolean isTrait(@Nullable DeclarationDescriptor descriptor) {
231 return isKindOf(descriptor, ClassKind.TRAIT);
232 }
233
234 public static boolean isClass(@Nullable DeclarationDescriptor descriptor) {
235 return isKindOf(descriptor, ClassKind.CLASS);
236 }
237
238 public static boolean isKindOf(@Nullable DeclarationDescriptor descriptor, @NotNull ClassKind classKind) {
239 return descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == classKind;
240 }
241
242 @NotNull
243 public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) {
244 Collection<JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes();
245 List<ClassDescriptor> superClassDescriptors = new ArrayList<ClassDescriptor>();
246 for (JetType type : superclassTypes) {
247 ClassDescriptor result = getClassDescriptorForType(type);
248 if (!isAny(result)) {
249 superClassDescriptors.add(result);
250 }
251 }
252 return superClassDescriptors;
253 }
254
255 @NotNull
256 public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) {
257 return getClassDescriptorForTypeConstructor(type.getConstructor());
258 }
259
260 @NotNull
261 public static ClassDescriptor getClassDescriptorForTypeConstructor(@NotNull TypeConstructor typeConstructor) {
262 ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor();
263 assert descriptor instanceof ClassDescriptor
264 : "Classifier descriptor of a type should be of type ClassDescriptor: " + typeConstructor;
265 return (ClassDescriptor) descriptor;
266 }
267
268 public static boolean isAny(@NotNull DeclarationDescriptor superClassDescriptor) {
269 return superClassDescriptor.equals(KotlinBuiltIns.getInstance().getAny());
270 }
271
272 public static boolean isEnumClassObject(@NotNull DeclarationDescriptor descriptor) {
273 if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.CLASS_OBJECT) {
274 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
275 if ((containing instanceof ClassDescriptor) && ((ClassDescriptor) containing).getKind() == ClassKind.ENUM_CLASS) {
276 return true;
277 }
278 }
279 return false;
280 }
281
282 public static boolean isSyntheticClassObject(@NotNull DeclarationDescriptor descriptor) {
283 if (isClassObject(descriptor)) {
284 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
285 if (containing != null) {
286 return isEnumClass(containing) || isObject(containing) || isEnumEntry(containing);
287 }
288 }
289 return false;
290 }
291
292 @NotNull
293 public static Visibility getDefaultConstructorVisibility(@NotNull ClassDescriptor classDescriptor) {
294 ClassKind classKind = classDescriptor.getKind();
295 if (classKind == ClassKind.ENUM_CLASS || classKind.isSingleton() || isAnonymousObject(classDescriptor)) {
296 return Visibilities.PRIVATE;
297 }
298 assert classKind == ClassKind.CLASS || classKind == ClassKind.TRAIT || classKind == ClassKind.ANNOTATION_CLASS;
299 return Visibilities.PUBLIC;
300 }
301
302 @NotNull
303 public static Visibility getSyntheticClassObjectVisibility() {
304 return Visibilities.PUBLIC;
305 }
306
307 @Nullable
308 public static ClassDescriptor getInnerClassByName(@NotNull ClassDescriptor classDescriptor, @NotNull String innerClassName) {
309 ClassifierDescriptor classifier = classDescriptor.getDefaultType().getMemberScope().getClassifier(Name.identifier(innerClassName));
310 assert classifier instanceof ClassDescriptor :
311 "Inner class " + innerClassName + " in " + classDescriptor + " should be instance of ClassDescriptor, but was: "
312 + (classifier == null ? "null" : classifier.getClass());
313 return (ClassDescriptor) classifier;
314 }
315
316 @Nullable
317 public static JetType getReceiverParameterType(@Nullable ReceiverParameterDescriptor receiverParameterDescriptor) {
318 return receiverParameterDescriptor == null ? null : receiverParameterDescriptor.getType();
319 }
320
321 public static boolean isConstructorOfStaticNestedClass(@Nullable CallableDescriptor descriptor) {
322 return descriptor instanceof ConstructorDescriptor && isStaticNestedClass(descriptor.getContainingDeclaration());
323 }
324
325 /**
326 * @return true if descriptor is a class inside another class and does not have access to the outer class
327 */
328 public static boolean isStaticNestedClass(@NotNull DeclarationDescriptor descriptor) {
329 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
330 return descriptor instanceof ClassDescriptor &&
331 containing instanceof ClassDescriptor &&
332 !((ClassDescriptor) descriptor).isInner();
333 }
334
335 @NotNull
336 public static JetScope getStaticNestedClassesScope(@NotNull ClassDescriptor descriptor) {
337 JetScope innerClassesScope = descriptor.getUnsubstitutedInnerClassesScope();
338 return new FilteringScope(innerClassesScope, new Predicate<DeclarationDescriptor>() {
339 @Override
340 public boolean apply(@Nullable DeclarationDescriptor descriptor) {
341 return descriptor instanceof ClassDescriptor && !((ClassDescriptor) descriptor).isInner();
342 }
343 });
344 }
345
346 public static boolean isEnumValueOfMethod(@NotNull FunctionDescriptor functionDescriptor) {
347 List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
348 JetType nullableString = TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getStringType());
349 return "valueOf".equals(functionDescriptor.getName().asString())
350 && methodTypeParameters.size() == 1
351 && JetTypeChecker.DEFAULT.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString);
352 }
353
354 public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor functionDescriptor) {
355 List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
356 return "values".equals(functionDescriptor.getName().asString())
357 && methodTypeParameters.isEmpty();
358 }
359
360 /**
361 * @return true iff {@code descriptor}'s first non-class container is a package
362 */
363 public static boolean isTopLevelOrInnerClass(@NotNull ClassDescriptor descriptor) {
364 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
365 return isTopLevelDeclaration(descriptor) ||
366 containing instanceof ClassDescriptor && isTopLevelOrInnerClass((ClassDescriptor) containing);
367 }
368
369 /**
370 * Given a fake override, finds any declaration of it in the overridden descriptors. Keep in mind that there may be many declarations
371 * of the fake override in the supertypes, this method finds just the only one.
372 * TODO: probably all call-sites of this method are wrong, they should handle all super-declarations
373 */
374 @NotNull
375 public static <D extends CallableMemberDescriptor> D unwrapFakeOverride(@NotNull D descriptor) {
376 while (descriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
377 Set<? extends CallableMemberDescriptor> overridden = descriptor.getOverriddenDescriptors();
378 if (overridden.isEmpty()) {
379 throw new IllegalStateException("Fake override should have at least one overridden descriptor: " + descriptor);
380 }
381 //noinspection unchecked
382 descriptor = (D) overridden.iterator().next();
383 }
384 return descriptor;
385 }
386
387 public static boolean shouldRecordInitializerForProperty(@NotNull VariableDescriptor variable, @NotNull JetType type) {
388 if (variable.isVar() || type.isError()) return false;
389
390 if (type instanceof LazyType || type.isNullable()) return true;
391
392 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
393 return builtIns.isPrimitiveType(type) ||
394 builtIns.getStringType().equals(type) ||
395 builtIns.getNumber().getDefaultType().equals(type) ||
396 builtIns.getAnyType().equals(type);
397 }
398 }