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