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