KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > aspectj > compiler > base > InnerAccessFixer


1 /* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * This file is part of the compiler and core tools for the AspectJ(tm)
4  * programming language; see http://aspectj.org
5  *
6  * The contents of this file are subject to the Mozilla Public License
7  * Version 1.1 (the "License"); you may not use this file except in
8  * compliance with the License. You may obtain a copy of the License at
9  * either http://www.mozilla.org/MPL/ or http://aspectj.org/MPL/.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is AspectJ.
17  *
18  * The Initial Developer of the Original Code is Xerox Corporation. Portions
19  * created by Xerox Corporation are Copyright (C) 1999-2002 Xerox Corporation.
20  * All Rights Reserved.
21  *
22  * Contributor(s):
23  */

24
25 package org.aspectj.compiler.base;
26
27 import org.aspectj.compiler.base.ast.*;
28
29 import java.util.*;
30
31 /** Provides backdoor methods for access to methods and fields that
32     otherwise would not be accessible.
33
34     <p> This follows the javac model rather than the jikes model.
35     This model generates more methods, but will result in fewer method
36     calls. In particular, the code <code>foo1.x += 5</code> will be
37     translated into
38     </p>
39
40 <pre>
41 Foo.incX(foo1, 5)
42 static int Foo.incX(Foo obj, int val) {
43     return obj.x += 5;
44 }
45 </pre>
46
47     <p> rather than </p>
48
49 <pre>
50 Foo.setX(Foo.getX() + 5)
51 static int Foo.setX(Foo obj, int val) {
52     return obj.x = val;
53 }
54 static int Foo.getX(Foo obj) {
55     return obj.x;
56 }
57 </pre>
58
59     <p> which means we might have, for every private variable, one
60     method for each kind of assignment expression, prefix expression,
61     and postfix expression, in addition to one for plain reference.
62     The jikes/ajc model would just have two. Ah well. </p>
63
64     <p> This creates the access methods on the <em>qualifying</em>
65     type of the field access or method expression, not the type that
66     necessarily declares the field. So, the expression
67     <code>foo1.m()</code>, when referring to the protected method m
68     defined in a superclass of foo from outside the package, will
69     result in:</p>
70
71 <pre>
72 package p1:
73   public class Goo { protected void m() {} }
74 package p2:
75   class Foo extends Goo {
76       class Inner {
77           ... Foo.this.m() ...
78       }
79   }
80 --&gt;
81 package p2:
82   class Foo extends Goo {
83       static void access$m(Foo f) {
84           f.m(); return;
85       }
86       class Inner {
87          ... Foo.access$m(Foo.this) ...
88       }
89   }
90 </pre>
91
92     <p> the access method going into Foo, the qualifying type of the
93     method call, not Goo, the defining type of the protected method.</p>
94
95     <p> This pass was written to deal with inner access (access to
96     private and protected members), so it will always generate
97     package-protected access methods (see {@link #makeAccessMethod})
98     when access is needed (see {@link #isAccessible}). It could be
99     used (with some adaptation) as a cleanup from the crosscutting,
100     and in such a case would generate some public access methods. </p>
101
102     <p> Currently it handles private constructors by simply making
103     them package-protected. This will not work in general for
104     crosscutting, but works just fine for inners. We may want to
105     change this to add "cookied" access constructors when needed. </p>
106
107 */

