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.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.ThisClassReceiver;
025 import org.jetbrains.kotlin.util.ModuleVisibilityHelper;
026 import org.jetbrains.kotlin.utils.CollectionsKt;
027
028 import java.util.*;
029
030 public class Visibilities {
031 public static final Visibility PRIVATE = new Visibility("private", false) {
032 @Override
033 public boolean mustCheckInImports() {
034 return true;
035 }
036
037 @Override
038 public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
039 if (DescriptorUtils.isTopLevelDeclaration(what)) {
040 SourceFile fromContainingFile = DescriptorUtils.getContainingSourceFile(from);
041 if (fromContainingFile != SourceFile.NO_SOURCE_FILE) {
042 return fromContainingFile.equals(DescriptorUtils.getContainingSourceFile(what));
043 }
044 }
045
046 DeclarationDescriptor parent = what;
047 while (parent != null) {
048 parent = parent.getContainingDeclaration();
049 if ((parent instanceof ClassDescriptor && !DescriptorUtils.isCompanionObject(parent)) ||
050 parent instanceof PackageFragmentDescriptor) {
051 break;
052 }
053 }
054 if (parent == null) {
055 return false;
056 }
057 DeclarationDescriptor fromParent = from;
058 while (fromParent != null) {
059 if (parent == fromParent) {
060 return true;
061 }
062 if (fromParent instanceof PackageFragmentDescriptor) {
063 return parent instanceof PackageFragmentDescriptor
064 && ((PackageFragmentDescriptor) parent).getFqName().equals(((PackageFragmentDescriptor) fromParent).getFqName())
065 && DescriptorUtils.areInSameModule(fromParent, parent);
066 }
067 fromParent = fromParent.getContainingDeclaration();
068 }
069 return false;
070 }
071 };
072
073 /**
074 * This visibility is needed for the next case:
075 * class A<in T>(t: T) {
076 * private val t: T = t // visibility for t is PRIVATE_TO_THIS
077 *
078 * fun test() {
079 * val x: T = t // correct
080 * val y: T = this.t // also correct
081 * }
082 * fun foo(a: A<String>) {
083 * val x: String = a.t // incorrect, because a.t can be Any
084 * }
085 * }
086 */
087 public static final Visibility PRIVATE_TO_THIS = new Visibility("private_to_this", false) {
088 @Override
089 public boolean isVisible(@Nullable ReceiverValue thisObject, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
090 if (PRIVATE.isVisible(thisObject, what, from)) {
091 DeclarationDescriptor classDescriptor = DescriptorUtils.getParentOfType(what, ClassDescriptor.class);
092
093 if (classDescriptor != null && thisObject instanceof ThisClassReceiver) {
094 return ((ThisClassReceiver) thisObject).getClassDescriptor().getOriginal().equals(classDescriptor.getOriginal());
095 }
096 }
097 return false;
098 }
099
100 @Override
101 public boolean mustCheckInImports() {
102 return true;
103 }
104
105 @NotNull
106 @Override
107 public String getDisplayName() {
108 return "private/*private to this*/";
109 }
110 };
111
112 public static final Visibility PROTECTED = new Visibility("protected", true) {
113 @Override
114 public boolean mustCheckInImports() {
115 return false;
116 }
117
118 @Override
119 public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
120 ClassDescriptor classDescriptor = DescriptorUtils.getParentOfType(what, ClassDescriptor.class);
121 if (DescriptorUtils.isCompanionObject(classDescriptor)) {
122 classDescriptor = DescriptorUtils.getParentOfType(classDescriptor, ClassDescriptor.class);
123 }
124 if (classDescriptor == null) return false;
125
126 ClassDescriptor fromClass = DescriptorUtils.getParentOfType(from, ClassDescriptor.class, false);
127 if (fromClass == null) return false;
128 if (DescriptorUtils.isSubclass(fromClass, classDescriptor)) {
129 return true;
130 }
131 return isVisible(receiver, what, fromClass.getContainingDeclaration());
132 }
133 };
134
135 public static final Visibility INTERNAL = new Visibility("internal", false) {
136 @Override
137 public boolean mustCheckInImports() {
138 return true;
139 }
140
141 @Override
142 public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
143 DeclarationDescriptor fromOrModule = from instanceof PackageViewDescriptor ? ((PackageViewDescriptor) from).getModule() : from;
144 if (!DescriptorUtils.getContainingModule(what).isFriend(DescriptorUtils.getContainingModule(fromOrModule))) return false;
145
146 return MODULE_VISIBILITY_HELPER.isInFriendModule(what, from);
147 }
148 };
149
150 public static final Visibility PUBLIC = new Visibility("public", true) {
151 @Override
152 public boolean mustCheckInImports() {
153 return false;
154 }
155
156 @Override
157 public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
158 return true;
159 }
160 };
161
162 public static final Visibility LOCAL = new Visibility("local", false) {
163 @Override
164 public boolean mustCheckInImports() {
165 throw new IllegalStateException("This method shouldn't be invoked for LOCAL visibility");
166 }
167
168 @Override
169 public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
170 throw new IllegalStateException("This method shouldn't be invoked for LOCAL visibility");
171 }
172 };
173
174 public static final Visibility INHERITED = new Visibility("inherited", false) {
175 @Override
176 public boolean mustCheckInImports() {
177 throw new IllegalStateException("This method shouldn't be invoked for INHERITED visibility");
178 }
179
180 @Override
181 public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
182 throw new IllegalStateException("Visibility is unknown yet"); //This method shouldn't be invoked for INHERITED visibility
183 }
184 };
185
186 /* Visibility for fake override invisible members (they are created for better error reporting) */
187 public static final Visibility INVISIBLE_FAKE = new Visibility("invisible_fake", false) {
188 @Override
189 public boolean mustCheckInImports() {
190 throw new IllegalStateException("This method shouldn't be invoked for INVISIBLE_FAKE visibility");
191 }
192
193 @Override
194 public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
195 return false;
196 }
197 };
198
199 // Currently used as default visibility of FunctionDescriptor
200 // It's needed to prevent NPE when requesting non-nullable visibility of descriptor before `initialize` has been called
201 public static final Visibility UNKNOWN = new Visibility("unknown", false) {
202 @Override
203 public boolean mustCheckInImports() {
204 throw new IllegalStateException("This method shouldn't be invoked for UNKNOWN visibility");
205 }
206
207 @Override
208 public boolean isVisible(
209 @Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from
210 ) {
211 return false;
212 }
213 };
214
215 public static final Set<Visibility> INVISIBLE_FROM_OTHER_MODULES =
216 Collections.unmodifiableSet(SetsKt.setOf(PRIVATE, PRIVATE_TO_THIS, INTERNAL, LOCAL));
217
218 private Visibilities() {
219 }
220
221 public static boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
222 return findInvisibleMember(receiver, what, from) == null;
223 }
224
225 /**
226 * Receiver used only for visibility PRIVATE_TO_THIS.
227 * For all other visibilities this method give correct result.
228 */
229 public static boolean isVisibleWithIrrelevantReceiver(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
230 return findInvisibleMember(null, what, from) == null;
231 }
232
233 @Nullable
234 public static DeclarationDescriptorWithVisibility findInvisibleMember(
235 @Nullable ReceiverValue receiver,
236 @NotNull DeclarationDescriptorWithVisibility what,
237 @NotNull DeclarationDescriptor from
238 ) {
239 DeclarationDescriptorWithVisibility parent = (DeclarationDescriptorWithVisibility) what.getOriginal();
240 while (parent != null && parent.getVisibility() != LOCAL) {
241 if (!parent.getVisibility().isVisible(receiver, parent, from)) {
242 return parent;
243 }
244 parent = DescriptorUtils.getParentOfType(parent, DeclarationDescriptorWithVisibility.class);
245 }
246 return null;
247 }
248
249 private static final Map<Visibility, Integer> ORDERED_VISIBILITIES;
250
251 static {
252 Map<Visibility, Integer> visibilities = CollectionsKt.newHashMapWithExpectedSize(4);
253 visibilities.put(PRIVATE_TO_THIS, 0);
254 visibilities.put(PRIVATE, 0);
255 visibilities.put(INTERNAL, 1);
256 visibilities.put(PROTECTED, 1);
257 visibilities.put(PUBLIC, 2);
258 ORDERED_VISIBILITIES = Collections.unmodifiableMap(visibilities);
259 }
260
261 /*package*/
262 @Nullable
263 static Integer compareLocal(@NotNull Visibility first, @NotNull Visibility second) {
264 if (first == second) return 0;
265 Integer firstIndex = ORDERED_VISIBILITIES.get(first);
266 Integer secondIndex = ORDERED_VISIBILITIES.get(second);
267 if (firstIndex == null || secondIndex == null || firstIndex.equals(secondIndex)) {
268 return null;
269 }
270 return firstIndex - secondIndex;
271 }
272
273 @Nullable
274 public static Integer compare(@NotNull Visibility first, @NotNull Visibility second) {
275 Integer result = first.compareTo(second);
276 if (result != null) {
277 return result;
278 }
279 Integer oppositeResult = second.compareTo(first);
280 if (oppositeResult != null) {
281 return -oppositeResult;
282 }
283 return null;
284 }
285
286 public static final Visibility DEFAULT_VISIBILITY = PUBLIC;
287
288 public static boolean isPrivate(@NotNull Visibility visibility) {
289 return visibility == PRIVATE || visibility == PRIVATE_TO_THIS;
290 }
291
292 @NotNull
293 private static final ModuleVisibilityHelper MODULE_VISIBILITY_HELPER;
294
295 static {
296 Iterator<ModuleVisibilityHelper> iterator = ServiceLoader.load(ModuleVisibilityHelper.class, ModuleVisibilityHelper.class.getClassLoader()).iterator();
297 MODULE_VISIBILITY_HELPER = iterator.hasNext() ? iterator.next() : ModuleVisibilityHelper.EMPTY.INSTANCE$;
298 }
299 }