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 protected 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().isAncestorOf(((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 protected 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 @Override
086 public String toString() {
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 protected 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 protected boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
122 //NOTE: supposedly temporarily
123 return PUBLIC.isVisible(receiver, what, from);
124 }
125 };
126
127 public static final Visibility PUBLIC = new Visibility("public", true) {
128 @Override
129 public boolean mustCheckInImports() {
130 return false;
131 }
132
133 @Override
134 protected boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
135 return true;
136 }
137 };
138
139 public static final Visibility LOCAL = new Visibility("local", false) {
140 @Override
141 public boolean mustCheckInImports() {
142 throw new IllegalStateException("This method shouldn't be invoked for LOCAL visibility");
143 }
144
145 @Override
146 protected boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
147 throw new IllegalStateException("This method shouldn't be invoked for LOCAL visibility");
148 }
149 };
150
151 public static final Visibility INHERITED = new Visibility("inherited", false) {
152 @Override
153 public boolean mustCheckInImports() {
154 throw new IllegalStateException("This method shouldn't be invoked for INHERITED visibility");
155 }
156
157 @Override
158 protected boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
159 throw new IllegalStateException("Visibility is unknown yet"); //This method shouldn't be invoked for INHERITED visibility
160 }
161 };
162
163 /* Visibility for fake override invisible members (they are created for better error reporting) */
164 public static final Visibility INVISIBLE_FAKE = new Visibility("invisible_fake", false) {
165 @Override
166 public boolean mustCheckInImports() {
167 throw new IllegalStateException("This method shouldn't be invoked for INVISIBLE_FAKE visibility");
168 }
169
170 @Override
171 protected boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
172 return false;
173 }
174 };
175
176 // Currently used as default visibility of FunctionDescriptor
177 // It's needed to prevent NPE when requesting non-nullable visibility of descriptor before `initialize` has been called
178 public static final Visibility UNKNOWN = new Visibility("unknown", false) {
179 @Override
180 public boolean mustCheckInImports() {
181 throw new IllegalStateException("This method shouldn't be invoked for UNKNOWN visibility");
182 }
183
184 @Override
185 protected boolean isVisible(
186 @NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from
187 ) {
188 return false;
189 }
190 };
191
192 public static final Set<Visibility> INVISIBLE_FROM_OTHER_MODULES =
193 Collections.unmodifiableSet(KotlinPackage.setOf(PRIVATE, PRIVATE_TO_THIS, INTERNAL, LOCAL));
194
195 private Visibilities() {
196 }
197
198 public static boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
199 return findInvisibleMember(receiver, what, from) == null;
200 }
201
202 @SuppressWarnings("UnusedDeclaration")
203 private static boolean isInFriendModule(@NotNull DeclarationDescriptor what, @NotNull DeclarationDescriptor from) {
204 return DescriptorUtils.getContainingModule(what).isFriend(DescriptorUtils.getContainingModule(from));
205 }
206
207 @Nullable
208 public static DeclarationDescriptorWithVisibility findInvisibleMember(
209 @NotNull ReceiverValue receiver,
210 @NotNull DeclarationDescriptorWithVisibility what,
211 @NotNull DeclarationDescriptor from
212 ) {
213 DeclarationDescriptorWithVisibility parent = what;
214 while (parent != null && parent.getVisibility() != LOCAL) {
215 if (!parent.getVisibility().isVisible(receiver, parent, from)) {
216 return parent;
217 }
218 parent = DescriptorUtils.getParentOfType(parent, DeclarationDescriptorWithVisibility.class);
219 }
220 return null;
221 }
222
223 private static final Map<Visibility, Integer> ORDERED_VISIBILITIES;
224
225 static {
226 Map<Visibility, Integer> visibilities = UtilsPackage.newHashMapWithExpectedSize(4);
227 visibilities.put(PRIVATE_TO_THIS, 0);
228 visibilities.put(PRIVATE, 0);
229 visibilities.put(INTERNAL, 1);
230 visibilities.put(PROTECTED, 1);
231 visibilities.put(PUBLIC, 2);
232 ORDERED_VISIBILITIES = Collections.unmodifiableMap(visibilities);
233 }
234
235 /*package*/
236 @Nullable
237 static Integer compareLocal(@NotNull Visibility first, @NotNull Visibility second) {
238 if (first == second) return 0;
239 Integer firstIndex = ORDERED_VISIBILITIES.get(first);
240 Integer secondIndex = ORDERED_VISIBILITIES.get(second);
241 if (firstIndex == null || secondIndex == null || firstIndex.equals(secondIndex)) {
242 return null;
243 }
244 return firstIndex - secondIndex;
245 }
246
247 @Nullable
248 public static Integer compare(@NotNull Visibility first, @NotNull Visibility second) {
249 Integer result = first.compareTo(second);
250 if (result != null) {
251 return result;
252 }
253 Integer oppositeResult = second.compareTo(first);
254 if (oppositeResult != null) {
255 return -oppositeResult;
256 }
257 return null;
258 }
259
260 public static boolean isPrivate(@NotNull Visibility visibility) {
261 return visibility == PRIVATE || visibility == PRIVATE_TO_THIS;
262 }
263 }