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.descriptors;
018    
019    import kotlin.collections.SetsKt;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.kotlin.resolve.DescriptorUtils;
023    import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
024    import org.jetbrains.kotlin.resolve.scopes.receivers.SuperCallReceiverValue;
025    import org.jetbrains.kotlin.resolve.scopes.receivers.ThisClassReceiver;
026    import org.jetbrains.kotlin.types.DynamicTypesKt;
027    import org.jetbrains.kotlin.types.KotlinType;
028    import org.jetbrains.kotlin.util.ModuleVisibilityHelper;
029    import org.jetbrains.kotlin.utils.CollectionsKt;
030    
031    import java.util.*;
032    
033    public class Visibilities {
034        public static final Visibility PRIVATE = new Visibility("private", false) {
035            @Override
036            public boolean mustCheckInImports() {
037                return true;
038            }
039    
040            @Override
041            public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
042                if (DescriptorUtils.isTopLevelDeclaration(what)) {
043                    SourceFile fromContainingFile = DescriptorUtils.getContainingSourceFile(from);
044                    if (fromContainingFile != SourceFile.NO_SOURCE_FILE) {
045                        return fromContainingFile.equals(DescriptorUtils.getContainingSourceFile(what));
046                    }
047                }
048    
049                DeclarationDescriptor parent = what;
050                while (parent != null) {
051                    parent = parent.getContainingDeclaration();
052                    if ((parent instanceof ClassDescriptor && !DescriptorUtils.isCompanionObject(parent)) ||
053                        parent instanceof PackageFragmentDescriptor) {
054                        break;
055                    }
056                }
057                if (parent == null) {
058                    return false;
059                }
060                DeclarationDescriptor fromParent = from;
061                while (fromParent != null) {
062                    if (parent == fromParent) {
063                        return true;
064                    }
065                    if (fromParent instanceof PackageFragmentDescriptor) {
066                        return parent instanceof PackageFragmentDescriptor
067                               && ((PackageFragmentDescriptor) parent).getFqName().equals(((PackageFragmentDescriptor) fromParent).getFqName())
068                               && DescriptorUtils.areInSameModule(fromParent, parent);
069                    }
070                    fromParent = fromParent.getContainingDeclaration();
071                }
072                return false;
073            }
074        };
075    
076        /**
077         * This visibility is needed for the next case:
078         *  class A<in T>(t: T) {
079         *      private val t: T = t // visibility for t is PRIVATE_TO_THIS
080         *
081         *      fun test() {
082         *          val x: T = t // correct
083         *          val y: T = this.t // also correct
084         *      }
085         *      fun foo(a: A<String>) {
086         *         val x: String = a.t // incorrect, because a.t can be Any
087         *      }
088         *  }
089         */
090        public static final Visibility PRIVATE_TO_THIS = new Visibility("private_to_this", false) {
091            @Override
092            public boolean isVisible(@Nullable ReceiverValue thisObject, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
093                if (PRIVATE.isVisible(thisObject, what, from)) {
094                    // See Visibility.isVisible contract
095                    if (thisObject == ALWAYS_SUITABLE_RECEIVER) return true;
096                    if (thisObject == IRRELEVANT_RECEIVER) return false;
097    
098                    DeclarationDescriptor classDescriptor = DescriptorUtils.getParentOfType(what, ClassDescriptor.class);
099    
100                    if (classDescriptor != null && thisObject instanceof ThisClassReceiver) {
101                        return ((ThisClassReceiver) thisObject).getClassDescriptor().getOriginal().equals(classDescriptor.getOriginal());
102                    }
103                }
104                return false;
105            }
106    
107            @Override
108            public boolean mustCheckInImports() {
109                return true;
110            }
111    
112            @NotNull
113            @Override
114            public String getDisplayName() {
115                return "private/*private to this*/";
116            }
117        };
118    
119        public static final Visibility PROTECTED = new Visibility("protected", true) {
120            @Override
121            public boolean mustCheckInImports() {
122                return false;
123            }
124    
125            @Override
126            public boolean isVisible(
127                    @Nullable ReceiverValue receiver,
128                    @NotNull DeclarationDescriptorWithVisibility what,
129                    @NotNull DeclarationDescriptor from
130            ) {
131                ClassDescriptor givenDescriptorContainingClass = DescriptorUtils.getParentOfType(what, ClassDescriptor.class);
132                ClassDescriptor fromClass = DescriptorUtils.getParentOfType(from, ClassDescriptor.class, false);
133                if (fromClass == null) return false;
134    
135                if (givenDescriptorContainingClass != null && DescriptorUtils.isCompanionObject(givenDescriptorContainingClass)) {
136                    // Access to protected members inside companion is allowed to all subclasses
137                    // Receiver type does not matter because objects are final
138                    // NB: protected fake overrides in companion from super class should also be allowed
139                    ClassDescriptor companionOwner = DescriptorUtils.getParentOfType(givenDescriptorContainingClass, ClassDescriptor.class);
140                    if (companionOwner != null && DescriptorUtils.isSubclass(fromClass, companionOwner)) return true;
141                }
142    
143                // The rest part of method checks visibility similarly to Java does for protected (see JLS p.6.6.2)
144    
145                // Protected fake overrides can have only one protected overridden (as protected is not allowed for interface members)
146                DeclarationDescriptorWithVisibility whatDeclaration = DescriptorUtils.unwrapFakeOverrideToAnyDeclaration(what);
147    
148                ClassDescriptor classDescriptor = DescriptorUtils.getParentOfType(whatDeclaration, ClassDescriptor.class);
149                if (classDescriptor == null) return false;
150    
151                if (DescriptorUtils.isSubclass(fromClass, classDescriptor)
152                        && doesReceiverFitForProtectedVisibility(receiver, whatDeclaration, fromClass)) {
153                    return true;
154                }
155    
156                return isVisible(receiver, what, fromClass.getContainingDeclaration());
157            }
158    
159            private boolean doesReceiverFitForProtectedVisibility(
160                    @Nullable ReceiverValue receiver,
161                    @NotNull DeclarationDescriptorWithVisibility whatDeclaration,
162                    @NotNull ClassDescriptor fromClass
163            ) {
164                //noinspection deprecation
165                if (receiver == FALSE_IF_PROTECTED) return false;
166    
167                // Do not check receiver for non-callable declarations
168                if (!(whatDeclaration instanceof CallableMemberDescriptor)) return true;
169                // Constructor accessibility check is performed manually
170                if (whatDeclaration instanceof ConstructorDescriptor) return true;
171    
172                // See Visibility.isVisible contract
173                if (receiver == ALWAYS_SUITABLE_RECEIVER) return true;
174                if (receiver == IRRELEVANT_RECEIVER || receiver == null) return false;
175    
176                KotlinType actualReceiverType = receiver instanceof SuperCallReceiverValue
177                                                ? ((SuperCallReceiverValue) receiver).getThisType()
178                                                : receiver.getType();
179    
180                return DescriptorUtils.isSubtypeOfClass(actualReceiverType, fromClass) || DynamicTypesKt.isDynamic(actualReceiverType);
181            }
182        };
183    
184        public static final Visibility INTERNAL = new Visibility("internal", false) {
185            @Override
186            public boolean mustCheckInImports() {
187                return true;
188            }
189    
190            @Override
191            public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
192                DeclarationDescriptor fromOrModule = from instanceof PackageViewDescriptor ? ((PackageViewDescriptor) from).getModule() : from;
193                if (!DescriptorUtils.getContainingModule(what).isFriend(DescriptorUtils.getContainingModule(fromOrModule))) return false;
194    
195                return MODULE_VISIBILITY_HELPER.isInFriendModule(what, from);
196            }
197        };
198    
199        public static final Visibility PUBLIC = new Visibility("public", true) {
200            @Override
201            public boolean mustCheckInImports() {
202                return false;
203            }
204    
205            @Override
206            public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
207                return true;
208            }
209        };
210    
211        public static final Visibility LOCAL = new Visibility("local", false) {
212            @Override
213            public boolean mustCheckInImports() {
214                throw new IllegalStateException("This method shouldn't be invoked for LOCAL visibility");
215            }
216    
217            @Override
218            public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
219                throw new IllegalStateException("This method shouldn't be invoked for LOCAL visibility");
220            }
221        };
222    
223        public static final Visibility INHERITED = new Visibility("inherited", false) {
224            @Override
225            public boolean mustCheckInImports() {
226                throw new IllegalStateException("This method shouldn't be invoked for INHERITED visibility");
227            }
228    
229            @Override
230            public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
231                throw new IllegalStateException("Visibility is unknown yet"); //This method shouldn't be invoked for INHERITED visibility
232            }
233        };
234    
235        /* Visibility for fake override invisible members (they are created for better error reporting) */
236        public static final Visibility INVISIBLE_FAKE = new Visibility("invisible_fake", false) {
237            @Override
238            public boolean mustCheckInImports() {
239                throw new IllegalStateException("This method shouldn't be invoked for INVISIBLE_FAKE visibility");
240            }
241    
242            @Override
243            public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
244                return false;
245            }
246        };
247    
248        // Currently used as default visibility of FunctionDescriptor
249        // It's needed to prevent NPE when requesting non-nullable visibility of descriptor before `initialize` has been called
250        public static final Visibility UNKNOWN = new Visibility("unknown", false) {
251            @Override
252            public boolean mustCheckInImports() {
253                throw new IllegalStateException("This method shouldn't be invoked for UNKNOWN visibility");
254            }
255    
256            @Override
257            public boolean isVisible(
258                    @Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from
259            ) {
260                return false;
261            }
262        };
263    
264        public static final Set<Visibility> INVISIBLE_FROM_OTHER_MODULES =
265                Collections.unmodifiableSet(SetsKt.setOf(PRIVATE, PRIVATE_TO_THIS, INTERNAL, LOCAL));
266    
267        private Visibilities() {
268        }
269    
270        public static boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
271            return findInvisibleMember(receiver, what, from) == null;
272        }
273    
274        /**
275         * @see Visibility.isVisible contract
276         */
277        public static boolean isVisibleIgnoringReceiver(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
278            return findInvisibleMember(ALWAYS_SUITABLE_RECEIVER, what, from) == null;
279        }
280    
281        /**
282         * @see Visibility.isVisible contract
283         * @see Visibilities.RECEIVER_DOES_NOT_EXIST
284         */
285        public static boolean isVisibleWithAnyReceiver(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
286            return findInvisibleMember(IRRELEVANT_RECEIVER, what, from) == null;
287        }
288    
289        @Nullable
290        public static DeclarationDescriptorWithVisibility findInvisibleMember(
291                @Nullable ReceiverValue receiver,
292                @NotNull DeclarationDescriptorWithVisibility what,
293                @NotNull DeclarationDescriptor from
294        ) {
295            DeclarationDescriptorWithVisibility parent = (DeclarationDescriptorWithVisibility) what.getOriginal();
296            while (parent != null && parent.getVisibility() != LOCAL) {
297                if (!parent.getVisibility().isVisible(receiver, parent, from)) {
298                    return parent;
299                }
300                parent = DescriptorUtils.getParentOfType(parent, DeclarationDescriptorWithVisibility.class);
301            }
302            return null;
303        }
304    
305        private static final Map<Visibility, Integer> ORDERED_VISIBILITIES;
306    
307        static {
308            Map<Visibility, Integer> visibilities = CollectionsKt.newHashMapWithExpectedSize(4);
309            visibilities.put(PRIVATE_TO_THIS, 0);
310            visibilities.put(PRIVATE, 0);
311            visibilities.put(INTERNAL, 1);
312            visibilities.put(PROTECTED, 1);
313            visibilities.put(PUBLIC, 2);
314            ORDERED_VISIBILITIES = Collections.unmodifiableMap(visibilities);
315        }
316    
317        /*package*/
318        @Nullable
319        static Integer compareLocal(@NotNull Visibility first, @NotNull Visibility second) {
320            if (first == second) return 0;
321            Integer firstIndex = ORDERED_VISIBILITIES.get(first);
322            Integer secondIndex = ORDERED_VISIBILITIES.get(second);
323            if (firstIndex == null || secondIndex == null || firstIndex.equals(secondIndex)) {
324                return null;
325            }
326            return firstIndex - secondIndex;
327        }
328    
329        @Nullable
330        public static Integer compare(@NotNull Visibility first, @NotNull Visibility second) {
331            Integer result = first.compareTo(second);
332            if (result != null) {
333                return result;
334            }
335            Integer oppositeResult = second.compareTo(first);
336            if (oppositeResult != null) {
337                return -oppositeResult;
338            }
339            return null;
340        }
341    
342        public static final Visibility DEFAULT_VISIBILITY = PUBLIC;
343    
344        /**
345         * This value should be used for receiverValue parameter of Visibility.isVisible
346         * iff there is intention to determine if member is visible for any receiver.
347         */
348        private static final ReceiverValue IRRELEVANT_RECEIVER = new ReceiverValue() {
349            @NotNull
350            @Override
351            public KotlinType getType() {
352                throw new IllegalStateException("This method should not be called");
353            }
354        };
355    
356        /**
357         * This value should be used for receiverValue parameter of Visibility.isVisible
358         * iff there is intention to determine if member is visible without receiver related checks being performed.
359         */
360        public static final ReceiverValue ALWAYS_SUITABLE_RECEIVER = new ReceiverValue() {
361            @NotNull
362            @Override
363            public KotlinType getType() {
364                throw new IllegalStateException("This method should not be called");
365            }
366        };
367    
368        // This constant is not intended to use somewhere else from
369        @Deprecated
370        public static final ReceiverValue FALSE_IF_PROTECTED = new ReceiverValue() {
371            @NotNull
372            @Override
373            public KotlinType getType() {
374                throw new IllegalStateException("This method should not be called");
375            }
376        };
377    
378        public static boolean isPrivate(@NotNull Visibility visibility) {
379            return visibility == PRIVATE || visibility == PRIVATE_TO_THIS;
380        }
381    
382        @NotNull
383        private static final ModuleVisibilityHelper MODULE_VISIBILITY_HELPER;
384    
385        static {
386            Iterator<ModuleVisibilityHelper> iterator = ServiceLoader.load(ModuleVisibilityHelper.class, ModuleVisibilityHelper.class.getClassLoader()).iterator();
387            MODULE_VISIBILITY_HELPER = iterator.hasNext() ? iterator.next() : ModuleVisibilityHelper.EMPTY.INSTANCE;
388        }
389    }