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