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