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 017package org.jetbrains.jet.lang.descriptors; 018 019import com.google.common.collect.Maps; 020import com.google.common.collect.Sets; 021import org.jetbrains.annotations.NotNull; 022import org.jetbrains.annotations.Nullable; 023import org.jetbrains.jet.lang.resolve.DescriptorUtils; 024 025import java.util.Map; 026import java.util.Set; 027 028public 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}