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