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.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 @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 FqName safe = getFqNameSafeIfPossible(descriptor); 113 return safe != null ? safe.toUnsafe() : getFqNameUnsafe(descriptor); 114 } 115 116 @NotNull 117 public static FqName getFqNameSafe(@NotNull DeclarationDescriptor descriptor) { 118 FqName safe = getFqNameSafeIfPossible(descriptor); 119 return safe != null ? safe : getFqNameUnsafe(descriptor).toSafe(); 120 } 121 122 123 @Nullable 124 private static FqName getFqNameSafeIfPossible(@NotNull DeclarationDescriptor descriptor) { 125 if (descriptor instanceof ModuleDescriptor || ErrorUtils.isError(descriptor)) { 126 return FqName.ROOT; 127 } 128 129 if (descriptor instanceof PackageViewDescriptor) { 130 return ((PackageViewDescriptor) descriptor).getFqName(); 131 } 132 else if (descriptor instanceof PackageFragmentDescriptor) { 133 return ((PackageFragmentDescriptor) descriptor).getFqName(); 134 } 135 136 return null; 137 } 138 139 @NotNull 140 private static FqNameUnsafe getFqNameUnsafe(@NotNull DeclarationDescriptor descriptor) { 141 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 142 143 if (containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).getKind() == ClassKind.CLASS_OBJECT) { 144 DeclarationDescriptor classOfClassObject = containingDeclaration.getContainingDeclaration(); 145 assert classOfClassObject != null; 146 return getFqName(classOfClassObject).child(descriptor.getName()); 147 } 148 149 return getFqName(containingDeclaration).child(descriptor.getName()); 150 } 151 152 public static boolean isTopLevelDeclaration(@NotNull DeclarationDescriptor descriptor) { 153 return descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor; 154 } 155 156 public static boolean areInSameModule(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) { 157 ModuleDescriptor parentModule = getParentOfType(first, ModuleDescriptor.class, false); 158 ModuleDescriptor fromModule = getParentOfType(second, ModuleDescriptor.class, false); 159 assert parentModule != null && fromModule != null; 160 return parentModule.equals(fromModule); 161 } 162 163 @Nullable 164 public static DeclarationDescriptor findTopLevelParent(@NotNull DeclarationDescriptor declarationDescriptor) { 165 DeclarationDescriptor descriptor = declarationDescriptor; 166 if (declarationDescriptor instanceof PropertyAccessorDescriptor) { 167 descriptor = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty(); 168 } 169 while (!(descriptor == null || isTopLevelDeclaration(descriptor))) { 170 descriptor = descriptor.getContainingDeclaration(); 171 } 172 return descriptor; 173 } 174 175 @Nullable 176 public static <D extends DeclarationDescriptor> D getParentOfType( 177 @Nullable DeclarationDescriptor descriptor, 178 @NotNull Class<D> aClass 179 ) { 180 return getParentOfType(descriptor, aClass, true); 181 } 182 183 @Nullable 184 public static <D extends DeclarationDescriptor> D getParentOfType( 185 @Nullable DeclarationDescriptor descriptor, 186 @NotNull Class<D> aClass, 187 boolean strict 188 ) { 189 if (descriptor == null) return null; 190 if (strict) { 191 descriptor = descriptor.getContainingDeclaration(); 192 } 193 while (descriptor != null) { 194 if (aClass.isInstance(descriptor)) { 195 //noinspection unchecked 196 return (D) descriptor; 197 } 198 descriptor = descriptor.getContainingDeclaration(); 199 } 200 return null; 201 } 202 203 public static boolean isAncestor( 204 @Nullable DeclarationDescriptor ancestor, 205 @NotNull DeclarationDescriptor declarationDescriptor, 206 boolean strict 207 ) { 208 if (ancestor == null) return false; 209 DeclarationDescriptor descriptor = strict ? declarationDescriptor.getContainingDeclaration() : declarationDescriptor; 210 while (descriptor != null) { 211 if (ancestor == descriptor) return true; 212 descriptor = descriptor.getContainingDeclaration(); 213 } 214 return false; 215 } 216 217 public static boolean isSubclass(@NotNull ClassDescriptor subClass, @NotNull ClassDescriptor superClass) { 218 return isSubtypeOfClass(subClass.getDefaultType(), superClass.getOriginal()); 219 } 220 221 private static boolean isSubtypeOfClass(@NotNull JetType type, @NotNull DeclarationDescriptor superClass) { 222 DeclarationDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); 223 if (descriptor != null && superClass == descriptor.getOriginal()) { 224 return true; 225 } 226 for (JetType superType : type.getConstructor().getSupertypes()) { 227 if (isSubtypeOfClass(superType, superClass)) { 228 return true; 229 } 230 } 231 return false; 232 } 233 234 public static boolean isFunctionLiteral(@NotNull FunctionDescriptor descriptor) { 235 return descriptor instanceof AnonymousFunctionDescriptor; 236 } 237 238 public static boolean isClassObject(@NotNull DeclarationDescriptor descriptor) { 239 return isKindOf(descriptor, ClassKind.CLASS_OBJECT); 240 } 241 242 public static boolean isAnonymousObject(@NotNull DeclarationDescriptor descriptor) { 243 return isClass(descriptor) && descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED); 244 } 245 246 public static boolean isObject(@NotNull DeclarationDescriptor descriptor) { 247 return isKindOf(descriptor, ClassKind.OBJECT); 248 } 249 250 public static boolean isEnumEntry(@NotNull DeclarationDescriptor descriptor) { 251 return isKindOf(descriptor, ClassKind.ENUM_ENTRY); 252 } 253 254 public static boolean isSingleton(@Nullable DeclarationDescriptor classifier) { 255 if (classifier instanceof ClassDescriptor) { 256 ClassDescriptor clazz = (ClassDescriptor) classifier; 257 return clazz.getKind().isSingleton(); 258 } 259 return false; 260 } 261 262 public static boolean isEnumClass(@NotNull DeclarationDescriptor descriptor) { 263 return isKindOf(descriptor, ClassKind.ENUM_CLASS); 264 } 265 266 public static boolean isAnnotationClass(@Nullable DeclarationDescriptor descriptor) { 267 return isKindOf(descriptor, ClassKind.ANNOTATION_CLASS); 268 } 269 270 public static boolean isTrait(@NotNull DeclarationDescriptor descriptor) { 271 return isKindOf(descriptor, ClassKind.TRAIT); 272 } 273 274 public static boolean isClass(@NotNull DeclarationDescriptor descriptor) { 275 return isKindOf(descriptor, ClassKind.CLASS); 276 } 277 278 public static boolean isKindOf(@Nullable DeclarationDescriptor descriptor, @NotNull ClassKind classKind) { 279 return descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == classKind; 280 } 281 282 @NotNull 283 public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) { 284 Collection<JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes(); 285 List<ClassDescriptor> superClassDescriptors = new ArrayList<ClassDescriptor>(); 286 for (JetType type : superclassTypes) { 287 ClassDescriptor result = getClassDescriptorForType(type); 288 if (!isAny(result)) { 289 superClassDescriptors.add(result); 290 } 291 } 292 return superClassDescriptors; 293 } 294 295 @NotNull 296 public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) { 297 return getClassDescriptorForTypeConstructor(type.getConstructor()); 298 } 299 300 @NotNull 301 public static ClassDescriptor getClassDescriptorForTypeConstructor(@NotNull TypeConstructor typeConstructor) { 302 ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor(); 303 assert descriptor instanceof ClassDescriptor 304 : "Classifier descriptor of a type should be of type ClassDescriptor: " + typeConstructor; 305 return (ClassDescriptor) descriptor; 306 } 307 308 public static boolean isAny(@NotNull DeclarationDescriptor superClassDescriptor) { 309 return superClassDescriptor.equals(KotlinBuiltIns.getInstance().getAny()); 310 } 311 312 public static boolean isEnumClassObject(@NotNull DeclarationDescriptor descriptor) { 313 if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.CLASS_OBJECT) { 314 DeclarationDescriptor containing = descriptor.getContainingDeclaration(); 315 if ((containing instanceof ClassDescriptor) && ((ClassDescriptor) containing).getKind() == ClassKind.ENUM_CLASS) { 316 return true; 317 } 318 } 319 return false; 320 } 321 322 public static boolean isSyntheticClassObject(@NotNull DeclarationDescriptor descriptor) { 323 if (isClassObject(descriptor)) { 324 DeclarationDescriptor containing = descriptor.getContainingDeclaration(); 325 if (containing != null) { 326 return isEnumClass(containing) || isObject(containing) || isEnumEntry(containing); 327 } 328 } 329 return false; 330 } 331 332 @NotNull 333 public static Visibility getDefaultConstructorVisibility(@NotNull ClassDescriptor classDescriptor) { 334 ClassKind classKind = classDescriptor.getKind(); 335 if (classKind == ClassKind.ENUM_CLASS || classKind.isSingleton() || isAnonymousObject(classDescriptor)) { 336 return Visibilities.PRIVATE; 337 } 338 assert classKind == ClassKind.CLASS || classKind == ClassKind.TRAIT || classKind == ClassKind.ANNOTATION_CLASS; 339 return Visibilities.PUBLIC; 340 } 341 342 @NotNull 343 public static Visibility getSyntheticClassObjectVisibility() { 344 return Visibilities.PUBLIC; 345 } 346 347 @Nullable 348 public static ClassDescriptor getInnerClassByName(@NotNull ClassDescriptor classDescriptor, @NotNull String innerClassName) { 349 ClassifierDescriptor classifier = classDescriptor.getDefaultType().getMemberScope().getClassifier(Name.identifier(innerClassName)); 350 assert classifier instanceof ClassDescriptor : 351 "Inner class " + innerClassName + " in " + classDescriptor + " should be instance of ClassDescriptor, but was: " 352 + (classifier == null ? "null" : classifier.getClass()); 353 return (ClassDescriptor) classifier; 354 } 355 356 @NotNull 357 public static ConstructorDescriptor getConstructorOfDataClass(ClassDescriptor classDescriptor) { 358 ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor); 359 assert descriptor != null : "Data class must have only one constructor: " + classDescriptor.getConstructors(); 360 return descriptor; 361 } 362 363 @NotNull 364 public static ConstructorDescriptor getConstructorOfSingletonObject(ClassDescriptor classDescriptor) { 365 ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor); 366 assert descriptor != null : "Class of singleton object must have only one constructor: " + classDescriptor.getConstructors(); 367 return descriptor; 368 } 369 370 @Nullable 371 private static ConstructorDescriptor getConstructorDescriptorIfOnlyOne(ClassDescriptor classDescriptor) { 372 Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors(); 373 return constructors.size() != 1 ? null : constructors.iterator().next(); 374 } 375 376 @Nullable 377 public static JetType getReceiverParameterType(@Nullable ReceiverParameterDescriptor receiverParameterDescriptor) { 378 if (receiverParameterDescriptor == null) { 379 return null; 380 } 381 return receiverParameterDescriptor.getType(); 382 } 383 384 @NotNull 385 public static JetType getVarargParameterType(@NotNull JetType elementType) { 386 JetType primitiveArrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(elementType); 387 return primitiveArrayType != null ? primitiveArrayType : KotlinBuiltIns.getInstance().getArrayType(Variance.INVARIANT, elementType); 388 } 389 390 @NotNull 391 public static List<JetType> getValueParametersTypes(@NotNull List<ValueParameterDescriptor> valueParameters) { 392 List<JetType> parameterTypes = Lists.newArrayList(); 393 for (ValueParameterDescriptor parameter : valueParameters) { 394 parameterTypes.add(parameter.getType()); 395 } 396 return parameterTypes; 397 } 398 399 public static boolean isInsideOuterClassOrItsSubclass(@Nullable DeclarationDescriptor nested, @NotNull ClassDescriptor outer) { 400 if (nested == null) return false; 401 402 if (nested instanceof ClassDescriptor && isSubclass((ClassDescriptor) nested, outer)) return true; 403 404 return isInsideOuterClassOrItsSubclass(nested.getContainingDeclaration(), outer); 405 } 406 407 public static boolean isConstructorOfStaticNestedClass(@Nullable CallableDescriptor descriptor) { 408 return descriptor instanceof ConstructorDescriptor && isStaticNestedClass(descriptor.getContainingDeclaration()); 409 } 410 411 /** 412 * @return true if descriptor is a class inside another class and does not have access to the outer class 413 */ 414 public static boolean isStaticNestedClass(@NotNull DeclarationDescriptor descriptor) { 415 DeclarationDescriptor containing = descriptor.getContainingDeclaration(); 416 return descriptor instanceof ClassDescriptor && 417 containing instanceof ClassDescriptor && 418 !((ClassDescriptor) descriptor).isInner(); 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 package 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 }