]> source.dussan.org Git - aspectj.git/commitdiff
PerTypeWithin support.
authoraclement <aclement>
Tue, 18 Jan 2005 11:39:16 +0000 (11:39 +0000)
committeraclement <aclement>
Tue, 18 Jan 2005 11:39:16 +0000 (11:39 +0000)
16 files changed:
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AspectDeclaration.java
tests/src/org/aspectj/systemtest/ajc150/AllTestsAspectJ150.java
tests/src/org/aspectj/systemtest/ajc150/PerTypeWithinTests.java [new file with mode: 0644]
weaver/src/org/aspectj/weaver/Advice.java
weaver/src/org/aspectj/weaver/AdviceKind.java
weaver/src/org/aspectj/weaver/AjcMemberMaker.java
weaver/src/org/aspectj/weaver/NameMangler.java
weaver/src/org/aspectj/weaver/PerTypeWithinTargetTypeMunger.java [new file with mode: 0644]
weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java
weaver/src/org/aspectj/weaver/TypeX.java
weaver/src/org/aspectj/weaver/bcel/BcelAdvice.java
weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java
weaver/src/org/aspectj/weaver/patterns/PatternParser.java
weaver/src/org/aspectj/weaver/patterns/PerClause.java
weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java [new file with mode: 0644]

index cfb0381ce98513878babdc9f3045fc5619f3705b..a2f8fb22b439d2f1f484ac4122f10cbcb61935d8 100644 (file)
@@ -27,6 +27,7 @@ import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
 //import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.CodeStream;
+import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel;
 import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.Label;
 import org.aspectj.org.eclipse.jdt.internal.compiler.env.IGenericType;
 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.*;
@@ -194,6 +195,9 @@ public class AspectDeclaration extends TypeDeclaration {
 //                                     world.makeFieldBinding(
 //                                             AjcMemberMaker.perCflowField(
 //                                                     typeX)));
+                       } else if (perClause.getKind() == PerClause.PERTYPEWITHIN) {
+                               //PTWIMPL Add field for storing typename in aspect for which the aspect instance exists
+                               binding.addField(factory.makeFieldBinding(AjcMemberMaker.perTypeWithinWithinTypeField(typeX,typeX)));
                        } else {
                                throw new RuntimeException("unimplemented");
                        }
@@ -272,6 +276,14 @@ public class AspectDeclaration extends TypeDeclaration {
                        generatePerObjectAspectOfMethod(classFile, interfaceType);
                        generatePerObjectHasAspectMethod(classFile, interfaceType);
                        generatePerObjectBindMethod(classFile, interfaceType);
+               } else if (perClause.getKind() == PerClause.PERTYPEWITHIN) { 
+                   //PTWIMPL Generate the methods required *in the aspect*
+                       generatePerTypeWithinAspectOfMethod(classFile);    //  public static <aspecttype> aspectOf(java.lang.Class)
+                       generatePerTypeWithinGetInstanceMethod(classFile); // private static <aspecttype> ajc$getInstance(Class c) throws Exception
+                       generatePerTypeWithinHasAspectMethod(classFile);
+                       generatePerTypeWithinCreateAspectInstanceMethod(classFile); // generate public static X ajc$createAspectInstance(Class forClass) {
+                       // PTWIMPL getWithinType() would need this...
+                       // generatePerTypeWithinGetWithinTypeMethod(classFile); // generate public Class getWithinType() {
                } else {
                        throw new RuntimeException("unimplemented");
                }
@@ -450,6 +462,46 @@ public class AspectDeclaration extends TypeDeclaration {
        }
        
        
+       // PTWIMPL Generate aspectOf() method
+       private void generatePerTypeWithinAspectOfMethod(ClassFile classFile) {
+                       final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
+                       generateMethod(classFile, aspectOfMethod, new BodyGenerator() {
+                               public void generate(CodeStream codeStream) {
+                                       
+                                       Label instanceFound = new Label(codeStream);
+
+                                       ExceptionLabel anythingGoesWrong = new ExceptionLabel(codeStream,world.makeTypeBinding(TypeX.JAVA_LANG_EXCEPTION));
+                                       codeStream.aload_0();  
+                                       codeStream.invokestatic(world.makeMethodBindingForCall(AjcMemberMaker.perTypeWithinGetInstance(typeX)));
+                                       codeStream.astore_1();
+                                       codeStream.aload_1();
+                                       codeStream.ifnonnull(instanceFound);
+                                       codeStream.new_(world.makeTypeBinding(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION));
+                                       codeStream.dup();
+                                       
+                                       codeStream.ldc(typeX.getName());
+                                       codeStream.aconst_null();
+                                       
+                                       codeStream.invokespecial(world.makeMethodBindingForCall(AjcMemberMaker.noAspectBoundExceptionInit2()));
+                                       codeStream.athrow();
+                                       instanceFound.place();
+                                   codeStream.aload_1();
+                                       
+                                       codeStream.areturn();
+                                       anythingGoesWrong.placeEnd();
+                                       anythingGoesWrong.place();
+                                       
+                                       codeStream.astore_1();
+                                       codeStream.new_(world.makeTypeBinding(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION));
+                                       
+                                       codeStream.dup();
+                                       
+                                       // Run the simple ctor for NABE
+                                       codeStream.invokespecial(world.makeMethodBindingForCall(AjcMemberMaker.noAspectBoundExceptionInit()));
+                                       codeStream.athrow();
+                               }});
+               }
+       
        private void generatePerObjectAspectOfMethod(
                ClassFile classFile,
                final TypeBinding interfaceType) 
@@ -513,6 +565,32 @@ public class AspectDeclaration extends TypeDeclaration {
                        }});
        }
        
