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