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(@NotNull 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 public static final Visibility PRIVATE_TO_THIS = new Visibility("private_to_this", false) {
074 @Override
075 public boolean isVisible(@NotNull ReceiverValue thisObject, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
076 if (PRIVATE.isVisible(thisObject, what, from)) {
077 DeclarationDescriptor classDescriptor = DescriptorUtils.getParentOfType(what, ClassDescriptor.class);
078
079 if (classDescriptor != null && thisObject instanceof ThisClassReceiver) {
080 return ((ThisClassReceiver) thisObject).getClassDescriptor().getOriginal().equals(classDescriptor.getOriginal());
081 }
082 }
083 return false;
084 }
085
086 @Override
087 public boolean mustCheckInImports() {
088 return true;
089 }
090
091 @NotNull
092 @Override
093 public String getDisplayName() {
094 return "private/*private to this*/";
095 }
096 };
097
098 public static final Visibility PROTECTED = new Visibility("protected", true) {
099 @Override
100 public boolean mustCheckInImports() {
101 return false;
102 }
103
104 @Override
105 public boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
106 ClassDescriptor classDescriptor = DescriptorUtils.getParentOfType(what, ClassDescriptor.class);
107 if (DescriptorUtils.isCompanionObject(classDescriptor)) {
108 classDescriptor = DescriptorUtils.getParentOfType(classDescriptor, ClassDescriptor.class);
109 }
110 if (classDescriptor == null) return false;
111
112 ClassDescriptor fromClass = DescriptorUtils.getParentOfType(from, ClassDescriptor.class, false);
113 if (fromClass == null) return false;
114 if (DescriptorUtils.isSubclass(fromClass, classDescriptor)) {
115 return true;
116 }
117 return isVisible(receiver, what, fromClass.getContainingDeclaration());
118 }
119 };
120
121 public static final Visibility INTERNAL = new Visibility("internal", false) {
122 @Override
123 public boolean mustCheckInImports() {
124 return true;
125 }
126
127 @Override
128 public boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
129 DeclarationDescriptor fromOrModule = from instanceof PackageViewDescriptor ? ((PackageViewDescriptor) from).getModule() : from;
130 if (!DescriptorUtils.getContainingModule(what).isFriend(DescriptorUtils.getContainingModule(fromOrModule))) return false;
131
132 return MODULE_VISIBILITY_HELPER.isInFriendModule(what, from);
133 }
134 };
135
136 public static final Visibility PUBLIC = new Visibility("public", true) {
137 @Override
138 public boolean mustCheckInImports() {
139 return false;
140 }
141
142 @Override
143 public boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
144 return true;
145 }
146 };
147
148 public static final Visibility LOCAL = new Visibility("local", false) {
149 @Override
150 public boolean mustCheckInImports() {
151 throw new IllegalStateException("This method shouldn't be invoked for LOCAL visibility");
152 }
153
154 @Override
155 public boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
156 throw new IllegalStateException("This method shouldn't be invoked for LOCAL visibility");
157 }
158 };
159
160 public static final Visibility INHERITED = new Visibility("inherited", false) {
161 @Override
162 public boolean mustCheckInImports() {
163 throw new IllegalStateException("This method shouldn't be invoked for INHERITED visibility");
164 }
165
166 @Override
167 public boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
168 throw new IllegalStateException("Visibility is unknown yet"); //This method shouldn't be invoked for INHERITED visibility
169 }
170 };
171
172 /* Visibility for fake override invisible members (they are created for better error reporting) */
173 public static final Visibility INVISIBLE_FAKE = new Visibility("invisible_fake", false) {
174 @Override
175 public boolean mustCheckInImports() {
176 throw new IllegalStateException("This method shouldn't be invoked for INVISIBLE_FAKE visibility");
177 }
178
179 @Override
180 public boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
181 return false;
182 }
183 };
184
185 // Currently used as default visibility of FunctionDescriptor
186 // It's needed to prevent NPE when requesting non-nullable visibility of descriptor before `initialize` has been called
187 public static final Visibility UNKNOWN = new Visibility("unknown", false) {
188 @Override
189 public boolean mustCheckInImports() {
190 throw new IllegalStateException("This method shouldn't be invoked for UNKNOWN visibility");
191 }
192
193 @Override
194 public boolean isVisible(
195 @NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from
196 ) {
197 return false;
198 }
199 };
200
201 public static final Set<Visibility> INVISIBLE_FROM_OTHER_MODULES =
202 Collections.unmodifiableSet(SetsKt.setOf(PRIVATE, PRIVATE_TO_THIS, INTERNAL, LOCAL));
203
204 private Visibilities() {
205 }
206
207 public static boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
208 return findInvisibleMember(receiver, what, from) == null;
209 }
210
211 @Nullable
212 public static DeclarationDescriptorWithVisibility findInvisibleMember(
213 @NotNull ReceiverValue receiver,
214 @NotNull DeclarationDescriptorWithVisibility what,
215 @NotNull DeclarationDescriptor from
216 ) {
217 DeclarationDescriptorWithVisibility parent = (DeclarationDescriptorWithVisibility) what.getOriginal();
218 while (parent != null && parent.getVisibility() != LOCAL) {
219 if (!parent.getVisibility().isVisible(receiver, parent, from)) {
220 return parent;
221 }
222 parent = DescriptorUtils.getParentOfType(parent, DeclarationDescriptorWithVisibility.class);
223 }
224 return null;
225 }
226
227 private static final Map<Visibility, Integer> ORDERED_VISIBILITIES;
228
229 static {
230 Map<Visibility, Integer> visibilities = CollectionsKt.newHashMapWithExpectedSize(4);
231 visibilities.put(PRIVATE_TO_THIS, 0);
232 visibilities.put(PRIVATE, 0);
233 visibilities.put(INTERNAL, 1);
234 visibilities.put(PROTECTED, 1);
235 visibilities.put(PUBLIC, 2);
236 ORDERED_VISIBILITIES = Collections.unmodifiableMap(visibilities);
237 }
238
239 /*package*/
240 @Nullable
241 static Integer compareLocal(@NotNull Visibility first, @NotNull Visibility second) {
242 if (first == second) return 0;
243 Integer firstIndex = ORDERED_VISIBILITIES.get(first);
244 Integer secondIndex = ORDERED_VISIBILITIES.get(second);
245 if (firstIndex == null || secondIndex == null || firstIndex.equals(secondIndex)) {
246 return null;
247 }
248 return firstIndex - secondIndex;
249 }
250
251 @Nullable
252 public static Integer compare(@NotNull Visibility first, @NotNull Visibility second) {
253 Integer result = first.compareTo(second);
254 if (result != null) {
255 return result;
256 }
257 Integer oppositeResult = second.compareTo(first);
258 if (oppositeResult != null) {
259 return -oppositeResult;
260 }
261 return null;
262 }
263
264 public static final Visibility DEFAULT_VISIBILITY = PUBLIC;
265
266 public static boolean isPrivate(@NotNull Visibility visibility) {
267 return visibility == PRIVATE || visibility == PRIVATE_TO_THIS;
268 }
269
270 @NotNull
271 private static final ModuleVisibilityHelper MODULE_VISIBILITY_HELPER;
272
273 static {
274 Iterator<ModuleVisibilityHelper> iterator = ServiceLoader.load(ModuleVisibilityHelper.class, ModuleVisibilityHelper.class.getClassLoader()).iterator();
275 MODULE_VISIBILITY_HELPER = iterator.hasNext() ? iterator.next() : ModuleVisibilityHelper.EMPTY.INSTANCE$;
276 }
277 }