+       // PTWIMPL Generate hasAspect() method
+       private void generatePerTypeWithinHasAspectMethod(ClassFile classFile) {
+                       final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
+                       generateMethod(classFile, hasAspectMethod, new BodyGenerator() {
+                               public void generate(CodeStream codeStream) {
+                                          ExceptionLabel goneBang = new ExceptionLabel(codeStream,world.makeTypeBinding(TypeX.JAVA_LANG_EXCEPTION));
+                                          Label noInstanceExists = new Label(codeStream);
+                                          Label leave = new Label(codeStream);
+                                          goneBang.placeStart();
+                                          codeStream.aload_0();
+                                          codeStream.invokestatic(world.makeMethodBinding(AjcMemberMaker.perTypeWithinGetInstance(typeX)));
+                                          codeStream.ifnull(noInstanceExists);
+                                          codeStream.iconst_1();
+                                          codeStream.goto_(leave);
+                                          noInstanceExists.place();
+                                          codeStream.iconst_0();
+                                          leave.place();
+                                          goneBang.placeEnd();
+                                          codeStream.ireturn();
+                                          goneBang.place();
+                                          codeStream.astore_1();
+                                          codeStream.iconst_0();
+                                          codeStream.ireturn();
+                               }});
+               }
+       
        private void generatePerObjectBindMethod(
                ClassFile classFile,
                final TypeBinding interfaceType) 
@@ -550,6 +628,70 @@ public class AspectDeclaration extends TypeDeclaration {
                        }});
        }
        
