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 ClassifierDescriptor descriptor) { 235 return isKindOf(descriptor, ClassKind.OBJECT) && descriptor.getName().isSpecial(); 236 } 237 238 public static boolean isEnumEntry(@NotNull DeclarationDescriptor descriptor) { 239 return isKindOf(descriptor, ClassKind.ENUM_ENTRY); 240 } 241 242 public static boolean isEnumClass(@NotNull DeclarationDescriptor descriptor) { 243 return isKindOf(descriptor, ClassKind.ENUM_CLASS); 244 } 245 246 public static boolean isAnnotationClass(@Nullable DeclarationDescriptor descriptor) { 247 return isKindOf(descriptor, ClassKind.ANNOTATION_CLASS); 248 } 249 250 public static boolean isTrait(@NotNull DeclarationDescriptor descriptor) { 251 return isKindOf(descriptor, ClassKind.TRAIT); 252 } 253 254 public static boolean isClass(@NotNull DeclarationDescriptor descriptor) { 255 return isKindOf(descriptor, ClassKind.CLASS); 256 } 257 258 public static boolean isKindOf(@Nullable DeclarationDescriptor descriptor, @NotNull ClassKind classKind) { 259 return descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == classKind; 260 } 261 262 @NotNull 263 public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) { 264 Collection<JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes(); 265 List<ClassDescriptor> superClassDescriptors = new ArrayList<ClassDescriptor>(); 266 for (JetType type : superclassTypes) { 267 ClassDescriptor result = getClassDescriptorForType(type); 268 if (!isAny(result)) { 269 superClassDescriptors.add(result); 270 } 271 } 272 return superClassDescriptors; 273 } 274 275 @NotNull 276 public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) { 277 return getClassDescriptorForTypeConstructor(type.getConstructor()); 278 } 279 280 @NotNull 281 public static ClassDescriptor getClassDescriptorForTypeConstructor(@NotNull TypeConstructor typeConstructor) { 282 ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor(); 283 assert descriptor instanceof ClassDescriptor 284 : "Classifier descriptor of a type should be of type ClassDescriptor: " + typeConstructor; 285 return (ClassDescriptor) descriptor; 286 } 287 288 public static boolean isAny(@NotNull DeclarationDescriptor superClassDescriptor) { 289 return superClassDescriptor.equals(KotlinBuiltIns.getInstance().getAny()); 290 } 291 292 public static boolean inStaticContext(@NotNull DeclarationDescriptor descriptor) { 293 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 294 if (containingDeclaration instanceof NamespaceDescriptor) { 295 return true; 296 } 297 if (containingDeclaration instanceof ClassDescriptor) { 298 ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; 299 300 if (classDescriptor.getKind().isObject()) { 301 return inStaticContext(classDescriptor.getContainingDeclaration()); 302 } 303 304 } 305 return false; 306 } 307 308 public static boolean isEnumClassObject(@NotNull DeclarationDescriptor descriptor) { 309 if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.CLASS_OBJECT) { 310 DeclarationDescriptor containing = descriptor.getContainingDeclaration(); 311 if ((containing instanceof ClassDescriptor) && ((ClassDescriptor) containing).getKind() == ClassKind.ENUM_CLASS) { 312 return true; 313 } 314 } 315 return false; 316 } 317 318 @NotNull 319 public static Visibility getDefaultConstructorVisibility(@NotNull ClassDescriptor classDescriptor) { 320 ClassKind classKind = classDescriptor.getKind(); 321 if (classKind == ClassKind.ENUM_CLASS) { 322 return Visibilities.PRIVATE; 323 } 324 if (classKind.isObject()) { 325 return Visibilities.PRIVATE; 326 } 327 assert classKind == ClassKind.CLASS || classKind == ClassKind.TRAIT || classKind == ClassKind.ANNOTATION_CLASS; 328 return Visibilities.PUBLIC; 329 } 330 331 @NotNull 332 public static List<String> getSortedValueArguments( 333 @NotNull AnnotationDescriptor descriptor, 334 @Nullable DescriptorRenderer rendererForTypesIfNecessary 335 ) { 336 List<String> resultList = Lists.newArrayList(); 337 for (Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>> entry : descriptor.getAllValueArguments().entrySet()) { 338 CompileTimeConstant<?> value = entry.getValue(); 339 String typeSuffix = rendererForTypesIfNecessary == null 340 ? "" 341 : ": " + rendererForTypesIfNecessary.renderType(value.getType(KotlinBuiltIns.getInstance())); 342 resultList.add(entry.getKey().getName().asString() + " = " + value.toString() + typeSuffix); 343 } 344 Collections.sort(resultList); 345 return resultList; 346 } 347 348 @Nullable 349 public static ClassDescriptor getInnerClassByName(@NotNull ClassDescriptor classDescriptor, @NotNull String innerClassName) { 350 ClassifierDescriptor classifier = classDescriptor.getDefaultType().getMemberScope().getClassifier(Name.identifier(innerClassName)); 351 assert classifier instanceof ClassDescriptor : 352 "Inner class " + innerClassName + " in " + classDescriptor + " should be instance of ClassDescriptor, but was: " 353 + (classifier == null ? "null" : classifier.getClass()); 354 return (ClassDescriptor) classifier; 355 } 356 357 @NotNull 358 public static ConstructorDescriptor getConstructorOfDataClass(ClassDescriptor classDescriptor) { 359 ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor); 360 assert descriptor != null : "Data class must have only one constructor: " + classDescriptor.getConstructors(); 361 return descriptor; 362 } 363 364 @NotNull 365 public static ConstructorDescriptor getConstructorOfSingletonObject(ClassDescriptor classDescriptor) { 366 ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor); 367 assert descriptor != null : "Class of singleton object must have only one constructor: " + classDescriptor.getConstructors(); 368 return descriptor; 369 } 370 371 @Nullable 372 private static ConstructorDescriptor getConstructorDescriptorIfOnlyOne(ClassDescriptor classDescriptor) { 373 Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors(); 374 return constructors.size() != 1 ? null : constructors.iterator().next(); 375 } 376 377 @Nullable 378 public static JetType getReceiverParameterType(@Nullable ReceiverParameterDescriptor receiverParameterDescriptor) { 379 if (receiverParameterDescriptor == null) { 380 return null; 381 } 382 return receiverParameterDescriptor.getType(); 383 } 384 385 @NotNull 386 public static JetType getVarargParameterType(@NotNull JetType elementType) { 387 JetType primitiveArrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(elementType); 388 return primitiveArrayType != null ? primitiveArrayType : KotlinBuiltIns.getInstance().getArrayType(Variance.INVARIANT, elementType); 389 } 390 391 @NotNull 392 public static List<JetType> getValueParametersTypes(@NotNull List<ValueParameterDescriptor> valueParameters) { 393 List<JetType> parameterTypes = Lists.newArrayList(); 394 for (ValueParameterDescriptor parameter : valueParameters) { 395 parameterTypes.add(parameter.getType()); 396 } 397 return parameterTypes; 398 } 399 400 public static boolean isConstructorOfStaticNestedClass(@Nullable CallableDescriptor descriptor) { 401 return descriptor instanceof ConstructorDescriptor && isStaticNestedClass(descriptor.getContainingDeclaration()); 402 } 403 404 /** 405 * @return true if descriptor is a class inside another class and does not have access to the outer class 406 */ 407 public static boolean isStaticNestedClass(@NotNull DeclarationDescriptor descriptor) { 408 DeclarationDescriptor containing = descriptor.getContainingDeclaration(); 409 return descriptor instanceof ClassDescriptor && 410 containing instanceof ClassDescriptor && 411 !((ClassDescriptor) descriptor).isInner() && 412 !((ClassDescriptor) containing).getKind().isObject(); 413 } 414 415 @Nullable 416 public static ClassDescriptor getContainingClass(@NotNull JetScope scope) { 417 DeclarationDescriptor containingDeclaration = scope.getContainingDeclaration(); 418 return getParentOfType(containingDeclaration, ClassDescriptor.class, false); 419 } 420 421 @NotNull 422 public static JetScope getStaticNestedClassesScope(@NotNull ClassDescriptor descriptor) { 423 JetScope innerClassesScope = descriptor.getUnsubstitutedInnerClassesScope(); 424 return new FilteringScope(innerClassesScope, new Predicate<DeclarationDescriptor>() { 425 @Override 426 public boolean apply(@Nullable DeclarationDescriptor descriptor) { 427 return descriptor instanceof ClassDescriptor && !((ClassDescriptor) descriptor).isInner(); 428 } 429 }); 430 } 431 432 public static boolean isEnumValueOfMethod(@NotNull FunctionDescriptor functionDescriptor) { 433 List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters(); 434 JetType nullableString = TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getStringType()); 435 return "valueOf".equals(functionDescriptor.getName().asString()) 436 && methodTypeParameters.size() == 1 437 && JetTypeChecker.INSTANCE.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString); 438 } 439 440 public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor functionDescriptor) { 441 List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters(); 442 return "values".equals(functionDescriptor.getName().asString()) 443 && methodTypeParameters.isEmpty(); 444 } 445 446 @NotNull 447 public static Set<ClassDescriptor> getAllSuperClasses(@NotNull ClassDescriptor klass) { 448 Set<JetType> allSupertypes = TypeUtils.getAllSupertypes(klass.getDefaultType()); 449 Set<ClassDescriptor> allSuperclasses = Sets.newHashSet(); 450 for (JetType supertype : allSupertypes) { 451 ClassDescriptor superclass = TypeUtils.getClassDescriptor(supertype); 452 assert superclass != null; 453 allSuperclasses.add(superclass); 454 } 455 return allSuperclasses; 456 } 457 458 /** 459 * @return true iff {@code descriptor}'s first non-class container is a namespace 460 */ 461 public static boolean isTopLevelOrInnerClass(@NotNull ClassDescriptor descriptor) { 462 DeclarationDescriptor containing = descriptor.getContainingDeclaration(); 463 return isTopLevelDeclaration(descriptor) || 464 containing instanceof ClassDescriptor && isTopLevelOrInnerClass((ClassDescriptor) containing); 465 } 466 467 @NotNull 468 public static JetScope getEnumEntriesScope(@NotNull ClassDescriptor enumClass) { 469 assert enumClass.getKind() == ClassKind.ENUM_CLASS : "Only enum classes have enum entries: " + enumClass; 470 ClassDescriptor classObject = enumClass.getClassObjectDescriptor(); 471 assert classObject != null : "Enum class should have a class object: " + enumClass; 472 return classObject.getDefaultType().getMemberScope(); 473 } 474 }