001    /*
002     * Copyright 2010-2015 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.kotlin.builtins;
018    
019    import kotlin.collections.SetsKt;
020    import kotlin.jvm.functions.Function1;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFactory;
024    import org.jetbrains.kotlin.descriptors.*;
025    import org.jetbrains.kotlin.descriptors.annotations.*;
026    import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
027    import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
028    import org.jetbrains.kotlin.name.ClassId;
029    import org.jetbrains.kotlin.name.FqName;
030    import org.jetbrains.kotlin.name.FqNameUnsafe;
031    import org.jetbrains.kotlin.name.Name;
032    import org.jetbrains.kotlin.resolve.DescriptorUtils;
033    import org.jetbrains.kotlin.resolve.scopes.MemberScope;
034    import org.jetbrains.kotlin.serialization.deserialization.AdditionalSupertypes;
035    import org.jetbrains.kotlin.storage.LockBasedStorageManager;
036    import org.jetbrains.kotlin.types.*;
037    import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
038    
039    import java.io.InputStream;
040    import java.util.*;
041    
042    import static kotlin.collections.CollectionsKt.single;
043    import static kotlin.collections.SetsKt.setOf;
044    import static org.jetbrains.kotlin.builtins.PrimitiveType.*;
045    import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqName;
046    
047    public abstract class KotlinBuiltIns {
048        public static final Name BUILT_INS_PACKAGE_NAME = Name.identifier("kotlin");
049        public static final FqName BUILT_INS_PACKAGE_FQ_NAME = FqName.topLevel(BUILT_INS_PACKAGE_NAME);
050        private static final FqName ANNOTATION_PACKAGE_FQ_NAME = BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier("annotation"));
051        public static final FqName COLLECTIONS_PACKAGE_FQ_NAME = BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier("collections"));
052        public static final FqName RANGES_PACKAGE_FQ_NAME = BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier("ranges"));
053    
054        public static final Set<FqName> BUILT_INS_PACKAGE_FQ_NAMES = setOf(
055                BUILT_INS_PACKAGE_FQ_NAME,
056                COLLECTIONS_PACKAGE_FQ_NAME,
057                RANGES_PACKAGE_FQ_NAME,
058                ANNOTATION_PACKAGE_FQ_NAME,
059                ReflectionTypesKt.getKOTLIN_REFLECT_FQ_NAME(),
060                BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier("internal"))
061        );
062    
063        protected final ModuleDescriptorImpl builtInsModule;
064        private final BuiltInsPackageFragment builtInsPackageFragment;
065        private final BuiltInsPackageFragment collectionsPackageFragment;
066        private final BuiltInsPackageFragment rangesPackageFragment;
067        private final BuiltInsPackageFragment annotationPackageFragment;
068    
069        private final Set<BuiltInsPackageFragment> builtInsPackageFragments;
070    
071        private final Map<PrimitiveType, KotlinType> primitiveTypeToArrayKotlinType;
072        private final Map<KotlinType, KotlinType> primitiveKotlinTypeToKotlinArrayType;
073        private final Map<KotlinType, KotlinType> kotlinArrayTypeToPrimitiveKotlinType;
074        private final Map<FqName, BuiltInsPackageFragment> packageNameToPackageFragment;
075    
076        public static final FqNames FQ_NAMES = new FqNames();
077    
078        protected KotlinBuiltIns() {
079            LockBasedStorageManager storageManager = new LockBasedStorageManager();
080            builtInsModule = new ModuleDescriptorImpl(
081                    Name.special("<built-ins module>"), storageManager, ModuleParameters.Empty.INSTANCE, this
082            );
083    
084            PackageFragmentProvider packageFragmentProvider = BuiltInsPackageFragmentProviderKt.createBuiltInPackageFragmentProvider(
085                    storageManager, builtInsModule, BUILT_INS_PACKAGE_FQ_NAMES,
086                    new BuiltInFictitiousFunctionClassFactory(storageManager, builtInsModule),
087                    getAdditionalSupertypesProvider(),
088                    new Function1<String, InputStream>() {
089                        @Override
090                        public InputStream invoke(String path) {
091                            return KotlinBuiltIns.class.getClassLoader().getResourceAsStream(path);
092                        }
093                    }
094            );
095    
096            builtInsModule.initialize(packageFragmentProvider);
097            builtInsModule.setDependencies(builtInsModule);
098    
099            packageNameToPackageFragment = new LinkedHashMap<FqName, BuiltInsPackageFragment>();
100    
101            builtInsPackageFragment = createPackage(packageFragmentProvider, packageNameToPackageFragment, BUILT_INS_PACKAGE_FQ_NAME);
102            collectionsPackageFragment = createPackage(packageFragmentProvider, packageNameToPackageFragment, COLLECTIONS_PACKAGE_FQ_NAME);
103            rangesPackageFragment = createPackage(packageFragmentProvider, packageNameToPackageFragment, RANGES_PACKAGE_FQ_NAME);
104            annotationPackageFragment = createPackage(packageFragmentProvider, packageNameToPackageFragment, ANNOTATION_PACKAGE_FQ_NAME);
105    
106            builtInsPackageFragments = new LinkedHashSet<BuiltInsPackageFragment>(packageNameToPackageFragment.values());
107    
108            primitiveTypeToArrayKotlinType = new EnumMap<PrimitiveType, KotlinType>(PrimitiveType.class);
109            primitiveKotlinTypeToKotlinArrayType = new HashMap<KotlinType, KotlinType>();
110            kotlinArrayTypeToPrimitiveKotlinType = new HashMap<KotlinType, KotlinType>();
111            for (PrimitiveType primitive : PrimitiveType.values()) {
112                makePrimitive(primitive);
113            }
114        }
115    
116        @NotNull
117        protected AdditionalSupertypes getAdditionalSupertypesProvider() {
118            return AdditionalSupertypes.None.INSTANCE;
119        }
120    
121        private void makePrimitive(@NotNull PrimitiveType primitiveType) {
122            KotlinType type = getBuiltInTypeByClassName(primitiveType.getTypeName().asString());
123            KotlinType arrayType = getBuiltInTypeByClassName(primitiveType.getArrayTypeName().asString());
124    
125            primitiveTypeToArrayKotlinType.put(primitiveType, arrayType);
126            primitiveKotlinTypeToKotlinArrayType.put(type, arrayType);
127            kotlinArrayTypeToPrimitiveKotlinType.put(arrayType, type);
128        }
129    
130    
131        @NotNull
132        private static BuiltInsPackageFragment createPackage(
133                @NotNull PackageFragmentProvider fragmentProvider,
134                @NotNull Map<FqName, BuiltInsPackageFragment> packageNameToPackageFragment,
135                @NotNull FqName packageFqName
136        ) {
137            BuiltInsPackageFragment packageFragment = (BuiltInsPackageFragment) single(fragmentProvider.getPackageFragments(packageFqName));
138            packageNameToPackageFragment.put(packageFqName, packageFragment);
139            return packageFragment;
140        }
141    
142        @SuppressWarnings("WeakerAccess")
143        public static class FqNames {
144            public final FqNameUnsafe any = fqNameUnsafe("Any");
145            public final FqNameUnsafe nothing = fqNameUnsafe("Nothing");
146            public final FqNameUnsafe cloneable = fqNameUnsafe("Cloneable");
147            public final FqNameUnsafe suppress = fqNameUnsafe("Suppress");
148            public final FqNameUnsafe unit = fqNameUnsafe("Unit");
149            public final FqNameUnsafe charSequence = fqNameUnsafe("CharSequence");
150            public final FqNameUnsafe string = fqNameUnsafe("String");
151            public final FqNameUnsafe array = fqNameUnsafe("Array");
152    
153            public final FqNameUnsafe _boolean = fqNameUnsafe("Boolean");
154            public final FqNameUnsafe _char = fqNameUnsafe("Char");
155            public final FqNameUnsafe _byte = fqNameUnsafe("Byte");
156            public final FqNameUnsafe _short = fqNameUnsafe("Short");
157            public final FqNameUnsafe _int = fqNameUnsafe("Int");
158            public final FqNameUnsafe _long = fqNameUnsafe("Long");
159            public final FqNameUnsafe _float = fqNameUnsafe("Float");
160            public final FqNameUnsafe _double = fqNameUnsafe("Double");
161            public final FqNameUnsafe number = fqNameUnsafe("Number");
162    
163            public final FqNameUnsafe _enum = fqNameUnsafe("Enum");
164    
165    
166    
167            public final FqName throwable = fqName("Throwable");
168    
169            public final FqName deprecated = fqName("Deprecated");
170            public final FqName deprecationLevel = fqName("DeprecationLevel");
171            public final FqName extensionFunctionType = fqName("ExtensionFunctionType");
172            public final FqName target = annotationName("Target");
173            public final FqName annotationTarget = annotationName("AnnotationTarget");
174            public final FqName annotationRetention = annotationName("AnnotationRetention");
175            public final FqName retention = annotationName("Retention");
176            public final FqName repeatable = annotationName("Repeatable");
177            public final FqName mustBeDocumented = annotationName("MustBeDocumented");
178            public final FqName unsafeVariance = fqName("UnsafeVariance");
179    
180            public final FqName iterator = collectionsFqName("Iterator");
181            public final FqName iterable = collectionsFqName("Iterable");
182            public final FqName collection = collectionsFqName("Collection");
183            public final FqName list = collectionsFqName("List");
184            public final FqName listIterator = collectionsFqName("ListIterator");
185            public final FqName set = collectionsFqName("Set");
186            public final FqName map = collectionsFqName("Map");
187            public final FqName mapEntry = map.child(Name.identifier("Entry"));
188            public final FqName mutableIterator = collectionsFqName("MutableIterator");
189            public final FqName mutableIterable = collectionsFqName("MutableIterable");
190            public final FqName mutableCollection = collectionsFqName("MutableCollection");
191            public final FqName mutableList = collectionsFqName("MutableList");
192            public final FqName mutableListIterator = collectionsFqName("MutableListIterator");
193            public final FqName mutableSet = collectionsFqName("MutableSet");
194            public final FqName mutableMap = collectionsFqName("MutableMap");
195            public final FqName mutableMapEntry = mutableMap.child(Name.identifier("MutableEntry"));
196    
197            private final FqNameUnsafe _collection = collection.toUnsafe();
198            private final FqNameUnsafe _list = list.toUnsafe();
199            private final FqNameUnsafe _set = set.toUnsafe();
200            private final FqNameUnsafe _iterable = iterable.toUnsafe();
201    
202            public final FqNameUnsafe kClass = reflect("KClass");
203            public final FqNameUnsafe kCallable = reflect("KCallable");
204            public final ClassId kProperty = ClassId.topLevel(reflect("KProperty").toSafe());
205    
206            public final Map<FqNameUnsafe, PrimitiveType> fqNameToPrimitiveType;
207            public final Map<FqNameUnsafe, PrimitiveType> arrayClassFqNameToPrimitiveType;
208            {
209                fqNameToPrimitiveType = new HashMap<FqNameUnsafe, PrimitiveType>(0);
210                arrayClassFqNameToPrimitiveType = new HashMap<FqNameUnsafe, PrimitiveType>(0);
211                for (PrimitiveType primitiveType : PrimitiveType.values()) {
212                    fqNameToPrimitiveType.put(fqNameUnsafe(primitiveType.getTypeName().asString()), primitiveType);
213                    arrayClassFqNameToPrimitiveType.put(fqNameUnsafe(primitiveType.getArrayTypeName().asString()), primitiveType);
214                }
215            }
216    
217            @NotNull
218            private static FqNameUnsafe fqNameUnsafe(@NotNull String simpleName) {
219                return fqName(simpleName).toUnsafe();
220            }
221    
222            @NotNull
223            private static FqName fqName(@NotNull String simpleName) {
224                return BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier(simpleName));
225            }
226    
227            @NotNull
228            private static FqName collectionsFqName(@NotNull String simpleName) {
229                return COLLECTIONS_PACKAGE_FQ_NAME.child(Name.identifier(simpleName));
230            }
231    
232            @NotNull
233            private static FqNameUnsafe reflect(@NotNull String simpleName) {
234                return ReflectionTypesKt.getKOTLIN_REFLECT_FQ_NAME().child(Name.identifier(simpleName)).toUnsafe();
235            }
236    
237            @NotNull
238            private static FqName annotationName(@NotNull String simpleName) {
239                return ANNOTATION_PACKAGE_FQ_NAME.child(Name.identifier(simpleName));
240            }
241        }
242    
243        @NotNull
244        public ModuleDescriptorImpl getBuiltInsModule() {
245            return builtInsModule;
246        }
247    
248        @NotNull
249        public Set<BuiltInsPackageFragment> getBuiltInsPackageFragments() {
250            return builtInsPackageFragments;
251        }
252    
253        @NotNull
254        public PackageFragmentDescriptor getBuiltInsPackageFragment() {
255            return builtInsPackageFragment;
256        }
257    
258        public boolean isBuiltInPackageFragment(@Nullable PackageFragmentDescriptor packageFragment) {
259            return packageFragment != null && packageFragment.getContainingDeclaration() == getBuiltInsModule();
260        }
261    
262        @NotNull
263        public MemberScope getBuiltInsPackageScope() {
264            return builtInsPackageFragment.getMemberScope();
265        }
266    
267        @NotNull
268        private ClassDescriptor getAnnotationClassByName(@NotNull Name simpleName) {
269            return getBuiltInClassByName(simpleName, annotationPackageFragment);
270        }
271    
272        @NotNull
273        public ClassDescriptor getBuiltInClassByName(@NotNull Name simpleName) {
274            return getBuiltInClassByName(simpleName, getBuiltInsPackageFragment());
275        }
276    
277        @NotNull
278        private static ClassDescriptor getBuiltInClassByName(@NotNull Name simpleName, @NotNull PackageFragmentDescriptor packageFragment) {
279            ClassDescriptor classDescriptor = getBuiltInClassByNameNullable(simpleName, packageFragment);
280            assert classDescriptor != null : "Built-in class " + simpleName + " is not found";
281            return classDescriptor;
282        }
283    
284        @Nullable
285        public ClassDescriptor getBuiltInClassByNameNullable(@NotNull Name simpleName) {
286            return getBuiltInClassByNameNullable(simpleName, getBuiltInsPackageFragment());
287        }
288    
289        @Nullable
290        public ClassDescriptor getBuiltInClassByFqNameNullable(@NotNull FqName fqName) {
291            if (!fqName.isRoot()) {
292                FqName parent = fqName.parent();
293                BuiltInsPackageFragment packageFragment = packageNameToPackageFragment.get(parent);
294                if (packageFragment != null) {
295                    return getBuiltInClassByNameNullable(fqName.shortName(), packageFragment);
296                }
297            }
298            return null;
299        }
300    
301        @Nullable
302        private static ClassDescriptor getBuiltInClassByNameNullable(@NotNull Name simpleName, @NotNull PackageFragmentDescriptor packageFragment) {
303            ClassifierDescriptor classifier = packageFragment.getMemberScope().getContributedClassifier(
304                    simpleName,
305                    NoLookupLocation.FROM_BUILTINS);
306    
307            assert classifier == null ||
308                   classifier instanceof ClassDescriptor : "Must be a class descriptor " + simpleName + ", but was " + classifier;
309            return (ClassDescriptor) classifier;
310        }
311    
312        @NotNull
313        private ClassDescriptor getBuiltInClassByName(@NotNull String simpleName) {
314            return getBuiltInClassByName(Name.identifier(simpleName));
315        }
316    
317        @NotNull
318        private static ClassDescriptor getBuiltInClassByName(@NotNull String simpleName, PackageFragmentDescriptor packageFragment) {
319            return getBuiltInClassByName(Name.identifier(simpleName), packageFragment);
320        }
321    
322        @NotNull
323        public ClassDescriptor getAny() {
324            return getBuiltInClassByName("Any");
325        }
326    
327        @NotNull
328        public ClassDescriptor getNothing() {
329            return getBuiltInClassByName("Nothing");
330        }
331    
332        @NotNull
333        public ClassDescriptor getPrimitiveClassDescriptor(@NotNull PrimitiveType type) {
334            return getBuiltInClassByName(type.getTypeName().asString());
335        }
336    
337        @NotNull
338        public ClassDescriptor getByte() {
339            return getPrimitiveClassDescriptor(BYTE);
340        }
341    
342        @NotNull
343        public ClassDescriptor getShort() {
344            return getPrimitiveClassDescriptor(SHORT);
345        }
346    
347        @NotNull
348        public ClassDescriptor getInt() {
349            return getPrimitiveClassDescriptor(INT);
350        }
351    
352        @NotNull
353        public ClassDescriptor getLong() {
354            return getPrimitiveClassDescriptor(LONG);
355        }
356    
357        @NotNull
358        public ClassDescriptor getFloat() {
359            return getPrimitiveClassDescriptor(FLOAT);
360        }
361    
362        @NotNull
363        public ClassDescriptor getDouble() {
364            return getPrimitiveClassDescriptor(DOUBLE);
365        }
366    
367        @NotNull
368        public ClassDescriptor getChar() {
369            return getPrimitiveClassDescriptor(CHAR);
370        }
371    
372        @NotNull
373        public ClassDescriptor getBoolean() {
374            return getPrimitiveClassDescriptor(BOOLEAN);
375        }
376    
377        @NotNull
378        public Set<DeclarationDescriptor> getIntegralRanges() {
379            return SetsKt.<DeclarationDescriptor>setOf(
380                    getBuiltInClassByName("CharRange", rangesPackageFragment),
381                    getBuiltInClassByName("IntRange", rangesPackageFragment)
382                    // TODO: contains in LongRange should be optimized too
383            );
384        }
385    
386        @NotNull
387        public ClassDescriptor getArray() {
388            return getBuiltInClassByName("Array");
389        }
390    
391        @NotNull
392        public ClassDescriptor getPrimitiveArrayClassDescriptor(@NotNull PrimitiveType type) {
393            return getBuiltInClassByName(type.getArrayTypeName().asString());
394        }
395    
396        @NotNull
397        public ClassDescriptor getNumber() {
398            return getBuiltInClassByName("Number");
399        }
400    
401        @NotNull
402        public ClassDescriptor getUnit() {
403            return getBuiltInClassByName("Unit");
404        }
405    
406        @NotNull
407        public static String getFunctionName(int parameterCount) {
408            return "Function" + parameterCount;
409        }
410    
411        @NotNull
412        public ClassDescriptor getFunction(int parameterCount) {
413            return getBuiltInClassByName(getFunctionName(parameterCount));
414        }
415    
416        @NotNull
417        public ClassDescriptor getThrowable() {
418            return getBuiltInClassByName("Throwable");
419        }
420    
421        @NotNull
422        public ClassDescriptor getCloneable() {
423            return getBuiltInClassByName("Cloneable");
424        }
425    
426        @NotNull
427        public ClassDescriptor getDeprecatedAnnotation() {
428            return getBuiltInClassByName(FQ_NAMES.deprecated.shortName());
429        }
430    
431        @Nullable
432        private static ClassDescriptor getEnumEntry(@NotNull ClassDescriptor enumDescriptor, @NotNull String entryName) {
433            ClassifierDescriptor result = enumDescriptor.getUnsubstitutedInnerClassesScope().getContributedClassifier(
434                    Name.identifier(entryName), NoLookupLocation.FROM_BUILTINS
435            );
436            return result instanceof ClassDescriptor ? (ClassDescriptor) result : null;
437        }
438    
439        @Nullable
440        public ClassDescriptor getDeprecationLevelEnumEntry(@NotNull String level) {
441            return getEnumEntry(getBuiltInClassByName(FQ_NAMES.deprecationLevel.shortName()), level);
442        }
443    
444        @NotNull
445        public ClassDescriptor getTargetAnnotation() {
446            return getAnnotationClassByName(FQ_NAMES.target.shortName());
447        }
448    
449        @NotNull
450        public ClassDescriptor getRetentionAnnotation() {
451            return getAnnotationClassByName(FQ_NAMES.retention.shortName());
452        }
453    
454        @NotNull
455        public ClassDescriptor getRepeatableAnnotation() {
456            return getAnnotationClassByName(FQ_NAMES.repeatable.shortName());
457        }
458    
459        @NotNull
460        public ClassDescriptor getMustBeDocumentedAnnotation() {
461            return getAnnotationClassByName(FQ_NAMES.mustBeDocumented.shortName());
462        }
463    
464        @Nullable
465        public ClassDescriptor getAnnotationTargetEnumEntry(@NotNull KotlinTarget target) {
466            return getEnumEntry(getAnnotationClassByName(FQ_NAMES.annotationTarget.shortName()), target.name());
467        }
468    
469        @Nullable
470        public ClassDescriptor getAnnotationRetentionEnumEntry(@NotNull KotlinRetention retention) {
471            return getEnumEntry(getAnnotationClassByName(FQ_NAMES.annotationRetention.shortName()), retention.name());
472        }
473    
474        @NotNull
475        public ClassDescriptor getString() {
476            return getBuiltInClassByName("String");
477        }
478    
479        @NotNull
480        public ClassDescriptor getCharSequence() {
481            return getBuiltInClassByName("CharSequence");
482        }
483    
484        @NotNull
485        public ClassDescriptor getComparable() {
486            return getBuiltInClassByName("Comparable");
487        }
488    
489        @NotNull
490        public ClassDescriptor getEnum() {
491            return getBuiltInClassByName("Enum");
492        }
493    
494        @NotNull
495        public ClassDescriptor getAnnotation() {
496            return getBuiltInClassByName("Annotation");
497        }
498    
499        @NotNull
500        public ClassDescriptor getIterator() {
501            return getBuiltInClassByName("Iterator", collectionsPackageFragment);
502        }
503    
504        @NotNull
505        public ClassDescriptor getIterable() {
506            return getBuiltInClassByName("Iterable", collectionsPackageFragment);
507        }
508    
509        @NotNull
510        public ClassDescriptor getMutableIterable() {
511            return getBuiltInClassByName("MutableIterable", collectionsPackageFragment);
512        }
513    
514        @NotNull
515        public ClassDescriptor getMutableIterator() {
516            return getBuiltInClassByName("MutableIterator", collectionsPackageFragment);
517        }
518    
519        @NotNull
520        public ClassDescriptor getCollection() {
521            return getBuiltInClassByName("Collection", collectionsPackageFragment);
522        }
523    
524        @NotNull
525        public ClassDescriptor getMutableCollection() {
526            return getBuiltInClassByName("MutableCollection", collectionsPackageFragment);
527        }
528    
529        @NotNull
530        public ClassDescriptor getList() {
531            return getBuiltInClassByName("List", collectionsPackageFragment);
532        }
533    
534        @NotNull
535        public ClassDescriptor getMutableList() {
536            return getBuiltInClassByName("MutableList", collectionsPackageFragment);
537        }
538    
539        @NotNull
540        public ClassDescriptor getSet() {
541            return getBuiltInClassByName("Set", collectionsPackageFragment);
542        }
543    
544        @NotNull
545        public ClassDescriptor getMutableSet() {
546            return getBuiltInClassByName("MutableSet", collectionsPackageFragment);
547        }
548    
549        @NotNull
550        public ClassDescriptor getMap() {
551            return getBuiltInClassByName("Map", collectionsPackageFragment);
552        }
553    
554        @NotNull
555        public ClassDescriptor getMutableMap() {
556            return getBuiltInClassByName("MutableMap", collectionsPackageFragment);
557        }
558    
559        @NotNull
560        public ClassDescriptor getMapEntry() {
561            ClassDescriptor classDescriptor = DescriptorUtils.getInnerClassByName(getMap(), "Entry", NoLookupLocation.FROM_BUILTINS);
562            assert classDescriptor != null : "Can't find Map.Entry";
563            return classDescriptor;
564        }
565    
566        @NotNull
567        public ClassDescriptor getMutableMapEntry() {
568            ClassDescriptor classDescriptor = DescriptorUtils.getInnerClassByName(getMutableMap(), "MutableEntry", NoLookupLocation.FROM_BUILTINS);
569            assert classDescriptor != null : "Can't find MutableMap.MutableEntry";
570            return classDescriptor;
571        }
572    
573        @NotNull
574        public ClassDescriptor getListIterator() {
575            return getBuiltInClassByName("ListIterator", collectionsPackageFragment);
576        }
577    
578        @NotNull
579        public ClassDescriptor getMutableListIterator() {
580            return getBuiltInClassByName("MutableListIterator", collectionsPackageFragment);
581        }
582    
583        @NotNull
584        private KotlinType getBuiltInTypeByClassName(@NotNull String classSimpleName) {
585            return getBuiltInClassByName(classSimpleName).getDefaultType();
586        }
587    
588        @NotNull
589        public KotlinType getNothingType() {
590            return getNothing().getDefaultType();
591        }
592    
593        @NotNull
594        public KotlinType getNullableNothingType() {
595            return TypeUtils.makeNullable(getNothingType());
596        }
597    
598        @NotNull
599        public KotlinType getAnyType() {
600            return getAny().getDefaultType();
601        }
602    
603        @NotNull
604        public KotlinType getNullableAnyType() {
605            return TypeUtils.makeNullable(getAnyType());
606        }
607    
608        @NotNull
609        public KotlinType getDefaultBound() {
610            return getNullableAnyType();
611        }
612    
613        @NotNull
614        public KotlinType getPrimitiveKotlinType(@NotNull PrimitiveType type) {
615            return getPrimitiveClassDescriptor(type).getDefaultType();
616        }
617    
618        @NotNull
619        public KotlinType getByteType() {
620            return getPrimitiveKotlinType(BYTE);
621        }
622    
623        @NotNull
624        public KotlinType getShortType() {
625            return getPrimitiveKotlinType(SHORT);
626        }
627    
628        @NotNull
629        public KotlinType getIntType() {
630            return getPrimitiveKotlinType(INT);
631        }
632    
633        @NotNull
634        public KotlinType getLongType() {
635            return getPrimitiveKotlinType(LONG);
636        }
637    
638        @NotNull
639        public KotlinType getFloatType() {
640            return getPrimitiveKotlinType(FLOAT);
641        }
642    
643        @NotNull
644        public KotlinType getDoubleType() {
645            return getPrimitiveKotlinType(DOUBLE);
646        }
647    
648        @NotNull
649        public KotlinType getCharType() {
650            return getPrimitiveKotlinType(CHAR);
651        }
652    
653        @NotNull
654        public KotlinType getBooleanType() {
655            return getPrimitiveKotlinType(BOOLEAN);
656        }
657    
658        @NotNull
659        public KotlinType getUnitType() {
660            return getUnit().getDefaultType();
661        }
662    
663        @NotNull
664        public KotlinType getStringType() {
665            return getString().getDefaultType();
666        }
667    
668        @NotNull
669        public KotlinType getArrayElementType(@NotNull KotlinType arrayType) {
670            if (isArray(arrayType)) {
671                if (arrayType.getArguments().size() != 1) {
672                    throw new IllegalStateException();
673                }
674                return arrayType.getArguments().get(0).getType();
675            }
676            KotlinType primitiveType = kotlinArrayTypeToPrimitiveKotlinType.get(TypeUtils.makeNotNullable(arrayType));
677            if (primitiveType == null) {
678                throw new IllegalStateException("not array: " + arrayType);
679            }
680            return primitiveType;
681        }
682    
683        @NotNull
684        public KotlinType getPrimitiveArrayKotlinType(@NotNull PrimitiveType primitiveType) {
685            return primitiveTypeToArrayKotlinType.get(primitiveType);
686        }
687    
688        /**
689         * @return {@code null} if not primitive
690         */
691        @Nullable
692        public KotlinType getPrimitiveArrayKotlinTypeByPrimitiveKotlinType(@NotNull KotlinType kotlinType) {
693            return primitiveKotlinTypeToKotlinArrayType.get(kotlinType);
694        }
695    
696        public static boolean isPrimitiveArray(@NotNull FqNameUnsafe arrayFqName) {
697            return getPrimitiveTypeByArrayClassFqName(arrayFqName) != null;
698        }
699    
700        @Nullable
701        public static PrimitiveType getPrimitiveTypeByFqName(@NotNull FqNameUnsafe primitiveClassFqName) {
702            return FQ_NAMES.fqNameToPrimitiveType.get(primitiveClassFqName);
703        }
704    
705        @Nullable
706        public static PrimitiveType getPrimitiveTypeByArrayClassFqName(@NotNull FqNameUnsafe primitiveArrayClassFqName) {
707            return FQ_NAMES.arrayClassFqNameToPrimitiveType.get(primitiveArrayClassFqName);
708        }
709    
710        @NotNull
711        public KotlinType getArrayType(@NotNull Variance projectionType, @NotNull KotlinType argument) {
712            List<TypeProjectionImpl> types = Collections.singletonList(new TypeProjectionImpl(projectionType, argument));
713            return KotlinTypeImpl.create(
714                    Annotations.Companion.getEMPTY(),
715                    getArray(),
716                    false,
717                    types
718            );
719        }
720    
721        @NotNull
722        public KotlinType getEnumType(@NotNull KotlinType argument) {
723            Variance projectionType = Variance.INVARIANT;
724            List<TypeProjectionImpl> types = Collections.singletonList(new TypeProjectionImpl(projectionType, argument));
725            return KotlinTypeImpl.create(
726                    Annotations.Companion.getEMPTY(),
727                    getEnum(),
728                    false,
729                    types
730            );
731        }
732    
733        @NotNull
734        public KotlinType getAnnotationType() {
735            return getAnnotation().getDefaultType();
736        }
737    
738        public static boolean isArray(@NotNull KotlinType type) {
739            return isConstructedFromGivenClass(type, FQ_NAMES.array);
740        }
741    
742        public static boolean isArrayOrPrimitiveArray(@NotNull ClassDescriptor descriptor) {
743            return classFqNameEquals(descriptor, FQ_NAMES.array) || getPrimitiveTypeByArrayClassFqName(getFqName(descriptor)) != null;
744        }
745    
746        public static boolean isPrimitiveArray(@NotNull KotlinType type) {
747            ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
748            return descriptor != null && getPrimitiveTypeByArrayClassFqName(getFqName(descriptor)) != null;
749        }
750    
751        public static boolean isPrimitiveType(@NotNull KotlinType type) {
752            ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
753            return !type.isMarkedNullable() && descriptor instanceof ClassDescriptor && isPrimitiveClass((ClassDescriptor) descriptor);
754        }
755    
756        public static boolean isPrimitiveClass(@NotNull ClassDescriptor descriptor) {
757            return getPrimitiveTypeByFqName(getFqName(descriptor)) != null;
758        }
759    
760        private static boolean isConstructedFromGivenClass(@NotNull KotlinType type, @NotNull FqNameUnsafe fqName) {
761            ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
762            return descriptor instanceof ClassDescriptor && classFqNameEquals(descriptor, fqName);
763        }
764    
765        private static boolean classFqNameEquals(@NotNull ClassifierDescriptor descriptor, @NotNull FqNameUnsafe fqName) {
766            // Quick check to avoid creation of full FqName instance
767            return descriptor.getName().equals(fqName.shortName()) &&
768                   fqName.equals(getFqName(descriptor));
769        }
770    
771        private static boolean isNotNullConstructedFromGivenClass(@NotNull KotlinType type, @NotNull FqNameUnsafe fqName) {
772            return !type.isMarkedNullable() && isConstructedFromGivenClass(type, fqName);
773        }
774    
775        public static boolean isSpecialClassWithNoSupertypes(@NotNull ClassDescriptor descriptor) {
776            return classFqNameEquals(descriptor, FQ_NAMES.any) || classFqNameEquals(descriptor, FQ_NAMES.nothing);
777        }
778    
779        public static boolean isAny(@NotNull ClassDescriptor descriptor) {
780            return classFqNameEquals(descriptor, FQ_NAMES.any);
781        }
782    
783        public static boolean isAny(@NotNull KotlinType type) {
784            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES.any);
785        }
786    
787        public static boolean isBoolean(@NotNull KotlinType type) {
788            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._boolean);
789        }
790    
791        public static boolean isBooleanOrNullableBoolean(@NotNull KotlinType type) {
792            return isConstructedFromGivenClass(type, FQ_NAMES._boolean);
793        }
794    
795        public static boolean isBoolean(@NotNull ClassDescriptor classDescriptor) {
796            return classFqNameEquals(classDescriptor, FQ_NAMES._boolean);
797        }
798    
799        public static boolean isChar(@NotNull KotlinType type) {
800            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._char);
801        }
802    
803        public static boolean isInt(@NotNull KotlinType type) {
804            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._int);
805        }
806    
807        public static boolean isByte(@NotNull KotlinType type) {
808            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._byte);
809        }
810    
811        public static boolean isLong(@NotNull KotlinType type) {
812            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._long);
813        }
814    
815        public static boolean isShort(@NotNull KotlinType type) {
816            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._short);
817        }
818    
819        public static boolean isFloat(@NotNull KotlinType type) {
820            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._float);
821        }
822    
823        public static boolean isDouble(@NotNull KotlinType type) {
824            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._double);
825        }
826    
827        private static boolean isConstructedFromGivenClassAndNotNullable(@NotNull KotlinType type, @NotNull FqNameUnsafe fqName) {
828            return isConstructedFromGivenClass(type, fqName) && !type.isMarkedNullable();
829        }
830    
831        public static boolean isNothing(@NotNull KotlinType type) {
832            return isNothingOrNullableNothing(type)
833                   && !type.isMarkedNullable();
834        }
835    
836        public static boolean isNullableNothing(@NotNull KotlinType type) {
837            return isNothingOrNullableNothing(type)
838                   && type.isMarkedNullable();
839        }
840    
841        public static boolean isNothingOrNullableNothing(@NotNull KotlinType type) {
842            return isConstructedFromGivenClass(type, FQ_NAMES.nothing);
843        }
844    
845        public static boolean isAnyOrNullableAny(@NotNull KotlinType type) {
846            return isConstructedFromGivenClass(type, FQ_NAMES.any);
847        }
848    
849        public static boolean isNullableAny(@NotNull KotlinType type) {
850            return isAnyOrNullableAny(type) && type.isMarkedNullable();
851        }
852    
853        public static boolean isDefaultBound(@NotNull KotlinType type) {
854            return isNullableAny(type);
855        }
856    
857        public static boolean isUnit(@NotNull KotlinType type) {
858            return isNotNullConstructedFromGivenClass(type, FQ_NAMES.unit);
859        }
860    
861        public static boolean isUnitOrNullableUnit(@NotNull KotlinType type) {
862            return isConstructedFromGivenClass(type, FQ_NAMES.unit);
863        }
864    
865        public boolean isBooleanOrSubtype(@NotNull KotlinType type) {
866            return KotlinTypeChecker.DEFAULT.isSubtypeOf(type, getBooleanType());
867        }
868    
869        public boolean isMemberOfAny(@NotNull DeclarationDescriptor descriptor) {
870            return descriptor.getContainingDeclaration() == getAny();
871        }
872    
873        public static boolean isString(@Nullable KotlinType type) {
874            return type != null && isNotNullConstructedFromGivenClass(type, FQ_NAMES.string);
875        }
876    
877        public static boolean isCollectionOrNullableCollection(@NotNull KotlinType type) {
878            return isConstructedFromGivenClass(type, FQ_NAMES._collection);
879        }
880    
881        public static boolean isListOrNullableList(@NotNull KotlinType type) {
882            return isConstructedFromGivenClass(type, FQ_NAMES._list);
883        }
884    
885        public static boolean isSetOrNullableSet(@NotNull KotlinType type) {
886            return isConstructedFromGivenClass(type, FQ_NAMES._set);
887        }
888    
889        public static boolean isIterableOrNullableIterable(@NotNull KotlinType type) {
890            return isConstructedFromGivenClass(type, FQ_NAMES._iterable);
891        }
892    
893        public static boolean isKClass(@NotNull ClassDescriptor descriptor) {
894            return classFqNameEquals(descriptor, FQ_NAMES.kClass);
895        }
896    
897        public static boolean isNonPrimitiveArray(@NotNull ClassDescriptor descriptor) {
898            return classFqNameEquals(descriptor, FQ_NAMES.array);
899        }
900    
901        public static boolean isCloneable(@NotNull ClassDescriptor descriptor) {
902            return classFqNameEquals(descriptor, FQ_NAMES.cloneable);
903        }
904    
905        public static boolean isDeprecated(@NotNull DeclarationDescriptor declarationDescriptor) {
906            if (containsAnnotation(declarationDescriptor, FQ_NAMES.deprecated)) return true;
907    
908            if (declarationDescriptor instanceof PropertyDescriptor) {
909                boolean isVar = ((PropertyDescriptor) declarationDescriptor).isVar();
910                PropertyGetterDescriptor getter = ((PropertyDescriptor) declarationDescriptor).getGetter();
911                PropertySetterDescriptor setter = ((PropertyDescriptor) declarationDescriptor).getSetter();
912                return getter != null && isDeprecated(getter) && (!isVar || setter != null && isDeprecated(setter));
913            }
914    
915            return false;
916        }
917    
918        public static boolean isSuppressAnnotation(@NotNull AnnotationDescriptor annotationDescriptor) {
919            return isConstructedFromGivenClass(annotationDescriptor.getType(), FQ_NAMES.suppress);
920        }
921    
922        private static boolean containsAnnotation(DeclarationDescriptor descriptor, FqName annotationClassFqName) {
923            DeclarationDescriptor original = descriptor.getOriginal();
924            Annotations annotations = original.getAnnotations();
925    
926            if (annotations.findAnnotation(annotationClassFqName) != null) return true;
927    
928            AnnotationUseSiteTarget associatedUseSiteTarget = AnnotationUseSiteTarget.Companion.getAssociatedUseSiteTarget(descriptor);
929            if (associatedUseSiteTarget != null) {
930                if (Annotations.Companion.findUseSiteTargetedAnnotation(annotations, associatedUseSiteTarget, annotationClassFqName) != null) {
931                    return true;
932                }
933            }
934    
935            return false;
936        }
937    }