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