001    /* Copyright (c) 2005-2008, Torbjorn Ekman
002     * All rights reserved.
003     *
004     * Redistribution and use in source and binary forms, with or without
005     * modification, are permitted provided that the following conditions are met:
006     *
007     * 1. Redistributions of source code must retain the above copyright notice,
008     * this list of conditions and the following disclaimer.
009     *
010     * 2. Redistributions in binary form must reproduce the above copyright notice,
011     * this list of conditions and the following disclaimer in the documentation
012     * and/or other materials provided with the distribution.
013     *
014     * 3. Neither the name of the copyright holder nor the names of its
015     * contributors may be used to endorse or promote products derived from this
016     * software without specific prior written permission.
017     *
018     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
022     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028     * POSSIBILITY OF SUCH DAMAGE.
029     */
030    
031    aspect AccessControl {
032      // 6.6 Access Control
033    
034      syn lazy boolean ArrayDecl.accessibleFrom(TypeDecl type) = elementType().accessibleFrom(type);
035    
036      syn lazy boolean TypeDecl.accessibleFromPackage(String packageName) =
037          !isPrivate() && (isPublic() || hostPackage().equals(packageName));
038    
039      eq UnknownType.accessibleFromPackage(String packageName) = false;
040    
041      syn lazy boolean TypeDecl.accessibleFromExtend(TypeDecl type) {
042        if (type == this) {
043          return true;
044        }
045        if (isInnerType()) {
046          if (!enclosingType().accessibleFrom(type)) {
047            return false;
048          }
049        }
050        if (isPublic()) {
051          return true;
052        } else if (isProtected()) {
053          // isProtected implies a nested type
054          if (hostPackage().equals(type.hostPackage())) {
055            return true;
056          }
057          if (type.isNestedType() && type.enclosingType().withinBodyThatSubclasses(enclosingType()) != null) {
058            return true;
059          }
060          return false;
061        } else if (isPrivate()) {
062          return topLevelType() == type.topLevelType();
063        } else {
064          return hostPackage().equals(type.hostPackage());
065        }
066      }
067    
068      syn lazy boolean TypeDecl.accessibleFrom(TypeDecl type) {
069        if (type == this) {
070          return true;
071        }
072        if (isInnerType()) {
073          if (!enclosingType().accessibleFrom(type)) {
074            return false;
075          }
076        }
077        if (isPublic()) {
078          return true;
079        } else if (isProtected()) {
080          if (hostPackage().equals(type.hostPackage())) {
081            return true;
082          }
083          if (isMemberType()) {
084            TypeDecl typeDecl = type;
085            while (typeDecl != null && !typeDecl.instanceOf(enclosingType())) {
086              typeDecl = typeDecl.enclosingType();
087            }
088            if (typeDecl != null) {
089              return true;
090            }
091          }
092          return false;
093        } else if (isPrivate()) {
094          return topLevelType() == type.topLevelType();
095        } else {
096          return hostPackage().equals(type.hostPackage());
097        }
098      }
099    
100      syn lazy boolean MethodDecl.accessibleFrom(TypeDecl type) {
101        if (isPublic()) {
102          return true;
103        } else if (isProtected()) {
104          if (hostPackage().equals(type.hostPackage())) {
105            return true;
106          }
107          if (type.withinBodyThatSubclasses(hostType()) != null) {
108            return true;
109          }
110          return false;
111        } else if (isPrivate()) {
112          return hostType().topLevelType() == type.topLevelType();
113        } else {
114          return hostPackage().equals(type.hostPackage());
115        }
116      }
117    
118      syn lazy boolean ConstructorDecl.accessibleFrom(TypeDecl type) {
119        if (!hostType().accessibleFrom(type)) {
120          return false;
121        } else if (isPublic()) {
122          return true;
123        } else if (isProtected()) {
124          return true;
125        } else if (isPrivate()) {
126          return hostType().topLevelType() == type.topLevelType();
127        } else {
128          return hostPackage().equals(type.hostPackage());
129        }
130      }
131    
132      syn lazy boolean FieldDeclaration.accessibleFrom(TypeDecl type) {
133        if (isPublic()) {
134          return true;
135        } else if (isProtected()) {
136          if (hostPackage().equals(type.hostPackage())) {
137            return true;
138          }
139          if (type.withinBodyThatSubclasses(hostType()) != null) {
140            return true;
141          }
142          return false;
143        } else if (isPrivate()) {
144          return hostType().topLevelType() == type.topLevelType();
145        } else {
146          return hostPackage().equals(type.hostPackage());
147        }
148      }
149    
150      public void ASTNode.accessControl() {
151      }
152    
153      public void TypeAccess.accessControl() {
154        super.accessControl();
155        TypeDecl hostType = hostType();
156        if (hostType != null && !hostType.isUnknown() && !type().accessibleFrom(hostType)) {
157          errorf("%s in %s can not access type %s",
158              this.prettyPrint(), hostType().fullName(), type().fullName());
159        } else if ((hostType == null || hostType.isUnknown())
160            && !type().accessibleFromPackage(hostPackage())) {
161          errorf("%s can not access type %s", this.prettyPrint(), type().fullName());
162        }
163      }
164    
165      public void ClassInstanceExpr.accessControl() {
166        super.accessControl();
167        if (type().isAbstract()) {
168          errorf("Can not instantiate abstract class %s", type().fullName());
169        }
170        if (!decl().accessibleFrom(hostType())) {
171          errorf("constructor %s is not accessible", decl().signature());
172        }
173      }
174    
175      public void ClassDecl.accessControl() {
176        super.accessControl();
177    
178        // 8.1.1.2 final Classes
179        TypeDecl typeDecl = superclass();
180        if (!typeDecl.isUnknown() && !typeDecl.accessibleFromExtend(this)) {
181          errorf("class %s may not extend non accessible type %s", fullName(), typeDecl.fullName());
182        }
183    
184        if (hasSuperclass() && !superclass().accessibleFrom(this)) {
185          errorf("a superclass must be accessible which %s is not", superclass().name());
186        }
187    
188        // 8.1.4
189        for (int i = 0; i < getNumImplements(); i++) {
190          TypeDecl decl = getImplements(i).type();
191          if (!decl.isCircular() && !decl.accessibleFrom(this)) {
192            errorf("class %s can not implement non accessible type %s", fullName(), decl.fullName());
193          }
194        }
195      }
196    
197      public void InterfaceDecl.accessControl() {
198        super.accessControl();
199    
200        if (!isCircular()) {
201          // 9.1.2
202          HashSet set = new HashSet();
203          for (int i = 0; i < getNumSuperInterface(); i++) {
204            TypeDecl decl = getSuperInterface(i).type();
205    
206            if (!decl.isInterfaceDecl() && !decl.isUnknown()) {
207              errorf("interface %s can not extend non interface type %s", fullName(), decl.fullName());
208            }
209            if (!decl.isCircular() && !decl.accessibleFrom(this)) {
210              errorf("interface %s can not extend non accessible type %s", fullName(), decl.fullName());
211            }
212            if (set.contains(decl)) {
213              errorf("extended interface %s is mentionened multiple times in extends clause",
214                  decl.fullName());
215            }
216            set.add(decl);
217          }
218        }
219      }
220    }