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 }