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 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.impl.AnonymousFunctionDescriptor; 026 import org.jetbrains.jet.lang.resolve.name.FqName; 027 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; 028 import org.jetbrains.jet.lang.resolve.name.Name; 029 import org.jetbrains.jet.lang.resolve.name.SpecialNames; 030 import org.jetbrains.jet.lang.resolve.scopes.FilteringScope; 031 import org.jetbrains.jet.lang.resolve.scopes.JetScope; 032 import org.jetbrains.jet.lang.types.*; 033 import org.jetbrains.jet.lang.types.checker.JetTypeChecker; 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 @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 @Nullable 061 public static ReceiverParameterDescriptor getExpectedThisObjectIfNeeded(@NotNull DeclarationDescriptor containingDeclaration) { 062 if (containingDeclaration instanceof ClassDescriptor) { 063 ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; 064 return classDescriptor.getThisAsReceiverParameter(); 065 } 066 else if (containingDeclaration instanceof ScriptDescriptor) { 067 ScriptDescriptor scriptDescriptor = (ScriptDescriptor) containingDeclaration; 068 return scriptDescriptor.getThisAsReceiverParameter(); 069 } 070 return NO_RECEIVER_PARAMETER; 071 } 072 073 /** 074 * The primary case for local extensions is the following: 075 * 076 * I had a locally declared extension function or a local variable of function type called foo 077 * And I called it on my x 078 * Now, someone added function foo() to the class of x 079 * My code should not change 080 * 081 * thus 082 * 083 * local extension prevail over members (and members prevail over all non-local extensions) 084 */ 085 public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) { 086 if (candidate instanceof ValueParameterDescriptor) { 087 return true; 088 } 089 DeclarationDescriptor parent = candidate.getContainingDeclaration(); 090 if (!(parent instanceof FunctionDescriptor)) { 091 return false; 092 } 093 FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent; 094 DeclarationDescriptor current = containerOfTheCurrentLocality; 095 while (current != null) { 096 if (current == functionDescriptor) { 097 return true; 098 } 099 current = current.getContainingDeclaration(); 100 } 101 return false; 102 } 103 104 @NotNull 105 public static FqNameUnsafe getFqName(@NotNull DeclarationDescriptor descriptor) { 106 FqName safe = getFqNameSafeIfPossible(descriptor); 107 return safe != null ? safe.toUnsafe() : getFqNameUnsafe(descriptor); 108 } 109 110 @NotNull 111 public static FqName getFqNameSafe(@NotNull DeclarationDescriptor descriptor) { 112 FqName safe = getFqNameSafeIfPossible(descriptor); 113 return safe != null ? safe : getFqNameUnsafe(descriptor).toSafe(); 114 } 115 116 117 @Nullable 118 private static FqName getFqNameSafeIfPossible(@NotNull DeclarationDescriptor descriptor) { 119 if (descriptor instanceof ModuleDescriptor || ErrorUtils.isError(descriptor)) { 120 return FqName.ROOT; 121 } 122 123 if (descriptor instanceof PackageViewDescriptor) { 124 return ((PackageViewDescriptor) descriptor).getFqName(); 125 } 126 else if (descriptor instanceof PackageFragmentDescriptor) { 127 return ((PackageFragmentDescriptor) descriptor).getFqName(); 128 } 129 130 return null; 131 } 132 133 @NotNull 134 private static FqNameUnsafe getFqNameUnsafe(@NotNull DeclarationDescriptor descriptor) { 135 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 136 137 if (containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).getKind() == ClassKind.CLASS_OBJECT) { 138 DeclarationDescriptor classOfClassObject = containingDeclaration.getContainingDeclaration(); 139 assert classOfClassObject != null; 140 return getFqName(classOfClassObject).child(descriptor.getName()); 141 } 142 143 return getFqName(containingDeclaration).child(descriptor.getName()); 144 } 145 146 public static boolean isTopLevelDeclaration(@NotNull DeclarationDescriptor descriptor) { 147 return descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor; 148 } 149 150 public static boolean areInSameModule(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) { 151 return getContainingModule(first).equals(getContainingModule(second)); 152 } 153 154 @Nullable 155 public static DeclarationDescriptor findTopLevelParent(@NotNull DeclarationDescriptor declarationDescriptor) { 156 DeclarationDescriptor descriptor = declarationDescriptor; 157 if (declarationDescriptor instanceof PropertyAccessorDescriptor) { 158 descriptor = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty(); 159 } 160 while (!(descriptor == null || isTopLevelDeclaration(descriptor))) { 161 descriptor = descriptor.getContainingDeclaration(); 162 } 163 return descriptor; 164 } 165 166 @Nullable 167 public static <D extends DeclarationDescriptor> D getParentOfType( 168 @Nullable DeclarationDescriptor descriptor, 169 @NotNull Class<D> aClass 170 ) { 171 return getParentOfType(descriptor, aClass, true); 172 } 173 174 @Nullable 175 public static <D extends DeclarationDescriptor> D getParentOfType( 176 @Nullable DeclarationDescriptor descriptor, 177 @NotNull Class<D> aClass, 178 boolean strict 179 ) { 180 if (descriptor == null) return null; 181 if (strict) { 182 descriptor = descriptor.getContainingDeclaration(); 183 } 184 while (descriptor != null) { 185 if (aClass.isInstance(descriptor)) { 186 //noinspection unchecked 187 return (D) descriptor; 188 } 189 descriptor = descriptor.getContainingDeclaration(); 190 } 191 return null; 192 } 193 194 @NotNull 195 public static ModuleDescriptor getContainingModule(@NotNull DeclarationDescriptor descriptor) { 196 ModuleDescriptor module = getParentOfType(descriptor, ModuleDescriptor.class, false); 197 assert module != null : "Descriptor without a containing module: " + descriptor; 198 return module; 199 } 200 201 public static boolean isAncestor( 202 @Nullable DeclarationDescriptor ancestor, 203 @NotNull DeclarationDescriptor declarationDescriptor, 204 boolean strict 205 ) { 206 if (ancestor == null) return false; 207 DeclarationDescriptor descriptor = strict ? declarationDescriptor.getContainingDeclaration() : declarationDescriptor; 208 while (descriptor != null) { 209 if (ancestor == descriptor) return true; 210 descriptor = descriptor.getContainingDeclaration(); 211 } 212 return false; 213 } 214 215 public static boolean isSubclass(@NotNull ClassDescriptor subClass, @NotNull ClassDescriptor superClass) { 216 return isSubtypeOfClass(subClass.getDefaultType(), superClass.getOriginal()); 217 } 218 219 private static boolean isSubtypeOfClass(@NotNull JetType type, @NotNull DeclarationDescriptor superClass) { 220 DeclarationDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); 221 if (descriptor != null && superClass == descriptor.getOriginal()) { 222 return true; 223 } 224 for (JetType superType : type.getConstructor().getSupertypes()) { 225 if (isSubtypeOfClass(superType, superClass)) { 226 return true; 227 } 228 } 229 return false; 230 } 231 232 public static boolean isFunctionLiteral(@NotNull FunctionDescriptor descriptor) { 233 return descriptor instanceof AnonymousFunctionDescriptor; 234 } 235 236 public static boolean isClassObject(@NotNull DeclarationDescriptor descriptor) { 237 return isKindOf(descriptor, ClassKind.CLASS_OBJECT); 238 } 239 240 public static boolean isAnonymousObject(@NotNull DeclarationDescriptor descriptor) { 241 return isClass(descriptor) && descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED); 242 } 243 244 public static boolean isObject(@NotNull DeclarationDescriptor descriptor) { 245 return isKindOf(descriptor, ClassKind.OBJECT); 246 } 247 248 public static boolean isEnumEntry(@NotNull DeclarationDescriptor descriptor) { 249 return isKindOf(descriptor, ClassKind.ENUM_ENTRY); 250 } 251 252 public static boolean isSingleton(@Nullable DeclarationDescriptor classifier) { 253 if (classifier instanceof ClassDescriptor) { 254 ClassDescriptor clazz = (ClassDescriptor) classifier; 255 return clazz.getKind().isSingleton(); 256 } 257 return false; 258 } 259 260 public static boolean isEnumClass(@NotNull DeclarationDescriptor descriptor) { 261 return isKindOf(descriptor, ClassKind.ENUM_CLASS); 262 } 263 264 public static boolean isAnnotationClass(@Nullable DeclarationDescriptor descriptor) { 265 return isKindOf(descriptor, ClassKind.ANNOTATION_CLASS); 266 } 267 268 public static boolean isTrait(@Nullable DeclarationDescriptor descriptor) { 269 return isKindOf(descriptor, ClassKind.TRAIT); 270 } 271 272 public static boolean isClass(@Nullable DeclarationDescriptor descriptor) { 273 return isKindOf(descriptor, ClassKind.CLASS); 274 } 275 276 public static boolean isKindOf(@Nullable DeclarationDescriptor descriptor, @NotNull ClassKind classKind) { 277 return descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == classKind; 278 } 279 280 @NotNull 281 public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) { 282 Collection<JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes(); 283 List<ClassDescriptor> superClassDescriptors = new ArrayList<ClassDescriptor>(); 284 for (JetType type : superclassTypes) { 285 ClassDescriptor result = getClassDescriptorForType(type); 286 if (!isAny(result)) { 287 superClassDescriptors.add(result); 288 } 289 } 290 return superClassDescriptors; 291 } 292 293 @NotNull 294 public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) { 295 return getClassDescriptorForTypeConstructor(type.getConstructor()); 296 } 297 298 @NotNull 299 public static ClassDescriptor getClassDescriptorForTypeConstructor(@NotNull TypeConstructor typeConstructor) { 300 ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor(); 301 assert descriptor instanceof ClassDescriptor 302 : "Classifier descriptor of a type should be of type ClassDescriptor: " + typeConstructor; 303 return (ClassDescriptor) descriptor; 304 } 305 306 public static boolean isAny(@NotNull DeclarationDescriptor superClassDescriptor) { 307 return superClassDescriptor.equals(KotlinBuiltIns.getInstance().getAny()); 308 } 309 310 public static boolean isEnumClassObject(@NotNull DeclarationDescriptor descriptor) { 311 if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.CLASS_OBJECT) { 312 DeclarationDescriptor containing = descriptor.getContainingDeclaration(); 313 if ((containing instanceof ClassDescriptor) && ((ClassDescriptor) containing).getKind() == ClassKind.ENUM_CLASS) { 314 return true; 315 } 316 } 317 return false; 318 } 319 320 public static boolean isSyntheticClassObject(@NotNull DeclarationDescriptor descriptor) { 321 if (isClassObject(descriptor)) { 322 DeclarationDescriptor containing = descriptor.getContainingDeclaration(); 323 if (containing != null) { 324 return isEnumClass(containing) || isObject(containing) || isEnumEntry(containing); 325 } 326 } 327 return false; 328 } 329 330 @NotNull 331 public static Visibility getDefaultConstructorVisibility(@NotNull ClassDescriptor classDescriptor) { 332 ClassKind classKind = classDescriptor.getKind(); 333 if (classKind == ClassKind.ENUM_CLASS || classKind.isSingleton() || isAnonymousObject(classDescriptor)) { 334 return Visibilities.PRIVATE; 335 } 336 assert classKind == ClassKind.CLASS || classKind == ClassKind.TRAIT || classKind == ClassKind.ANNOTATION_CLASS; 337 return Visibilities.PUBLIC; 338 } 339 340 @NotNull 341 public static Visibility getSyntheticClassObjectVisibility() { 342 return Visibilities.PUBLIC; 343 } 344 345 @Nullable 346 public static ClassDescriptor getInnerClassByName(@NotNull ClassDescriptor classDescriptor, @NotNull String innerClassName) { 347 ClassifierDescriptor classifier = classDescriptor.getDefaultType().getMemberScope().getClassifier(Name.identifier(innerClassName)); 348 assert classifier instanceof ClassDescriptor : 349 "Inner class " + innerClassName + " in " + classDescriptor + " should be instance of ClassDescriptor, but was: " 350 + (classifier == null ? "null" : classifier.getClass()); 351 return (ClassDescriptor) classifier; 352 } 353 354 @NotNull 355 public static ConstructorDescriptor getConstructorOfDataClass(ClassDescriptor classDescriptor) { 356 ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor); 357 assert descriptor != null : "Data class must have only one constructor: " + classDescriptor.getConstructors(); 358 return descriptor; 359 } 360 361 @NotNull 362 public static ConstructorDescriptor getConstructorOfSingletonObject(ClassDescriptor classDescriptor) { 363 ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor); 364 assert descriptor != null : "Class of singleton object must have only one constructor: " + classDescriptor.getConstructors(); 365 return descriptor; 366 } 367 368 @Nullable 369 private static ConstructorDescriptor getConstructorDescriptorIfOnlyOne(ClassDescriptor classDescriptor) { 370 Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors(); 371 return constructors.size() != 1 ? null : constructors.iterator().next(); 372 } 373 374 @Nullable 375 public static JetType getReceiverParameterType(@Nullable ReceiverParameterDescriptor receiverParameterDescriptor) { 376 if (receiverParameterDescriptor == null) { 377 return null; 378 } 379 return receiverParameterDescriptor.getType(); 380 } 381 382 @NotNull 383 public static JetType getVarargParameterType(@NotNull JetType elementType) { 384 JetType primitiveArrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(elementType); 385 return primitiveArrayType != null ? primitiveArrayType : KotlinBuiltIns.getInstance().getArrayType(Variance.INVARIANT, elementType); 386 } 387 388 @NotNull 389 public static List<JetType> getValueParametersTypes(@NotNull List<ValueParameterDescriptor> valueParameters) { 390 List<JetType> parameterTypes = Lists.newArrayList(); 391 for (ValueParameterDescriptor parameter : valueParameters) { 392 parameterTypes.add(parameter.getType()); 393 } 394 return parameterTypes; 395 } 396 397 public static boolean isInsideOuterClassOrItsSubclass(@Nullable DeclarationDescriptor nested, @NotNull ClassDescriptor outer) { 398 if (nested == null) return false; 399 400 if (nested instanceof ClassDescriptor && isSubclass((ClassDescriptor) nested, outer)) return true; 401 402 return isInsideOuterClassOrItsSubclass(nested.getContainingDeclaration(), outer); 403 } 404 405 public static boolean isConstructorOfStaticNestedClass(@Nullable CallableDescriptor descriptor) { 406 return descriptor instanceof ConstructorDescriptor && isStaticNestedClass(descriptor.getContainingDeclaration()); 407 } 408 409 /** 410 * @return true if descriptor is a class inside another class and does not have access to the outer class 411 */ 412 public static boolean isStaticNestedClass(@NotNull DeclarationDescriptor descriptor) { 413 DeclarationDescriptor containing = descriptor.getContainingDeclaration(); 414 return descriptor instanceof ClassDescriptor && 415 containing instanceof ClassDescriptor && 416 !((ClassDescriptor) descriptor).isInner(); 417 } 418 419 @Nullable 420 public static ClassDescriptor getContainingClass(@NotNull JetScope scope) { 421 DeclarationDescriptor containingDeclaration = scope.getContainingDeclaration(); 422 return getParentOfType(containingDeclaration, ClassDescriptor.class, false); 423 } 424 425 @NotNull 426 public static JetScope getStaticNestedClassesScope(@NotNull ClassDescriptor descriptor) { 427 JetScope innerClassesScope = descriptor.getUnsubstitutedInnerClassesScope(); 428 return new FilteringScope(innerClassesScope, new Predicate<DeclarationDescriptor>() { 429 @Override 430 public boolean apply(@Nullable DeclarationDescriptor descriptor) { 431 return descriptor instanceof ClassDescriptor && !((ClassDescriptor) descriptor).isInner(); 432 } 433 }); 434 } 435 436 public static boolean isEnumValueOfMethod(@NotNull FunctionDescriptor functionDescriptor) { 437 List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters(); 438 JetType nullableString = TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getStringType()); 439 return "valueOf".equals(functionDescriptor.getName().asString()) 440 && methodTypeParameters.size() == 1 441 && JetTypeChecker.INSTANCE.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString); 442 } 443 444 public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor functionDescriptor) { 445 List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters(); 446 return "values".equals(functionDescriptor.getName().asString()) 447 && methodTypeParameters.isEmpty(); 448 } 449 450 @NotNull 451 public static Set<ClassDescriptor> getAllSuperClasses(@NotNull ClassDescriptor klass) { 452 Set<JetType> allSupertypes = TypeUtils.getAllSupertypes(klass.getDefaultType()); 453 Set<ClassDescriptor> allSuperclasses = Sets.newHashSet(); 454 for (JetType supertype : allSupertypes) { 455 ClassDescriptor superclass = TypeUtils.getClassDescriptor(supertype); 456 assert superclass != null; 457 allSuperclasses.add(superclass); 458 } 459 return allSuperclasses; 460 } 461 462 /** 463 * @return true iff {@code descriptor}'s first non-class container is a package 464 */ 465 public static boolean isTopLevelOrInnerClass(@NotNull ClassDescriptor descriptor) { 466 DeclarationDescriptor containing = descriptor.getContainingDeclaration(); 467 return isTopLevelDeclaration(descriptor) || 468 containing instanceof ClassDescriptor && isTopLevelOrInnerClass((ClassDescriptor) containing); 469 } 470 471 /** 472 * Given a fake override, finds any declaration of it in the overridden descriptors. Keep in mind that there may be many declarations 473 * of the fake override in the supertypes, this method finds just the only one. 474 * TODO: probably all call-sites of this method are wrong, they should handle all super-declarations 475 */ 476 @NotNull 477 public static <D extends CallableMemberDescriptor> D unwrapFakeOverride(@NotNull D descriptor) { 478 while (descriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { 479 Set<? extends CallableMemberDescriptor> overridden = descriptor.getOverriddenDescriptors(); 480 if (overridden.isEmpty()) { 481 throw new IllegalStateException("Fake override should have at least one overridden descriptor: " + descriptor); 482 } 483 //noinspection unchecked 484 descriptor = (D) overridden.iterator().next(); 485 } 486 return descriptor; 487 } 488 489 public static boolean isPropertyCompileTimeConstant(@NotNull VariableDescriptor descriptor) { 490 if (descriptor.isVar()) { 491 return false; 492 } 493 if (isClassObject(descriptor.getContainingDeclaration()) || isTopLevelDeclaration(descriptor)) { 494 JetType type = descriptor.getType(); 495 return KotlinBuiltIns.getInstance().isPrimitiveType(type) || KotlinBuiltIns.getInstance().getStringType().equals(type); 496 } 497 return false; 498 } 499 500 public static boolean shouldRecordInitializerForProperty(@NotNull VariableDescriptor variable, @NotNull JetType type) { 501 if (variable.isVar() || type.isError()) return false; 502 503 if (type instanceof LazyType || type.isNullable()) return true; 504 505 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); 506 return builtIns.isPrimitiveType(type) || 507 builtIns.getStringType().equals(type) || 508 builtIns.getNumber().getDefaultType().equals(type) || 509 builtIns.getAnyType().equals(type); 510 } 511 }