Java tutorial
/* * Copyright 2010-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jetbrains.jet.lang.resolve; import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetFunction; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.DescriptorSubstitutor; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import java.util.*; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; /** * @author abreslav */ public class DescriptorUtils { @NotNull public static <D extends CallableDescriptor> D substituteBounds(@NotNull final D functionDescriptor) { final List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters(); if (typeParameters.isEmpty()) return functionDescriptor; // TODO: this does not handle any recursion in the bounds @SuppressWarnings("unchecked") D substitutedFunction = (D) functionDescriptor .substitute(DescriptorSubstitutor.createUpperBoundsSubstitutor(typeParameters)); assert substitutedFunction != null : "Substituting upper bounds should always be legal"; return substitutedFunction; } public static Modality convertModality(Modality modality, boolean makeNonAbstract) { if (makeNonAbstract && modality == Modality.ABSTRACT) return Modality.OPEN; return modality; } @NotNull public static ReceiverDescriptor getExpectedThisObjectIfNeeded( @NotNull DeclarationDescriptor containingDeclaration) { if (containingDeclaration instanceof ClassDescriptor) { ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; return classDescriptor.getImplicitReceiver(); } else if (containingDeclaration instanceof ScriptDescriptor) { ScriptDescriptor scriptDescriptor = (ScriptDescriptor) containingDeclaration; return scriptDescriptor.getImplicitReceiver(); } return NO_RECEIVER; } /** * The primary case for local extensions is the following: * * I had a locally declared extension function or a local variable of function type called foo * And I called it on my x * Now, someone added function foo() to the class of x * My code should not change * * thus * * local extension prevail over members (and members prevail over all non-local extensions) */ public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) { if (candidate instanceof ValueParameterDescriptor) { return true; } DeclarationDescriptor parent = candidate.getContainingDeclaration(); if (!(parent instanceof FunctionDescriptor)) { return false; } FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent; DeclarationDescriptor current = containerOfTheCurrentLocality; while (current != null) { if (current == functionDescriptor) { return true; } current = current.getContainingDeclaration(); } return false; } @NotNull public static FqNameUnsafe getFQName(@NotNull DeclarationDescriptor descriptor) { DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); if (descriptor instanceof ModuleDescriptor || containingDeclaration instanceof ModuleDescriptor) { return FqName.ROOT.toUnsafe(); } if (containingDeclaration == null) { if (descriptor instanceof NamespaceDescriptor) { // TODO: namespace must always have parent if (descriptor.getName().equals(Name.identifier("jet"))) { return FqNameUnsafe.topLevel(Name.identifier("jet")); } if (descriptor.getName().equals(Name.special("<java_root>"))) { return FqName.ROOT.toUnsafe(); } } throw new IllegalStateException( "descriptor is not module descriptor and has null containingDeclaration: " + containingDeclaration); } return getFQName(containingDeclaration).child(descriptor.getName()); } public static boolean isTopLevelDeclaration(@NotNull DeclarationDescriptor descriptor) { return descriptor.getContainingDeclaration() instanceof NamespaceDescriptor; } @Nullable public static DeclarationDescriptor findTopLevelParent(@NotNull DeclarationDescriptor declarationDescriptor) { DeclarationDescriptor descriptor = declarationDescriptor; while (!(descriptor == null || isTopLevelDeclaration(descriptor))) { descriptor = descriptor.getContainingDeclaration(); } return descriptor; } @Nullable public static <D extends DeclarationDescriptor> D getParentOfType(@Nullable DeclarationDescriptor descriptor, @NotNull Class<D> aClass) { return getParentOfType(descriptor, aClass, true); } @Nullable public static <D extends DeclarationDescriptor> D getParentOfType(@Nullable DeclarationDescriptor descriptor, @NotNull Class<D> aClass, boolean strict) { if (descriptor == null) return null; if (strict) { descriptor = descriptor.getContainingDeclaration(); } while (descriptor != null) { if (aClass.isInstance(descriptor)) { //noinspection unchecked return (D) descriptor; } descriptor = descriptor.getContainingDeclaration(); } return null; } public static boolean isAncestor(@Nullable DeclarationDescriptor ancestor, @NotNull DeclarationDescriptor declarationDescriptor, boolean strict) { if (ancestor == null) return false; DeclarationDescriptor descriptor = strict ? declarationDescriptor.getContainingDeclaration() : declarationDescriptor; while (descriptor != null) { if (ancestor == descriptor) return true; descriptor = descriptor.getContainingDeclaration(); } return false; } @Nullable public static VariableDescriptor filterNonExtensionProperty(Collection<VariableDescriptor> variables) { for (VariableDescriptor variable : variables) { if (!variable.getReceiverParameter().exists()) { return variable; } } return null; } @NotNull public static JetType getFunctionExpectedReturnType(@NotNull FunctionDescriptor descriptor, @NotNull JetElement function) { JetType expectedType; if (function instanceof JetFunction) { if (((JetFunction) function).getReturnTypeRef() != null || ((JetFunction) function).hasBlockBody()) { expectedType = descriptor.getReturnType(); } else { expectedType = TypeUtils.NO_EXPECTED_TYPE; } } else { expectedType = descriptor.getReturnType(); } return expectedType != null ? expectedType : TypeUtils.NO_EXPECTED_TYPE; } public static boolean isSubclass(@NotNull ClassDescriptor subClass, @NotNull ClassDescriptor superClass) { return isSubtypeOfClass(subClass.getDefaultType(), superClass.getOriginal()); } private static boolean isSubtypeOfClass(@NotNull JetType type, @NotNull DeclarationDescriptor superClass) { DeclarationDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); if (descriptor != null && superClass == descriptor.getOriginal()) { return true; } for (JetType superType : type.getConstructor().getSupertypes()) { if (isSubtypeOfClass(superType, superClass)) { return true; } } return false; } public static void addSuperTypes(JetType type, Set<JetType> set) { set.add(type); for (JetType jetType : type.getConstructor().getSupertypes()) { addSuperTypes(jetType, set); } } public static boolean isTopLevelNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { return namespaceDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor && namespaceDescriptor .getContainingDeclaration().getContainingDeclaration() instanceof ModuleDescriptor; } public static boolean isRootNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { return namespaceDescriptor.getContainingDeclaration() instanceof ModuleDescriptor; } @NotNull public static List<DeclarationDescriptor> getPathWithoutRootNsAndModule( @NotNull DeclarationDescriptor descriptor) { List<DeclarationDescriptor> path = Lists.newArrayList(); DeclarationDescriptor current = descriptor; while (true) { if (current instanceof NamespaceDescriptor && isRootNamespace((NamespaceDescriptor) current)) { return Lists.reverse(path); } path.add(current); current = current.getContainingDeclaration(); } } public static boolean isClassObject(@NotNull DeclarationDescriptor descriptor) { return descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.CLASS_OBJECT; } public static boolean isEnumEntry(@NotNull DeclarationDescriptor descriptor) { return descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.ENUM_ENTRY; } @NotNull public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) { Collection<? extends JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes(); List<ClassDescriptor> superClassDescriptors = new ArrayList<ClassDescriptor>(); for (JetType type : superclassTypes) { ClassDescriptor result = getClassDescriptorForType(type); if (isNotAny(result)) { superClassDescriptors.add(result); } } return superClassDescriptors; } @NotNull public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) { DeclarationDescriptor superClassDescriptor = type.getConstructor().getDeclarationDescriptor(); assert superClassDescriptor instanceof ClassDescriptor : "Superclass descriptor of a type should be of type ClassDescriptor"; return (ClassDescriptor) superClassDescriptor; } public static boolean isNotAny(@NotNull DeclarationDescriptor superClassDescriptor) { return !superClassDescriptor.equals(KotlinBuiltIns.getInstance().getAny()); } public static boolean inStaticContext(@NotNull DeclarationDescriptor descriptor) { DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); if (containingDeclaration instanceof NamespaceDescriptor) { return true; } if (containingDeclaration instanceof ClassDescriptor) { ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; if (classDescriptor.getKind().isObject()) { return inStaticContext(classDescriptor.getContainingDeclaration()); } } return false; } public static boolean isIteratorWithoutRemoveImpl(@NotNull ClassDescriptor classDescriptor) { ClassDescriptor iteratorOfT = KotlinBuiltIns.getInstance().getIterator(); JetType iteratorOfAny = TypeUtils.substituteParameters(iteratorOfT, Collections.singletonList(KotlinBuiltIns.getInstance().getAnyType())); boolean isIterator = JetTypeChecker.INSTANCE.isSubtypeOf(classDescriptor.getDefaultType(), iteratorOfAny); boolean hasRemove = hasMethod(classDescriptor, Name.identifier("remove")); return isIterator && !hasRemove; } private static boolean hasMethod(ClassDescriptor classDescriptor, Name name) { Collection<FunctionDescriptor> removeFunctions = classDescriptor.getDefaultType().getMemberScope() .getFunctions(name); for (FunctionDescriptor function : removeFunctions) { if (function.getValueParameters().isEmpty() && function.getTypeParameters().isEmpty()) { return true; } } return false; } @NotNull public static Name getClassObjectName(@NotNull Name className) { return getClassObjectName(className.getName()); } @NotNull public static Name getClassObjectName(@NotNull String className) { return Name.special("<class-object-for-" + className + ">"); } public static boolean isEnumClassObject(@NotNull DeclarationDescriptor classObjectDescriptor) { DeclarationDescriptor containingDeclaration = classObjectDescriptor.getContainingDeclaration(); return ((containingDeclaration instanceof ClassDescriptor) && ((ClassDescriptor) containingDeclaration).getKind() == ClassKind.ENUM_CLASS); } @NotNull public static Visibility getDefaultConstructorVisibility(@NotNull ClassDescriptor classDescriptor) { ClassKind classKind = classDescriptor.getKind(); if (classKind == ClassKind.ENUM_CLASS) { return Visibilities.PRIVATE; } if (classKind.isObject()) { return Visibilities.PRIVATE; } assert classKind == ClassKind.CLASS || classKind == ClassKind.TRAIT || classKind == ClassKind.ANNOTATION_CLASS; return Visibilities.PUBLIC; } public static List<String> getSortedValueArguments(AnnotationDescriptor descriptor) { List<String> resultList = Lists.newArrayList(); for (Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>> entry : descriptor.getAllValueArguments() .entrySet()) { resultList.add(entry.getKey().getName().getName() + " = " + entry.getValue().toString()); } Collections.sort(resultList); return resultList; } @Nullable public static ClassDescriptor getInnerClassByName(@NotNull ClassDescriptor classDescriptor, @NotNull String innerClassName) { ClassifierDescriptor classifier = classDescriptor.getDefaultType().getMemberScope() .getClassifier(Name.identifier(innerClassName)); assert classifier instanceof ClassDescriptor : "Inner class " + innerClassName + " in " + classDescriptor + " should be instance of ClassDescriptor, but was: " + (classifier == null ? "null" : classifier.getClass()); return (ClassDescriptor) classifier; } @SuppressWarnings("unchecked") public static Collection<ClassDescriptor> getInnerClasses(ClassDescriptor classDescriptor) { Collection<DeclarationDescriptor> innerClasses = classDescriptor.getUnsubstitutedInnerClassesScope() .getAllDescriptors(); for (DeclarationDescriptor inner : innerClasses) { assert inner instanceof ClassDescriptor : "Not a class in inner classes scope of " + classDescriptor + ": " + inner; } return (Collection) innerClasses; } }