+       // PTWIMPL Generate getInstance method 
+       private void generatePerTypeWithinGetInstanceMethod(ClassFile classFile) {
+                       final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
+                       generateMethod(classFile, AjcMemberMaker.perTypeWithinGetInstance(EclipseFactory.fromBinding(binding)), 
+                       new BodyGenerator() {
+                               public void generate(CodeStream codeStream) {
+                                       ExceptionLabel exc = new ExceptionLabel(codeStream,world.makeTypeBinding(TypeX.JAVA_LANG_EXCEPTION));
+                                       exc.placeStart();
+                                       codeStream.aload_0();
+                                       codeStream.ldc(NameMangler.perTypeWithinLocalAspectOf(typeX));
+                                       codeStream.aconst_null();
+                                       codeStream.invokevirtual(
+                                                       new MethodBinding(
+                                                                       0, 
+                                                                       "getDeclaredMethod".toCharArray(), 
+                                                                       world.makeTypeBinding(TypeX.forSignature("Ljava/lang/reflect/Method;")), // return type
+                                                                        new TypeBinding[]{world.makeTypeBinding(TypeX.forSignature("Ljava/lang/String;")),
+                                                                                                  world.makeTypeBinding(TypeX.forSignature("[Ljava/lang/Class;"))},
+                                                                       new ReferenceBinding[0],
+                                                                       (ReferenceBinding)world.makeTypeBinding(TypeX.JAVA_LANG_CLASS)));
+                                       codeStream.astore_1();
+                                       codeStream.aload_1();
+                                       codeStream.aconst_null();
+                                       codeStream.aconst_null();
+                                       codeStream.invokevirtual(
+                                                       new MethodBinding(
+                                                                       0,
+                                                                       "invoke".toCharArray(),
+                                                                       world.makeTypeBinding(TypeX.OBJECT),
+                                                                       new TypeBinding[]{world.makeTypeBinding(TypeX.OBJECT),world.makeTypeBinding(TypeX.forSignature("[Ljava/lang/Object;"))},
+                                                                       new ReferenceBinding[0],
+                                                                       (ReferenceBinding)world.makeTypeBinding(TypeX.JAVA_LANG_REFLECT_METHOD)));
+                                       codeStream.checkcast(world.makeTypeBinding(typeX));
+                                       codeStream.astore_2();
+                                       codeStream.aload_2();
+                                       exc.placeEnd();
+                                       codeStream.areturn();
+                                       exc.place();
+                                       codeStream.astore_1();
+                                       codeStream.aload_1();
+                                       codeStream.athrow();                                    
+                               }});
+               }
+       
+       private void generatePerTypeWithinCreateAspectInstanceMethod(ClassFile classFile) {
+               final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
+               generateMethod(classFile, AjcMemberMaker.perTypeWithinCreateAspectInstance(EclipseFactory.fromBinding(binding)), 
+               new BodyGenerator() {
+                       public void generate(CodeStream codeStream) {
+                               
+                               codeStream.new_(world.makeTypeBinding(typeX));
+                               codeStream.dup();
+                               codeStream.invokespecial(new MethodBinding(0, "<init>".toCharArray(), 
+                                               BaseTypes.VoidBinding, new TypeBinding[0],
+                                               new ReferenceBinding[0], binding));
+                               codeStream.astore_1();
+                               codeStream.aload_1();
+                               codeStream.aload_0();
+                               codeStream.putfield(world.makeFieldBinding(AjcMemberMaker.perTypeWithinWithinTypeField(typeX,typeX)));
+                               codeStream.aload_1();
+                               codeStream.areturn();
+                       }});
+       }
+       
 
                
        private void generatePerSingletonAspectOfMethod(ClassFile classFile) {
@@ -785,6 +927,10 @@ public class AspectDeclaration extends TypeDeclaration {
                        } else if (perClause.getKind() == PerClause.PEROBJECT) {
                                aspectOfMethod = AjcMemberMaker.perObjectAspectOfMethod(typeX);
                                hasAspectMethod = AjcMemberMaker.perObjectHasAspectMethod(typeX);
+                       } else if (perClause.getKind() == PerClause.PERTYPEWITHIN) {
+                           // PTWIMPL Use these variants of aspectOf()/hasAspect()
+                               aspectOfMethod  = AjcMemberMaker.perTypeWithinAspectOfMethod(typeX);
+                               hasAspectMethod = AjcMemberMaker.perTypeWithinHasAspectMethod(typeX);
                        } else {
                                throw new RuntimeException("bad per clause: " + perClause);     
                        }
index d138eb64bad5f58c5504ea8e6c3bb4e6d711745a..fa0cff9c55059f634f2dcc7b9d50502c1be6d851 100644 (file)
@@ -13,12 +13,6 @@ package org.aspectj.systemtest.ajc150;
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
-/**
- * @author colyer
- *
- * TODO To change the template for this generated type comment go to
- * Window - Preferences - Java - Code Style - Code Templates
- */
 public class AllTestsAspectJ150 {
 
        public static Test suite() {
@@ -36,6 +30,7 @@ public class AllTestsAspectJ150 {
                suite.addTestSuite(AnnotationPointcutsTests.class);
                suite.addTestSuite(VarargsTests.class);
                suite.addTestSuite(AnnotationRuntimeTests.class);
+               suite.addTestSuite(PerTypeWithinTests.class);
                
                
                //$JUnit-END$
diff --git a/tests/src/org/aspectj/systemtest/ajc150/PerTypeWithinTests.java b/tests/src/org/aspectj/systemtest/ajc150/PerTypeWithinTests.java
new file mode 100644 (file)
index 0000000..6c61fca
--- /dev/null
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM 
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ *    Andy Clement - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.systemtest.ajc150;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.List;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.tools.ajc.CompilationResult;
+
+
+
+public class PerTypeWithinTests extends TestUtils {
+
+  protected void setUp() throws Exception {
+       super.setUp();
+       baseDir = new File("../tests/java5/pertypewithin");
+  }
+  
+  /**
+   * First few tests:
+   * 
+   * Five types p.A, p.B, p.C, q.D, q.E and an aspect a.X.
+   * 
+   * The aspect is pertypewithin(p..*) - this should match A,B,C but not D,E.
+   * 
+   * Aspect instances should be accessible for A,B,C but not D,E.
+   * The aspect instances for A,B,C should be different.
+   * 
+   * hasAspect(), aspectOf() should work.
+   * 
+   * We test these assumptions in A,B,C,D,E. 
+   */
+  public void testDoesItWorkAtAll() {
+       CompilationResult cR=ajc(baseDir,new String[]{"A.java","B.java","C.java","D.java","Main.java","X.java"});
+       assertTrue("Expected no errors:"+cR,!cR.hasErrorMessages());
+       // if (verbose) { System.err.println(cR); System.err.println(cR.getStandardError());}
+       RunResult rR = run("p.A");
+       // if (verbose) {System.err.println(rR.getStdErr());}
+       assertTrue("Expected a report from the aspect about 2 calls to sayhi():"+rR.getStdErr(),
+                          rR.getStdErr().indexOf("callcount = 2")!=-1);
+  }
+  
+  public void testCheckHasAspectWorks() {
+       CompilationResult cR=ajc(baseDir,new String[]{"A.java","B.java","C.java","D.java","Main.java","X.java"});
+       assertTrue("Expected no errors:"+cR,!cR.hasErrorMessages());
+       // if (verbose) { System.err.println(cR); System.err.println(cR.getStandardError());}
+       RunResult rR = run("p.A");
+       rR = run("p.B");
+       // if (verbose) {System.err.println(rR.getStdErr());}
+       assertTrue("Expected a report from the aspect about 3 calls to sayhi():"+rR.getStdErr(),
+                          rR.getStdErr().indexOf("callcount = 3")!=-1);
+  }
+  
+  public void testCheckAspectOfWorks() {
+       CompilationResult cR=ajc(baseDir,new String[]{"A.java","B.java","C.java","D.java","Main.java","X.java"});
+       assertTrue("Expected no errors:"+cR,!cR.hasErrorMessages());
+       // if (verbose) { System.err.println(cR); System.err.println(cR.getStandardError());}
+       RunResult rR = run("p.A");
+       rR = run("p.C");
+       // if (verbose) {System.err.println(rR.getStdErr());}
+       
+  }  
+  
+  /**
+   * Aspects Q and R match P with a pertypewithin() - they shouldn't clash in any way
+   *
+   */
+  public void testTwoAspectsHittingOneType() {
+       CompilationResult cR=ajc(baseDir,new String[]{"P.java","Q.java","R.java"});
+       assertTrue("Expected no errors:"+cR,!cR.hasErrorMessages());
+       // if (verbose) { System.err.println(cR); System.err.println(cR.getStandardError());}
+       RunResult rR = run("P");
+       // if (verbose) {System.err.println(rR.getStdErr());}   
+       assertTrue("Expected message about Q reporting 2: "+rR.getStdErr(),
+                       rR.getStdErr().indexOf("Q reporting 2")!=-1);
+       assertTrue("Expected message about R reporting 3: "+rR.getStdErr(),
+                       rR.getStdErr().indexOf("R reporting 3")!=-1);
+  }
+  
+  /**
+   * Checks the use of pertypewithin() doesn't result in extra join points (i.e. the
+   * infrastructure is properly hidden in ajc$ or synthetic members)
+   */
+  public void testPervasivenessOfWeaving() {
+       CompilationResult cR = ajc(baseDir,new String[]{"U.java","-showWeaveInfo"});
+       List l = cR.getInfoMessages();
+       int cnt = 0;
+       for (Iterator iter = l.iterator(); iter.hasNext();) {
+               IMessage element = (IMessage) iter.next();
+               if (element.getKind()==IMessage.WEAVEINFO) {
+                       //System.err.println(element);
+                       cnt++;
+               }
+       }
+       int weavingMessagesFromNormalDeploymentModel = cnt;
+       //System.err.println(cnt);
+
+    cR = ajc(baseDir,new String[]{"V.java","-showWeaveInfo"});
+       l = cR.getInfoMessages();
+       cnt = 0;
+       for (Iterator iter = l.iterator(); iter.hasNext();) {
+               IMessage element = (IMessage) iter.next();
+               if (element.getKind()==IMessage.WEAVEINFO) {
+                       //System.err.println(element);
+                       cnt++;
+               }
+       }
+       int weavingMessagesFromPerTypeWithin = cnt;
+       //System.err.println(cnt);
+       if (weavingMessagesFromNormalDeploymentModel!=weavingMessagesFromPerTypeWithin)
+               fail("Expected same number of messages regardless of perclause but got "+
+                               weavingMessagesFromNormalDeploymentModel+" and "+weavingMessagesFromPerTypeWithin);
+               
+  }
+  
+  public void testBinaryWeaving_ClassesAreBinary() {
+       // Compile the 'ordinary' class G.java into classes
+       CompilationResult cR = ajc(baseDir,new String[]{"G.java","-d","classes2"});
+       setShouldEmptySandbox(false);
+       // Compile the aspect with G.class as input, should be binary woven correctly
+       cR = ajc(baseDir,new String[]{"H.java","-inpath","classes2"});
+       RunResult rR = run("G");
+       assertTrue("Expected aspect related message 'advice running' in output from G",
+                       rR.getStdErr().indexOf("advice running")!=-1);
+       setShouldEmptySandbox(true);
+  }
+  
+  public void testBinaryWeaving_AspectsAreBinary() {
+       // Compile the aspect H.java into classes3
+       CompilationResult cR = ajc(baseDir,new String[]{"H.java","-outjar","aspects.jar"});
+       setShouldEmptySandbox(false);
+       // Compile the class with H.class as aspectpath, should be binary woven correctly
+       cR = ajc(baseDir,new String[]{"G.java","-aspectpath","aspects.jar"});
+       RunResult rR = run("G");
+       assertTrue("Expected aspect related message 'advice running' in output from G",
+                       rR.getStdErr().indexOf("advice running")!=-1);
+       setShouldEmptySandbox(true);
+  }
+  
+  // binary weaving case ...
+}
\ No newline at end of file
index 11b8f69c72b0350b40f5cc9e277a62ec1e4a50e8..a6cd8f412e4cdca4be2a0108e51ec6e0fc40aed6 100644 (file)
@@ -67,6 +67,13 @@ public abstract class Advice extends ShadowMunger {
        return ret;
     }
     
+    // PTWIMPL per type within entry advice is what initializes the aspect instance in the matched type
+    public static Advice makePerTypeWithinEntry(World world, Pointcut p, ResolvedTypeX inAspect) {
+       Advice ret = world.concreteAdvice(AdviceKind.PerTypeWithinEntry,p,null,0,p);
+       ret.concreteAspect = inAspect;
+       return ret;
+    }
+    
     public static Advice makeSoftener(World world, Pointcut entry, TypePattern exceptionType,ResolvedTypeX inAspect,IHasSourceLocation loc) {
        Advice ret = world.concreteAdvice(AdviceKind.Softener, entry, null, 0, loc);  
   
index abc560386051c1d1605e2702955f6e85edabd6f9..57851fd642524110c48b720d920c501a064f8bac 100644 (file)
@@ -53,6 +53,8 @@ public class AdviceKind extends TypeSafeEnum {
             case 12: return PerTargetEntry;
 
             case 13: return Softener;
+            
+            case 14: return PerTypeWithinEntry;
         }
         throw new RuntimeException("unimplemented kind: " + key);
     }
@@ -75,6 +77,9 @@ public class AdviceKind extends TypeSafeEnum {
     public static final AdviceKind PerTargetEntry         = new AdviceKind("perTargetEntry", 12, 1, false, false); 
 
     public static final AdviceKind Softener         = new AdviceKind("softener", 13, 1, false, false); 
+    
+    // PTWIMPL Advice representing when aspect should be initialized
+    public static final AdviceKind PerTypeWithinEntry   = new AdviceKind("perTypeWithinEntry",14,1,false,false);
    
 
     public static AdviceKind stringToKind(String s) {
@@ -99,8 +104,10 @@ public class AdviceKind extends TypeSafeEnum {
        }
 
        public boolean isPerEntry() {
-               return this == PerCflowEntry || this == PerCflowBelowEntry ||
-                       this == PerThisEntry || this == PerTargetEntry;
+               return 
+                   this == PerCflowEntry || this == PerCflowBelowEntry ||
+                       this == PerThisEntry || this == PerTargetEntry || 
+                       this == PerTypeWithinEntry; // PTWIMPL Allow for PTW case
        }
        
        public boolean isPerObjectEntry() {
index f19776f05ea00a014443ec9ccefd4c11ecbbebfc..d285a1574eefee6b789715c3bbec437e73de80ff 100644 (file)
@@ -68,6 +68,15 @@ public class AjcMemberMaker {
                                "<init>",
                "()V");
        }
+       
+       public static Member noAspectBoundExceptionInit2() {
+               return new ResolvedMember(
+                               Member.METHOD,
+                               NO_ASPECT_BOUND_EXCEPTION,
+                               Modifier.PUBLIC,
+                               "<init>",
+               "(Ljava/lang/String;Ljava/lang/Throwable;)V");
+       }
 
        public static Member noAspectBoundExceptionInitWithCause() {
                return new ResolvedMember(
@@ -129,6 +138,27 @@ public class AjcMemberMaker {
                        NameMangler.perObjectInterfaceField(aspectType),
                        TypeX.NONE);
        }
+       
+       // PTWIMPL ResolvedMember for aspect instance field, declared in matched type
+       public static ResolvedMember perTypeWithinField(TypeX declaringType, ResolvedTypeX aspectType) {
+               int modifiers = Modifier.PRIVATE | Modifier.STATIC;
+               if (!TypeX.SERIALIZABLE.isAssignableFrom(aspectType, aspectType.getWorld())) {
+                       modifiers |= Modifier.TRANSIENT;
+               }
+               return new ResolvedMember(Member.FIELD, declaringType, modifiers,
+                       aspectType,     NameMangler.perTypeWithinFieldForTarget(aspectType), TypeX.NONE);
+       }
+       
+       // PTWIMPL ResolvedMember for type instance field, declared in aspect 
+       // (holds typename for which aspect instance exists)
+       public static ResolvedMember perTypeWithinWithinTypeField(TypeX declaringType, ResolvedTypeX aspectType) {
+               int modifiers = Modifier.PRIVATE;
+               if (!TypeX.SERIALIZABLE.isAssignableFrom(aspectType, aspectType.getWorld())) {
+                       modifiers |= Modifier.TRANSIENT;
+               }
+               return new ResolvedMember(Member.FIELD, declaringType, modifiers,
+                       TypeX.forSignature("Ljava/lang/String;"), NameMangler.PERTYPEWITHIN_WITHINTYPEFIELD, TypeX.NONE);
+       }
 
        
        public static ResolvedMember perObjectBind(TypeX declaringType) {
@@ -139,6 +169,34 @@ public class AjcMemberMaker {
                        NameMangler.PEROBJECT_BIND_METHOD,
                        "(Ljava/lang/Object;)V");
        }
+       
+       // PTWIMPL ResolvedMember for getInstance() method, declared in aspect
+       public static ResolvedMember perTypeWithinGetInstance(TypeX declaringType) {
+//             private static a.X ajc$getInstance(java.lang.Class) throws java/lang/Exception
+               ResolvedMember rm = new ResolvedMember(
+                       Member.METHOD, 
+                       declaringType,
+                       PRIVATE_STATIC,
+                       declaringType, // return value
+                       NameMangler.PERTYPEWITHIN_GETINSTANCE_METHOD,
+                       new TypeX[]{TypeX.JAVA_LANG_CLASS},
+                       new TypeX[]{TypeX.JAVA_LANG_EXCEPTION}
+                       );      
+               return rm;
+       }
+       
+       public static ResolvedMember perTypeWithinCreateAspectInstance(TypeX declaringType) {
+               // public static a.X ajc$createAspectInstance(java.lang.String)
+               ResolvedMember rm = new ResolvedMember(
+                               Member.METHOD, 
+                               declaringType,
+                               PUBLIC_STATIC,
+                               declaringType, // return value
+                               NameMangler.PERTYPEWITHIN_CREATEASPECTINSTANCE_METHOD,
+                               new TypeX[]{TypeX.forSignature("Ljava/lang/String;")},new TypeX[]{}
+                               );      
+                       return rm;
+       }
 
 
        public static TypeX perObjectInterfaceType(TypeX aspectType) {
@@ -163,8 +221,16 @@ public class AjcMemberMaker {
                        "(" + aspectType.getSignature() + ")V");
        }
        
-       
-       
+       // PTWIMPL ResolvedMember for localAspectOf() method, declared in matched type
+       public static ResolvedMember perTypeWithinLocalAspectOf(TypeX shadowType,TypeX aspectType) {
+               return new ResolvedMember(
+                       Member.METHOD, 
+                       shadowType,//perTypeWithinInterfaceType(aspectType),
+                       Modifier.PUBLIC | Modifier.STATIC,
+                       NameMangler.perTypeWithinLocalAspectOf(aspectType),
+                       "()" + aspectType.getSignature());
+       }
+
        
        public static ResolvedMember perSingletonAspectOfMethod(TypeX declaringType) {
                return new ResolvedMember(Member.METHOD,
@@ -198,6 +264,20 @@ public class AjcMemberMaker {
                        "(Ljava/lang/Object;)Z");               
        };
        
+       // PTWIMPL ResolvedMember for aspectOf(), declared in aspect
+       public static ResolvedMember perTypeWithinAspectOfMethod(TypeX declaringType) {
+               return new ResolvedMember(Member.METHOD,
+                               declaringType, PUBLIC_STATIC, "aspectOf", 
+                               "(Ljava/lang/Class;)" + declaringType.getSignature());          
+       }
+       
+       // PTWIMPL ResolvedMember for hasAspect(), declared in aspect
+       public static ResolvedMember perTypeWithinHasAspectMethod(TypeX declaringType) {
+               return new ResolvedMember(Member.METHOD,
+                       declaringType, PUBLIC_STATIC, "hasAspect", 
+                       "(Ljava/lang/Class;)Z");                
+       };
+       
        // -- privileged accessors
        
        public static ResolvedMember privilegedAccessMethodForMethod(TypeX aspectType, ResolvedMember method) {
index 6d49a45fbf11eaaf7a66a6835d78f8f805b413d5..1888faef8befd46ec9afbec09972801aea1c6083 100644 (file)
@@ -37,7 +37,12 @@ public class NameMangler {
        public static final String PERCFLOW_PUSH_METHOD = PREFIX + "perCflowPush";
 
        public static final String PEROBJECT_BIND_METHOD = PREFIX + "perObjectBind";
-
+       
+       // PTWIMPL Method and field names
+       public static final String PERTYPEWITHIN_GETINSTANCE_METHOD          = PREFIX + "getInstance";
+       public static final String PERTYPEWITHIN_CREATEASPECTINSTANCE_METHOD = PREFIX + "createAspectInstance";
+       public static final String PERTYPEWITHIN_WITHINTYPEFIELD             = PREFIX + "withinType";
+       
        public static final String AJC_PRE_CLINIT_NAME = PREFIX + "preClinit";
 
        public static final String AJC_POST_CLINIT_NAME = PREFIX + "postClinit";
@@ -57,6 +62,17 @@ public class NameMangler {
        }
 
        
+       // PTWIMPL method names that must include aspect type
+       public static String perTypeWithinFieldForTarget(TypeX aspectType) {
+               String s = makeName(aspectType.getNameAsIdentifier(), "ptwAspectInstance");
+               return s;
+       }
+       
+       public static String perTypeWithinLocalAspectOf(TypeX aspectType) {
+               return makeName(aspectType.getNameAsIdentifier(), "localAspectOf");
+       }
+       
+       
        
        public static String privilegedAccessMethodForMethod(String name, TypeX objectType, TypeX aspectType) {
                return makeName("privMethod", aspectType.getNameAsIdentifier(),
diff --git a/weaver/src/org/aspectj/weaver/PerTypeWithinTargetTypeMunger.java b/weaver/src/org/aspectj/weaver/PerTypeWithinTargetTypeMunger.java
new file mode 100644 (file)
index 0000000..4da7f11
--- /dev/null
@@ -0,0 +1,52 @@
+/* *******************************************************************
+ * Copyright (c) 2005
+ * All rights reserved. 
+ * This program and the accompanying materials are made available 
+ * under the terms of the Common Public License v1.0 
+ * which accompanies this distribution and is available at 
+ * http://www.eclipse.org/legal/cpl-v10.html 
+ *  
+ * Contributors: 
+ *     Andy Clement     initial implementation 
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.aspectj.weaver.patterns.PerTypeWithin;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.TypePattern;
+
+// PTWIMPL Target type munger adds the localAspectOf() method
+public class PerTypeWithinTargetTypeMunger extends ResolvedTypeMunger {
+       private ResolvedMember localAspectOfMethod;
+       private TypeX aspectType;
+       private PerTypeWithin testPointcut;
+
+
+       public PerTypeWithinTargetTypeMunger(TypeX aspectType, PerTypeWithin testPointcut) {
+               super(PerTypeWithinInterface, null);
+               this.aspectType    = aspectType;
+               this.testPointcut  = testPointcut;
+       }
+       
+
+       public void write(DataOutputStream s) throws IOException {
+               throw new RuntimeException("shouldn't be serialized");
+       }
+       
+       public TypeX getAspectType() {
+               return aspectType;
+       }
+
+       public Pointcut getTestPointcut() {
+               return testPointcut;
+       }
+       
+       public boolean matches(ResolvedTypeX matchType, ResolvedTypeX aspectType) {
+               return testPointcut.getTypePattern().matches(matchType,TypePattern.STATIC).alwaysTrue();
+       }
+
+}
index f28e8753534df0c47aa08d5bb3e3bf3fbf09f653..17c87c9d35bf3f8fa0aac5c22d1a95afeeef60aa 100644 (file)
@@ -224,6 +224,7 @@ public abstract class ResolvedTypeMunger {
        public static final Kind PrivilegedAccess = new Kind("PrivilegedAccess", 4);
        
        public static final Kind Parent = new Kind("Parent", 6);
+       public static final Kind PerTypeWithinInterface = new Kind("PerTypeWithinInterface",7); // PTWIMPL not serialized, used during concretization of aspects
 
        public static final String SUPER_DISPATCH_NAME = "superDispatch";
 
index c13349eb351d1c4abc52054879ca0a1d47734879..3dad1b8fadd1ccc66d11172c83fa9a7bd0172c6b 100644 (file)
@@ -584,6 +584,9 @@ public class TypeX implements AnnotatedElement {
     public static final TypeX   AT_RETENTION = forSignature("Ljava/lang/annotation/Retention;");
     public static final TypeX   ENUM         = forSignature("Ljava/lang/Enum;");
     public static final TypeX   ANNOTATION   = forSignature("Ljava/lang/annotation/Annotation;");
+    public static final TypeX   JAVA_LANG_CLASS = forSignature("Ljava/lang/Class;");
+    public static final TypeX   JAVA_LANG_EXCEPTION = forSignature("Ljava/lang/Exception;");
+    public static final TypeX   JAVA_LANG_REFLECT_METHOD = forSignature("Ljava/lang/reflect/Method;");
 
     
     // ---- helpers
index 76589720f63b86bbfe19ac9d0e69695fe54971d0..344602d97c314a952d03e6bcf1b4adf6edfaccce 100644 (file)
@@ -160,6 +160,9 @@ public class BcelAdvice extends Advice {
                 shadow.weavePerObjectEntry(this, (BcelVar)shadow.getTargetVar());
         } else if (getKind() == AdviceKind.Softener) {
                 shadow.weaveSoftener(this, ((ExactTypePattern)exceptionType).getType());
+        } else if (getKind() == AdviceKind.PerTypeWithinEntry) {
+             // PTWIMPL Entry to ptw is the static initialization of a type that matched the ptw type pattern
+                    shadow.weavePerTypeWithinAspectInitialization(this,shadow.getEnclosingType());
         } else {
             throw new BCException("unimplemented kind: " + getKind());
         }
index fe32b0aa6d4eea93419b46b64256804c8e22bb96..aa03a51ab38c4ee50740ef086fa8ffc6adce6162 100644 (file)
@@ -43,6 +43,7 @@ import org.aspectj.apache.bcel.generic.LoadInstruction;
 import org.aspectj.apache.bcel.generic.MULTIANEWARRAY;
 import org.aspectj.apache.bcel.generic.NEW;
 import org.aspectj.apache.bcel.generic.ObjectType;
+import org.aspectj.apache.bcel.generic.PUSH;
 import org.aspectj.apache.bcel.generic.ReturnInstruction;
 import org.aspectj.apache.bcel.generic.SWAP;
 import org.aspectj.apache.bcel.generic.StoreInstruction;
@@ -1510,6 +1511,32 @@ public class BcelShadow extends Shadow {
                
                range.insert(entryInstructions, Range.InsideBefore);
        }
+       
+       // PTWIMPL Create static initializer to call the aspect factory 
+       /**
+        * Causes the aspect instance to be *set* for later retrievable through localAspectof()/aspectOf()
+        */
+       public void weavePerTypeWithinAspectInitialization(final BcelAdvice munger,TypeX t) {
+        final InstructionFactory fact = getFactory();        
+
+               InstructionList entryInstructions = new InstructionList();
+               InstructionList entrySuccessInstructions = new InstructionList();
+               
+               BcelObjectType aspectType = BcelWorld.getBcelObjectType(munger.getConcreteAspect());
+               String aspectname = munger.getConcreteAspect().getName();
+               
+               String ptwField = NameMangler.perTypeWithinFieldForTarget(munger.getConcreteAspect());
+               entrySuccessInstructions.append(new PUSH(fact.getConstantPool(),t.getName()));
+               
+               entrySuccessInstructions.append(fact.createInvoke(aspectname,"ajc$createAspectInstance",new ObjectType(aspectname),
+                               new Type[]{new ObjectType("java.lang.String")},Constants.INVOKESTATIC));
+               entrySuccessInstructions.append(fact.createPutStatic(t.getName(),ptwField,
+                               new ObjectType(aspectname)));
+               
+               entryInstructions.append(entrySuccessInstructions);
+               
+               range.insert(entryInstructions, Range.InsideBefore);
+       }
     
        
        public void weaveCflowEntry(final BcelAdvice munger, final Member cflowField) {
index 935d2f966a6acbaddf05f61fa5c998e50d4d7486..d8e755a8c834144cd3520d46a1bc7fc8b4982e7d 100644 (file)
@@ -42,6 +42,7 @@ import org.aspectj.weaver.NewFieldTypeMunger;
 import org.aspectj.weaver.NewMethodTypeMunger;
 import org.aspectj.weaver.NewParentTypeMunger;
 import org.aspectj.weaver.PerObjectInterfaceTypeMunger;
+//import org.aspectj.weaver.PerTypeWithinTargetTypeMunger;
 import org.aspectj.weaver.PrivilegedAccessMunger;
 import org.aspectj.weaver.ResolvedMember;
 import org.aspectj.weaver.ResolvedTypeMunger;
@@ -74,6 +75,10 @@ public class BcelTypeMunger extends ConcreteTypeMunger {
                } else if (munger.getKind() == ResolvedTypeMunger.PerObjectInterface) {
                        changed = mungePerObjectInterface(weaver, (PerObjectInterfaceTypeMunger)munger);
                        worthReporting = false;
+               } else if (munger.getKind() == ResolvedTypeMunger.PerTypeWithinInterface) {
+                       // PTWIMPL Transform the target type (add the aspect instance field)
+                       changed = mungePerTypeWithinTransformer(weaver);
+                       worthReporting = false;
                } else if (munger.getKind() == ResolvedTypeMunger.PrivilegedAccess) {
                        changed = mungePrivilegedAccess(weaver, (PrivilegedAccessMunger)munger);
                        worthReporting = false;
@@ -646,7 +651,42 @@ public class BcelTypeMunger extends ConcreteTypeMunger {
                        return false;
                }
        }
+       
+       // PTWIMPL Add field to hold aspect instance and an accessor
+       private boolean mungePerTypeWithinTransformer(BcelClassWeaver weaver) {
+               LazyClassGen gen = weaver.getLazyClassGen();
+                       
+               // if (couldMatch(gen.getBcelObjectType(), munger.getTestPointcut())) {
+                       
+                       // Add (to the target type) the field that will hold the aspect instance
+                       // e.g ajc$com_blah_SecurityAspect$ptwAspectInstance
+                       FieldGen fg = makeFieldGen(gen, AjcMemberMaker.perTypeWithinField(gen.getType(), aspectType));
+                   gen.addField(fg.getField(),getSourceLocation());
+                       
+                   // Add an accessor for this new field, the ajc$<aspectname>$localAspectOf() method
+                   // e.g. "public com_blah_SecurityAspect ajc$com_blah_SecurityAspect$localAspectOf()"
+                   Type fieldType = BcelWorld.makeBcelType(aspectType);
+                       LazyMethodGen mg = new LazyMethodGen(
+                                       Modifier.PUBLIC | Modifier.STATIC,fieldType,
+                               NameMangler.perTypeWithinLocalAspectOf(aspectType),
+                                       new Type[0], new String[0],gen);
+                       InstructionList il = new InstructionList();
+                       //PTWIMPL ?? Should check if it is null and throw NoAspectBoundException
+                       InstructionFactory fact = gen.getFactory();
+                       il.append(fact.createFieldAccess(
+                               gen.getClassName(), 
+                               fg.getName(),
+                               fieldType, Constants.GETSTATIC));
+                       il.append(InstructionFactory.createReturn(fieldType));
+                       mg.getBody().insert(il);                
+                       gen.addMethodGen(mg);
+                       return true;
+//             } else {
+//                     return false;
+//             }
+       }
 
+       // ??? Why do we have this method? I thought by now we would know if it matched or not
        private boolean couldMatch(
                BcelObjectType bcelObjectType,
                Pointcut pointcut) {
index 9b994deb8bda01af9ea9244f58189204445434ec..575bcc7e1168a7ccecc87dc36314d581af88b614 100644 (file)
@@ -51,6 +51,8 @@ public class PatternParser {
                                return parsePerCflow(false);
                        } else if (name.equals("percflowbelow")) {
                                return parsePerCflow(true);
+                       } else if (name.equals("pertypewithin")) { // PTWIMPL Parse the pertypewithin clause
+                               return parsePerTypeWithin();
                        } else {
                                return null;
                        }
@@ -74,6 +76,14 @@ public class PatternParser {
                eat(")");
                return new PerObject(entry, isThis);
        }
+       
+       private PerClause parsePerTypeWithin() {
+               parseIdentifier();
+               eat("(");
+               TypePattern withinTypePattern = parseTypePattern();
+               eat(")");
+               return new PerTypeWithin(withinTypePattern);
+       }
 
 
        private PerClause parsePerSingleton() {
index 5bff424ebf1014bd2299a53b996a241f6125033c..8b59094d148fb94fd5f47550ff37418c5231c502 100644 (file)
@@ -18,6 +18,7 @@ import java.io.IOException;
 import org.aspectj.util.TypeSafeEnum;
 import org.aspectj.weaver.*;
 
+// PTWIMPL New kind added to this class, can be (de)serialized
 public abstract class PerClause extends Pointcut {
        protected ResolvedTypeX inAspect;
 
@@ -27,6 +28,7 @@ public abstract class PerClause extends Pointcut {
                else if (kind == PERCFLOW) return PerCflow.readPerClause(s, context);
                else if (kind == PEROBJECT) return PerObject.readPerClause(s, context);
                else if (kind == FROMSUPER) return PerFromSuper.readPerClause(s, context);
+               else if (kind == PERTYPEWITHIN) return PerTypeWithin.readPerClause(s,context);
                        
                throw new BCException("unknown kind: " + kind);
        }
@@ -49,6 +51,7 @@ public abstract class PerClause extends Pointcut {
                 case 2: return PERCFLOW;
                 case 3: return PEROBJECT;
                 case 4: return FROMSUPER;
+                case 5: return PERTYPEWITHIN;
             }
             throw new BCException("weird kind " + key);
         }
@@ -62,4 +65,5 @@ public abstract class PerClause extends Pointcut {
        public static final Kind PERCFLOW  = new Kind("percflow", 2);
        public static final Kind PEROBJECT  = new Kind("perobject", 3);
        public static final Kind FROMSUPER  = new Kind("fromsuper", 4);
+       public static final Kind PERTYPEWITHIN = new Kind("pertypewithin",5);
 }
diff --git a/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java b/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java
new file mode 100644 (file)
index 0000000..4e29e13
--- /dev/null
@@ -0,0 +1,175 @@
+/* *******************************************************************
+ * Copyright (c) 2005 IBM
+ * All rights reserved. 
+ * This program and the accompanying materials are made available 
+ * under the terms of the Common Public License v1.0 
+ * which accompanies this distribution and is available at 
+ * http://www.eclipse.org/legal/cpl-v10.html 
+ *  
+ * Contributors: 
+ *     Andy Clement     initial implementation 
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.Message;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.Advice;
+import org.aspectj.weaver.AjcMemberMaker;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.Member;
+//import org.aspectj.weaver.PerTypeWithinTargetTypeMunger;
+import org.aspectj.weaver.PerTypeWithinTargetTypeMunger;
+import org.aspectj.weaver.ResolvedTypeMunger;
+import org.aspectj.weaver.ResolvedTypeX;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Expr;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+
+
+// PTWIMPL Represents a parsed pertypewithin()
+public class PerTypeWithin extends PerClause {
+
+       private TypePattern typePattern;
+       
+       // Any shadow could be considered within a pertypewithin() type pattern
+       private static final Set kindSet = new HashSet(Shadow.ALL_SHADOW_KINDS);
+       
+       public TypePattern getTypePattern() {
+               return typePattern;
+       }
+       
+       public PerTypeWithin(TypePattern p) {
+               this.typePattern = p;
+       }
+
+       public Set couldMatchKinds() {
+               return kindSet;
+       }
+       
+       // -----
+       public FuzzyBoolean fastMatch(FastMatchInfo info) {
+               if (typePattern.annotationPattern instanceof AnyAnnotationTypePattern) {
+                       return isWithinType(info.getType());
+               }
+               return FuzzyBoolean.MAYBE;
+       }
+       
+       
+    protected FuzzyBoolean matchInternal(Shadow shadow) {
+       ResolvedTypeX enclosingType = shadow.getIWorld().resolve(shadow.getEnclosingType(),true);
+       if (enclosingType == ResolvedTypeX.MISSING) {
+               //PTWIMPL ?? Add a proper message
+               IMessage msg = new Message(
+                               "Cant find type pertypewithin matching...",
+                                       shadow.getSourceLocation(),true,new ISourceLocation[]{getSourceLocation()});
+               shadow.getIWorld().getMessageHandler().handleMessage(msg);
+       }
+       typePattern.resolve(shadow.getIWorld());
+       return isWithinType(enclosingType);
+    }
+
+    public void resolveBindings(IScope scope, Bindings bindings) {
+       typePattern = typePattern.resolveBindings(scope, bindings, false, false);
+    }
+    
+    protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+       Member ptwField = AjcMemberMaker.perTypeWithinField(shadow.getEnclosingType(),inAspect);
+       
+       Expr myInstance =
+               Expr.makeCallExpr(AjcMemberMaker.perTypeWithinLocalAspectOf(shadow.getEnclosingType(),inAspect/*shadow.getEnclosingType()*/),
+                               Expr.NONE,inAspect);
+       state.setAspectInstance(myInstance);
+       
+       // this worked at one point
+       //Expr myInstance = Expr.makeFieldGet(ptwField,shadow.getEnclosingType().resolve(shadow.getIWorld()));//inAspect);
+       //state.setAspectInstance(myInstance);
+       
+       
+//     return Test.makeFieldGetCall(ptwField,null,Expr.NONE);
+       // cflowField, cflowCounterIsValidMethod, Expr.NONE
+       
+       // This is what is in the perObject variant of this ...
+//     Expr myInstance =
+//             Expr.makeCallExpr(AjcMemberMaker.perTypeWithinAspectOfMethod(inAspect),
+//                                                     new Expr[] {getVar(shadow)}, inAspect);
+//     state.setAspectInstance(myInstance);
+//     return Test.makeCall(AjcMemberMaker.perTypeWithinHasAspectMethod(inAspect), 
+//                     new Expr[] { getVar(shadow) });
+//     
+
+       
+        return match(shadow).alwaysTrue()?Literal.TRUE:Literal.FALSE;
+    }
+    
+
+       public PerClause concretize(ResolvedTypeX inAspect) {
+               PerTypeWithin ret = new PerTypeWithin(typePattern);
+               ret.copyLocationFrom(this);
+               ret.inAspect = inAspect;
+               if (inAspect.isAbstract()) return ret;
+               
+               
+               World world = inAspect.getWorld();
+               
+               SignaturePattern sigpat = new SignaturePattern(
+                               Member.STATIC_INITIALIZATION,
+                               ModifiersPattern.ANY,
+                               TypePattern.ANY,
+                               typePattern,
+                               NamePattern.ANY,
+                               TypePatternList.ANY,
+                               ThrowsPattern.ANY,
+                               AnnotationTypePattern.ANY
+                               );
+               Pointcut testPc = new KindedPointcut(Shadow.StaticInitialization,sigpat);
+               Pointcut testPc2= new WithinPointcut(typePattern);
+               // This munger will initialize the aspect instance field in the matched type
+               inAspect.crosscuttingMembers.addConcreteShadowMunger(Advice.makePerTypeWithinEntry(world, testPc, inAspect));
+               
+               ResolvedTypeMunger munger = new PerTypeWithinTargetTypeMunger(inAspect, ret);
+               inAspect.crosscuttingMembers.addTypeMunger(world.concreteTypeMunger(munger, inAspect));
+               return ret;
+               
+       }
+
+    public void write(DataOutputStream s) throws IOException {
+       PERTYPEWITHIN.write(s);
+       typePattern.write(s);
+       writeLocation(s);
+    }
+    
+       public static PerClause readPerClause(VersionedDataInputStream s, ISourceContext context) throws IOException {
+               PerClause ret = new PerTypeWithin(TypePattern.read(s, context));
+               ret.readLocation(context, s);
+               return ret;
+       }
+       
+       public PerClause.Kind getKind() {
+               return PERTYPEWITHIN;
+       }
+       
+       public String toString() {
+               return "pertypewithin("+typePattern+")";
+       }
+       
+       private FuzzyBoolean isWithinType(ResolvedTypeX type) {
+               while (type != null) {
+                       if (typePattern.matchesStatically(type)) {
+                               return FuzzyBoolean.YES;
+                       }
+                       type = type.getDeclaringType();
+               }
+               return FuzzyBoolean.NO;
+       }
+}