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.resolve.java;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.jet.lang.descriptors.*;
021    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
022    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
023    
024    public class JavaVisibilities {
025        private JavaVisibilities() {
026        }
027    
028        public static final Visibility PACKAGE_VISIBILITY = new Visibility("package", false) {
029            @Override
030            protected boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
031                return areInSamePackage(what, from);
032            }
033    
034            @Override
035            protected Integer compareTo(@NotNull Visibility visibility) {
036                if (this == visibility) return 0;
037                if (Visibilities.isPrivate(visibility)) return 1;
038                return -1;
039            }
040    
041            @Override
042            public String toString() {
043                return "public/*package*/";
044            }
045    
046            @NotNull
047            @Override
048            public Visibility normalize() {
049                return Visibilities.INTERNAL;
050            }
051        };
052    
053        public static final Visibility PROTECTED_STATIC_VISIBILITY = new Visibility("protected_static", false) {
054            @Override
055            protected boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
056                if (areInSamePackage(what, from)) {
057                    return true;
058                }
059    
060                ClassDescriptor fromClass = DescriptorUtils.getParentOfType(from, ClassDescriptor.class, false);
061                if (fromClass == null) return false;
062    
063                DeclarationDescriptor containingDeclaration = what.getContainingDeclaration();
064                assert containingDeclaration instanceof ClassDescriptor : "Only class members can have protected_static visibility";
065                ClassDescriptor whatClass = (ClassDescriptor) containingDeclaration;
066    
067                if (DescriptorUtils.isSubclass(fromClass, whatClass)) {
068                    return true;
069                }
070                return isVisible(receiver, what, fromClass.getContainingDeclaration());
071            }
072    
073            @Override
074            public String toString() {
075                return "protected/*protected static*/";
076            }
077    
078            @NotNull
079            @Override
080            public Visibility normalize() {
081                return Visibilities.PROTECTED;
082            }
083        };
084    
085        public static final Visibility PROTECTED_AND_PACKAGE = new Visibility("protected_and_package", false) {
086            @Override
087            protected boolean isVisible(@NotNull ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
088                if (areInSamePackage(what, from)) {
089                    return true;
090                }
091    
092                ClassDescriptor whatClass = DescriptorUtils.getParentOfType(what, ClassDescriptor.class, false);
093                if (whatClass == null) return false;
094    
095                ClassDescriptor fromClass = DescriptorUtils.getParentOfType(from, ClassDescriptor.class, false);
096                if (fromClass == null) return false;
097    
098                if (DescriptorUtils.isSubclass(fromClass, whatClass)) {
099                    return true;
100                }
101                return isVisible(receiver, what, fromClass.getContainingDeclaration());
102            }
103    
104            @Override
105            protected Integer compareTo(@NotNull Visibility visibility) {
106                if (this == visibility) return 0;
107                if (visibility == Visibilities.INTERNAL) return null;
108                if (Visibilities.isPrivate(visibility)) return 1;
109                return -1;
110            }
111    
112            @Override
113            public String toString() {
114                return "protected/*protected and package*/";
115            }
116    
117            @NotNull
118            @Override
119            public Visibility normalize() {
120                return Visibilities.PROTECTED;
121            }
122        };
123    
124        private static boolean areInSamePackage(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) {
125            PackageFragmentDescriptor whatPackage = DescriptorUtils.getParentOfType(first, PackageFragmentDescriptor.class, false);
126            PackageFragmentDescriptor fromPackage = DescriptorUtils.getParentOfType(second, PackageFragmentDescriptor.class, false);
127            return fromPackage != null && whatPackage != null && whatPackage.getFqName().equals(fromPackage.getFqName());
128        }
129    }