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