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