001 /*
002 * Copyright 2010-2013 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.jet.lang.descriptors;
018
019 import kotlin.KotlinPackage;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
023 import org.jetbrains.jet.utils.UtilsPackage;
024
025 import java.util.Collections;
026 import java.util.Map;
027 import java.util.Set;
028
029 public class Visibilities {
030 public static final Visibility PRIVATE = new Visibility("private", false) {
031 @Override
032 protected boolean isVisible(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
033 DeclarationDescriptor parent = what;
034 while (parent != null) {
035 parent = parent.getContainingDeclaration();
036 if ((parent instanceof ClassDescriptor && !DescriptorUtils.isClassObject(parent)) ||
037 parent instanceof PackageFragmentDescriptor) {
038 break;
039 }
040 }
041 if (parent == null) {
042 return false;
043 }
044 DeclarationDescriptor fromParent = from;
045 while (fromParent != null) {
046 if (parent == fromParent) {
047 return true;
048 }
049 if (fromParent instanceof PackageFragmentDescriptor) {
050 return parent instanceof PackageFragmentDescriptor
051 && ((PackageFragmentDescriptor) parent).getFqName().isAncestorOf(((PackageFragmentDescriptor) fromParent).getFqName())
052 && DescriptorUtils.areInSameModule(fromParent, parent);
053 }
054 fromParent = fromParent.getContainingDeclaration();
055 }
056 return false;
057 }
058 };
059
060 public static final Visibility PROTECTED = new Visibility("protected", true) {
061 @Override
062 protected boolean isVisible(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
063 ClassDescriptor classDescriptor = DescriptorUtils.getParentOfType(what, ClassDescriptor.class);
064 if (classDescriptor == null) return false;
065
066 ClassDescriptor fromClass = DescriptorUtils.getParentOfType(from, ClassDescriptor.class, false);
067 if (fromClass == null) return false;
068 if (DescriptorUtils.isSubclass(fromClass, classDescriptor)) {
069 return true;
070 }
071 return isVisible(what, fromClass.getContainingDeclaration());
072 }
073 };
074
075 public static final Visibility INTERNAL = new Visibility("internal", false) {
076 @Override
077 protected boolean isVisible(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
078 //NOTE: supposedly temporarily
079 return PUBLIC.isVisible(what, from);
080 }
081 };
082
083 public static final Visibility PUBLIC = new Visibility("public", true) {
084 @Override
085 protected boolean isVisible(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
086 return true;
087 }
088 };
089
090 public static final Visibility LOCAL = new Visibility("local", false) {
091 @Override
092 protected boolean isVisible(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
093 throw new IllegalStateException(); //This method shouldn't be invoked for LOCAL visibility
094 }
095 };
096
097 public static final Visibility INHERITED = new Visibility("inherited", false) {
098 @Override
099 protected boolean isVisible(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
100 throw new IllegalStateException("Visibility is unknown yet"); //This method shouldn't be invoked for INHERITED visibility
101 }
102 };
103
104 /* Visibility for fake override invisible members (they are created for better error reporting) */
105 public static final Visibility INVISIBLE_FAKE = new Visibility("invisible_fake", false) {
106 @Override
107 protected boolean isVisible(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
108 return false;
109 }
110 };
111
112 public static final Set<Visibility> INVISIBLE_FROM_OTHER_MODULES =
113 Collections.unmodifiableSet(KotlinPackage.setOf(PRIVATE, INTERNAL, LOCAL));
114
115 private Visibilities() {
116 }
117
118 public static boolean isVisible(@NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
119 return findInvisibleMember(what, from) == null;
120 }
121
122 @SuppressWarnings("UnusedDeclaration")
123 private static boolean isInFriendModule(@NotNull DeclarationDescriptor what, @NotNull DeclarationDescriptor from) {
124 return DescriptorUtils.getContainingModule(what).isFriend(DescriptorUtils.getContainingModule(from));
125 }
126
127 @Nullable
128 public static DeclarationDescriptorWithVisibility findInvisibleMember(
129 @NotNull DeclarationDescriptorWithVisibility what,
130 @NotNull DeclarationDescriptor from
131 ) {
132 DeclarationDescriptorWithVisibility parent = what;
133 while (parent != null && parent.getVisibility() != LOCAL) {
134 if (!parent.getVisibility().isVisible(parent, from)) {
135 return parent;
136 }
137 parent = DescriptorUtils.getParentOfType(parent, DeclarationDescriptorWithVisibility.class);
138 }
139 return null;
140 }
141
142 private static final Map<Visibility, Integer> ORDERED_VISIBILITIES;
143
144 static {
145 Map<Visibility, Integer> visibilities = UtilsPackage.newHashMapWithExpectedSize(4);
146 visibilities.put(PRIVATE, 0);
147 visibilities.put(INTERNAL, 1);
148 visibilities.put(PROTECTED, 1);
149 visibilities.put(PUBLIC, 2);
150 ORDERED_VISIBILITIES = Collections.unmodifiableMap(visibilities);
151 }
152
153 /*package*/
154 @Nullable
155 static Integer compareLocal(@NotNull Visibility first, @NotNull Visibility second) {
156 if (first == second) return 0;
157 Integer firstIndex = ORDERED_VISIBILITIES.get(first);
158 Integer secondIndex = ORDERED_VISIBILITIES.get(second);
159 if (firstIndex == null || secondIndex == null || firstIndex.equals(secondIndex)) {
160 return null;
161 }
162 return firstIndex - secondIndex;
163 }
164
165 @Nullable
166 public static Integer compare(@NotNull Visibility first, @NotNull Visibility second) {
167 Integer result = first.compareTo(second);
168 if (result != null) {
169 return result;
170 }
171 Integer oppositeResult = second.compareTo(first);
172 if (oppositeResult != null) {
173 return -oppositeResult;
174 }
175 return null;
176 }
177 }