108
109 public class InnerAccessFixer extends WalkerPass {
110
111     public InnerAccessFixer(JavaCompiler compiler) {
112         super(compiler);
113     }
114
115     public String JavaDoc getDisplayName() {
116         return "adding inner access backdoors";
117     }
118
119     public ASTObject process(ASTObject object) {
120         object.walk(this);
121         return object.postInnerAccess(this);
122     }
123
124     private Map/*<Triple, MethodDec>*/ accessMethods = new HashMap();
125
126     public MethodDec getAccessMethod(Type qType, Dec dec, String JavaDoc op, Expr src) {
127         Triple key = new Triple(qType, dec, op);
128         MethodDec methodDec = (MethodDec) accessMethods.get(key);
129         if (methodDec == null) {
130             methodDec = src.buildAccessMethod(this);
131             ((NameType)qType).getTypeDec().addToBody(methodDec);
132             accessMethods.put(key, methodDec);
133         }
134         return methodDec;
135     }
136
137     private int accessCounter = 0;
138     public MethodDec makeAccessMethod(Type returnType, Formals formals, Expr bodyExpr) {
139         final AST ast = getAST();
140         return
141             ast.makeMethod(ast.makeModifiers(Modifiers.STATIC),
142                            returnType,
143                            "access$" + accessCounter++,
144                            formals,
145                            returnType.isVoid()
146                            ? ast.makeCodeBody(ast.makeStmt(bodyExpr), ast.makeReturn())
147                            : ast.makeCodeBody(ast.makeReturn(bodyExpr)));
148     }
149
150     /** make a primary expression that is usable in calling the access
151         method. For static resources, this is the primary expression
152         originally used to get access to the resource. For non-static
153         resources, this is a TypeExpr of the type of the primary
154         expression, and in such cases we add the primary expression as
155         the first argument to the call to the access method.
156
157         @param isStatic is the resource static?
158         @param args the arguments to the call we are about to make,
159         which me may have to add to
160         @param e the original primary expression
161         
162         @return e or a TypeExpr
163
164     */

165     public Expr makeOutsidePrimary(boolean isStatic, Exprs args, Expr e) {
166         if (e.getType() instanceof PrimitiveType) throw new RuntimeException JavaDoc();
167         if (isStatic) {
168             return e;
169         } else {
170             args.add(0, e);
171             return getAST().makeTypeExpr(e.getType());
172         }
173     }
174
175     /** make a primary expression that is usable inside the access
176         method to get at the accessed resource (field or method). For
177         static resources, this is a typeExpr, but for non-static
178         resources, we add a new formal and return a reference to that
179         formal.
180
181         @param isStatic is the resource static?
182         @param f the formals of the access method, which we may add to
183         @param ty the type of the object with access to the resource
184
185         @return a TypeExpr or a VarExpr
186     */

187     public Expr makeInsidePrimary(boolean isStatic, Formals f, Type ty) {
188         final AST ast = getAST();
189         if (isStatic) {
190             return ast.makeTypeExpr(ty);
191         } else {
192             FormalDec obj = ast.makeFormal(ty, "obj$");
193             f.add(0, obj);
194             return ast.makeVar(obj);
195         }
196     }
197             
198     /** Is the dec accessible from the qualifying expression? Note
199         that this assumes that if q.getType() does not enclose
200         q.getDeclaringType() (i.e., if we're dealing with a
201         non-inner-type issue) that the dec <em>is</em> accessible. */

202     public boolean isAccessible(Dec dec, Expr q) {
203         if (dec.isPrivate()) {
204             return q.getBytecodeTypeDec() == dec.getBytecodeTypeDec();
205         } else if (dec.isProtected()) {
206             TypeDec target = dec.getBytecodeTypeDec();
207             TypeDec src = q.getBytecodeTypeDec();
208             if (src.getType().isSubtypeOf(target.getType())) return true;
209             String JavaDoc pkg1 = src.getPackageName();
210             String JavaDoc pkg2 = target.getPackageName();
211             return (pkg1 == null) ? (pkg2 == null) : pkg1.equals(pkg2);
212         } else {
213             return true;
214         }
215     }
216
217     // ------------------------------
218

219     /** A type used to create keys for the access method map */
220     static class Triple {
221         Object JavaDoc one, two, three;
222         Triple(Object JavaDoc one, Object JavaDoc two, Object JavaDoc three) {
223             this.one = one; this.two = two; this.three = three;
224         }
225         public int hashCode() {
226             return one.hashCode() + two.hashCode() * 2 + three.hashCode() * 3;
227         }
228         public boolean equals(Object JavaDoc other) {
229             if (other instanceof Triple) {
230                 Triple otherTriple = (Triple) other;
231                 return one.equals(otherTriple.one)
232                     && two.equals(otherTriple.two)
233                     && three.equals(otherTriple.three);
234             } else {
235                 return false;
236             }
237         }
238     }
239 }
240
Popular Tags