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.lang.resolve;
018    
019    import com.google.common.base.Predicate;
020    import com.google.common.collect.Lists;
021    import com.google.common.collect.Sets;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.jet.lang.descriptors.*;
025    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
026    import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
027    import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
028    import org.jetbrains.jet.lang.resolve.name.FqName;
029    import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
030    import org.jetbrains.jet.lang.resolve.name.Name;
031    import org.jetbrains.jet.lang.resolve.name.SpecialNames;
032    import org.jetbrains.jet.lang.resolve.scopes.FilteringScope;
033    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
034    import org.jetbrains.jet.lang.types.*;
035    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
036    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
037    import org.jetbrains.jet.renderer.DescriptorRenderer;
038    
039    import java.util.*;
040    
041    import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
042    
043    public class DescriptorUtils {
044        private DescriptorUtils() {
045        }
046    
047        @NotNull
048        public static <D extends CallableDescriptor> D substituteBounds(@NotNull D functionDescriptor) {
049            List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
050            if (typeParameters.isEmpty()) return functionDescriptor;
051    
052            // TODO: this does not handle any recursion in the bounds
053            @SuppressWarnings("unchecked")
054            D substitutedFunction = (D) functionDescriptor.substitute(DescriptorSubstitutor.createUpperBoundsSubstitutor(typeParameters));
055            assert substitutedFunction != null : "Substituting upper bounds should always be legal";
056    
057            return substitutedFunction;
058        }
059    
060        @NotNull
061        public static Modality convertModality(@NotNull Modality modality, boolean makeNonAbstract) {
062            if (makeNonAbstract && modality == Modality.ABSTRACT) return Modality.OPEN;
063            return modality;
064        }
065    
066        @Nullable
067        public static ReceiverParameterDescriptor getExpectedThisObjectIfNeeded(@NotNull DeclarationDescriptor containingDeclaration) {
068            if (containingDeclaration instanceof ClassDescriptor) {
069                ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
070                return classDescriptor.getThisAsReceiverParameter();
071            }
072            else if (containingDeclaration instanceof ScriptDescriptor) {
073                ScriptDescriptor scriptDescriptor = (ScriptDescriptor) containingDeclaration;
074                return scriptDescriptor.getThisAsReceiverParameter();
075            }
076            return NO_RECEIVER_PARAMETER;
077        }
078    
079        /**
080         * The primary case for local extensions is the following:
081         *
082         * I had a locally declared extension function or a local variable of function type called foo
083         * And I called it on my x
084         * Now, someone added function foo() to the class of x
085         * My code should not change
086         *
087         * thus
088         *
089         * local extension prevail over members (and members prevail over all non-local extensions)
090         */
091        public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) {
092            if (candidate instanceof ValueParameterDescriptor) {
093                return true;
094            }
095            DeclarationDescriptor parent = candidate.getContainingDeclaration();
096            if (!(parent instanceof FunctionDescriptor)) {
097                return false;
098            }
099            FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent;
100            DeclarationDescriptor current = containerOfTheCurrentLocality;
101            while (current != null) {
102                if (current == functionDescriptor) {
103                    return true;
104                }
105                current = current.getContainingDeclaration();
106            }
107            return false;
108        }
109    
110        @NotNull
111        public static FqNameUnsafe getFQName(@NotNull DeclarationDescriptor descriptor) {
112            DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
113    
114            if (descriptor instanceof ModuleDescriptor || containingDeclaration instanceof ModuleDescriptor) {
115                return FqName.ROOT.toUnsafe();
116            }
117    
118            if (containingDeclaration == null) {
119                if (descriptor instanceof NamespaceDescriptor) {
120                    // TODO: namespace must always have parent
121                    if (descriptor.getName().equals(Name.identifier("jet"))) {
122                        return FqNameUnsafe.topLevel(Name.identifier("jet"));
123                    }
124                    if (descriptor.getName().equals(Name.special("<java_root>"))) {
125                        return FqName.ROOT.toUnsafe();
126                    }
127                }
128                throw new IllegalStateException("descriptor is not module descriptor and has null containingDeclaration: " + descriptor);
129            }
130    
131            if (containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).getKind() == ClassKind.CLASS_OBJECT) {
132                DeclarationDescriptor classOfClassObject = containingDeclaration.getContainingDeclaration();
133                assert classOfClassObject != null;
134                return getFQName(classOfClassObject).child(descriptor.getName());
135            }
136    
137            return getFQName(containingDeclaration).child(descriptor.getName());
138        }
139    
140        public static boolean isTopLevelDeclaration(@NotNull DeclarationDescriptor descriptor) {
141            return descriptor.getContainingDeclaration() instanceof NamespaceDescriptor;
142        }
143    
144        public static boolean isInSameModule(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) {
145            ModuleDescriptor parentModule = getParentOfType(first, ModuleDescriptorImpl.class, false);
146            ModuleDescriptor fromModule = getParentOfType(second, ModuleDescriptorImpl.class, false);
147            assert parentModule != null && fromModule != null;
148            return parentModule.equals(fromModule);
149        }
150    
151        @Nullable
152        public static DeclarationDescriptor findTopLevelParent(@NotNull DeclarationDescriptor declarationDescriptor) {
153            DeclarationDescriptor descriptor = declarationDescriptor;
154            if (declarationDescriptor instanceof PropertyAccessorDescriptor) {
155                descriptor = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty();
156            }
157            while (!(descriptor == null || isTopLevelDeclaration(descriptor))) {
158                descriptor = descriptor.getContainingDeclaration();
159            }
160            return descriptor;
161        }
162    
163        @Nullable
164        public static <D extends DeclarationDescriptor> D getParentOfType(
165                @Nullable DeclarationDescriptor descriptor,
166                @NotNull Class<D> aClass
167        ) {
168            return getParentOfType(descriptor, aClass, true);
169        }
170    
171        @Nullable
172        public static <D extends DeclarationDescriptor> D getParentOfType(
173                @Nullable DeclarationDescriptor descriptor,
174                @NotNull Class<D> aClass,
175                boolean strict
176        ) {
177            if (descriptor == null) return null;
178            if (strict) {
179                descriptor = descriptor.getContainingDeclaration();
180            }
181            while (descriptor != null) {
182                if (aClass.isInstance(descriptor)) {
183                    //noinspection unchecked
184                    return (D) descriptor;
185                }
186                descriptor = descriptor.getContainingDeclaration();
187            }
188            return null;
189        }
190    
191        public static boolean isAncestor(
192                @Nullable DeclarationDescriptor ancestor,
193                @NotNull DeclarationDescriptor declarationDescriptor,
194                boolean strict
195        ) {
196            if (ancestor == null) return false;
197            DeclarationDescriptor descriptor = strict ? declarationDescriptor.getContainingDeclaration() : declarationDescriptor;
198            while (descriptor != null) {
199                if (ancestor == descriptor) return true;
200                descriptor = descriptor.getContainingDeclaration();
201            }
202            return false;
203        }
204    
205        public static boolean isSubclass(@NotNull ClassDescriptor subClass, @NotNull ClassDescriptor superClass) {
206            return isSubtypeOfClass(subClass.getDefaultType(), superClass.getOriginal());
207        }
208    
209        private static boolean isSubtypeOfClass(@NotNull JetType type, @NotNull DeclarationDescriptor superClass) {
210            DeclarationDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
211            if (descriptor != null && superClass == descriptor.getOriginal()) {
212                return true;
213            }
214            for (JetType superType : type.getConstructor().getSupertypes()) {
215                if (isSubtypeOfClass(superType, superClass)) {
216                    return true;
217                }
218            }
219            return false;
220        }
221    
222        public static boolean isRootNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) {
223            return namespaceDescriptor.getContainingDeclaration() instanceof ModuleDescriptor;
224        }
225    
226        public static boolean isFunctionLiteral(@NotNull FunctionDescriptor descriptor) {
227            return descriptor instanceof AnonymousFunctionDescriptor;
228        }
229    
230        public static boolean isClassObject(@NotNull 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(@NotNull 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(@NotNull DeclarationDescriptor descriptor) {
263            return isKindOf(descriptor, ClassKind.TRAIT);
264        }
265    
266        public static boolean isClass(@NotNull DeclarationDescriptor descriptor) {
267            return isKindOf(descriptor, ClassKind.CLASS);
268        }
269    
270        public static boolean isKindOf(@Nullable DeclarationDescriptor descriptor, @NotNull ClassKind classKind) {
271            return descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == classKind;
272        }
273    
274        @NotNull
275        public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) {
276            Collection<JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes();
277            List<ClassDescriptor> superClassDescriptors = new ArrayList<ClassDescriptor>();
278            for (JetType type : superclassTypes) {
279                ClassDescriptor result = getClassDescriptorForType(type);
280                if (!isAny(result)) {
281                    superClassDescriptors.add(result);
282                }
283            }
284            return superClassDescriptors;
285        }
286    
287        @NotNull
288        public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) {
289            return getClassDescriptorForTypeConstructor(type.getConstructor());
290        }
291    
292        @NotNull
293        public static ClassDescriptor getClassDescriptorForTypeConstructor(@NotNull TypeConstructor typeConstructor) {
294            ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor();
295            assert descriptor instanceof ClassDescriptor
296                : "Classifier descriptor of a type should be of type ClassDescriptor: " + typeConstructor;
297            return (ClassDescriptor) descriptor;
298        }
299    
300        public static boolean isAny(@NotNull DeclarationDescriptor superClassDescriptor) {
301            return superClassDescriptor.equals(KotlinBuiltIns.getInstance().getAny());
302        }
303    
304        public static boolean inStaticContext(@NotNull DeclarationDescriptor descriptor) {
305            DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
306            if (containingDeclaration instanceof NamespaceDescriptor) {
307                return true;
308            }
309            if (containingDeclaration instanceof ClassDescriptor) {
310                ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
311    
312                if (classDescriptor.getKind().isSingleton()) {
313                    return inStaticContext(classDescriptor.getContainingDeclaration());
314                }
315    
316            }
317            return false;
318        }
319    
320        public static boolean isEnumClassObject(@NotNull DeclarationDescriptor descriptor) {
321            if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.CLASS_OBJECT) {
322                DeclarationDescriptor containing = descriptor.getContainingDeclaration();
323                if ((containing instanceof ClassDescriptor) && ((ClassDescriptor) containing).getKind() == ClassKind.ENUM_CLASS) {
324                    return true;
325                }
326            }
327            return false;
328        }
329    
330        public static boolean isSyntheticClassObject(@NotNull DeclarationDescriptor descriptor) {
331            if (isClassObject(descriptor)) {
332                DeclarationDescriptor containing = descriptor.getContainingDeclaration();
333                if (containing != null) {
334                    return isEnumClass(containing) || isObject(containing) || isEnumEntry(containing);
335                }
336            }
337            return false;
338        }
339    
340        @NotNull
341        public static Visibility getDefaultConstructorVisibility(@NotNull ClassDescriptor classDescriptor) {
342            ClassKind classKind = classDescriptor.getKind();
343            if (classKind == ClassKind.ENUM_CLASS || classKind.isSingleton() || isAnonymousObject(classDescriptor)) {
344                return Visibilities.PRIVATE;
345            }
346            assert classKind == ClassKind.CLASS || classKind == ClassKind.TRAIT || classKind == ClassKind.ANNOTATION_CLASS;
347            return Visibilities.PUBLIC;
348        }
349    
350        @NotNull
351        public static Visibility getSyntheticClassObjectVisibility() {
352            return Visibilities.PUBLIC;
353        }
354    
355        @NotNull
356        public static List<String> getSortedValueArguments(
357                @NotNull AnnotationDescriptor descriptor,
358                @Nullable DescriptorRenderer rendererForTypesIfNecessary
359        ) {
360            List<String> resultList = Lists.newArrayList();
361            for (Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>> entry : descriptor.getAllValueArguments().entrySet()) {
362                CompileTimeConstant<?> value = entry.getValue();
363                String typeSuffix = rendererForTypesIfNecessary == null
364                                    ? ""
365                                    : ": " + rendererForTypesIfNecessary.renderType(value.getType(KotlinBuiltIns.getInstance()));
366                resultList.add(entry.getKey().getName().asString() + " = " + value.toString() + typeSuffix);
367            }
368            Collections.sort(resultList);
369            return resultList;
370        }
371    
372        @Nullable
373        public static ClassDescriptor getInnerClassByName(@NotNull ClassDescriptor classDescriptor, @NotNull String innerClassName) {
374            ClassifierDescriptor classifier = classDescriptor.getDefaultType().getMemberScope().getClassifier(Name.identifier(innerClassName));
375            assert classifier instanceof ClassDescriptor :
376                    "Inner class " + innerClassName + " in " + classDescriptor + " should be instance of ClassDescriptor, but was: "
377                    + (classifier == null ? "null" : classifier.getClass());
378            return (ClassDescriptor) classifier;
379        }
380    
381        @NotNull
382        public static ConstructorDescriptor getConstructorOfDataClass(ClassDescriptor classDescriptor) {
383            ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor);
384            assert descriptor != null : "Data class must have only one constructor: " + classDescriptor.getConstructors();
385            return descriptor;
386        }
387    
388        @NotNull
389        public static ConstructorDescriptor getConstructorOfSingletonObject(ClassDescriptor classDescriptor) {
390            ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor);
391            assert descriptor != null : "Class of singleton object must have only one constructor: " + classDescriptor.getConstructors();
392            return descriptor;
393        }
394    
395        @Nullable
396        private static ConstructorDescriptor getConstructorDescriptorIfOnlyOne(ClassDescriptor classDescriptor) {
397            Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
398            return constructors.size() != 1 ? null : constructors.iterator().next();
399        }
400    
401        @Nullable
402        public static JetType getReceiverParameterType(@Nullable ReceiverParameterDescriptor receiverParameterDescriptor) {
403            if (receiverParameterDescriptor == null) {
404                return null;
405            }
406            return receiverParameterDescriptor.getType();
407        }
408    
409        @NotNull
410        public static JetType getVarargParameterType(@NotNull JetType elementType) {
411            JetType primitiveArrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(elementType);
412            return primitiveArrayType != null ? primitiveArrayType : KotlinBuiltIns.getInstance().getArrayType(Variance.INVARIANT, elementType);
413        }
414    
415        @NotNull
416        public static List<JetType> getValueParametersTypes(@NotNull List<ValueParameterDescriptor> valueParameters) {
417            List<JetType> parameterTypes = Lists.newArrayList();
418            for (ValueParameterDescriptor parameter : valueParameters) {
419                parameterTypes.add(parameter.getType());
420            }
421            return parameterTypes;
422        }
423    
424        public static boolean isConstructorOfStaticNestedClass(@Nullable CallableDescriptor descriptor) {
425            return descriptor instanceof ConstructorDescriptor && isStaticNestedClass(descriptor.getContainingDeclaration());
426        }
427    
428        /**
429         * @return true if descriptor is a class inside another class and does not have access to the outer class
430         */
431        public static boolean isStaticNestedClass(@NotNull DeclarationDescriptor descriptor) {
432            DeclarationDescriptor containing = descriptor.getContainingDeclaration();
433            return descriptor instanceof ClassDescriptor &&
434                   containing instanceof ClassDescriptor &&
435                   !((ClassDescriptor) descriptor).isInner() &&
436                   !((ClassDescriptor) containing).getKind().isSingleton();
437        }
438    
439        @Nullable
440        public static ClassDescriptor getContainingClass(@NotNull JetScope scope) {
441            DeclarationDescriptor containingDeclaration = scope.getContainingDeclaration();
442            return getParentOfType(containingDeclaration, ClassDescriptor.class, false);
443        }
444    
445        @NotNull
446        public static JetScope getStaticNestedClassesScope(@NotNull ClassDescriptor descriptor) {
447            JetScope innerClassesScope = descriptor.getUnsubstitutedInnerClassesScope();
448            return new FilteringScope(innerClassesScope, new Predicate<DeclarationDescriptor>() {
449                @Override
450                public boolean apply(@Nullable DeclarationDescriptor descriptor) {
451                    return descriptor instanceof ClassDescriptor && !((ClassDescriptor) descriptor).isInner();
452                }
453            });
454        }
455    
456        public static boolean isEnumValueOfMethod(@NotNull FunctionDescriptor functionDescriptor) {
457            List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
458            JetType nullableString = TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getStringType());
459            return "valueOf".equals(functionDescriptor.getName().asString())
460                   && methodTypeParameters.size() == 1
461                   && JetTypeChecker.INSTANCE.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString);
462        }
463    
464        public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor functionDescriptor) {
465            List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
466            return "values".equals(functionDescriptor.getName().asString())
467                   && methodTypeParameters.isEmpty();
468        }
469    
470        @NotNull
471        public static Set<ClassDescriptor> getAllSuperClasses(@NotNull ClassDescriptor klass) {
472            Set<JetType> allSupertypes = TypeUtils.getAllSupertypes(klass.getDefaultType());
473            Set<ClassDescriptor> allSuperclasses = Sets.newHashSet();
474            for (JetType supertype : allSupertypes) {
475                ClassDescriptor superclass = TypeUtils.getClassDescriptor(supertype);
476                assert superclass != null;
477                allSuperclasses.add(superclass);
478            }
479            return allSuperclasses;
480        }
481    
482        /**
483         * @return true iff {@code descriptor}'s first non-class container is a namespace
484         */
485        public static boolean isTopLevelOrInnerClass(@NotNull ClassDescriptor descriptor) {
486            DeclarationDescriptor containing = descriptor.getContainingDeclaration();
487            return isTopLevelDeclaration(descriptor) ||
488                   containing instanceof ClassDescriptor && isTopLevelOrInnerClass((ClassDescriptor) containing);
489        }
490    }