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