]> source.dussan.org Git - aspectj.git/commitdiff
The BIG commit.
authoraclement <aclement>
Tue, 3 Aug 2004 12:31:29 +0000 (12:31 +0000)
committeraclement <aclement>
Tue, 3 Aug 2004 12:31:29 +0000 (12:31 +0000)
- Enhanced structure model support.
- *Incremental* structure model support written and tested (currently switched off, see incModelTests.xml)
- -showWeaveInfo compiler option
- existence of a 'runtimetest' surfaced through relationships
- UI can determine if errors/warnings came from DEOWs.
- Code to enable type mungers to remember source locations written (currently switched off)

89 files changed:
ajde/src/org/aspectj/ajde/internal/CompilerAdapter.java
ajde/src/org/aspectj/ajde/ui/StructureModelUtil.java
ajde/src/org/aspectj/ajde/ui/StructureViewNodeFactory.java
ajde/testsrc/org/aspectj/ajde/AjdeTests.java
ajde/testsrc/org/aspectj/ajde/AsmDeclarationsTest.java
ajde/testsrc/org/aspectj/ajde/AsmRelationshipsTest.java
ajde/testsrc/org/aspectj/ajde/BuildCancellingTest.java
ajde/testsrc/org/aspectj/ajde/ShowWeaveMessagesTestCase.java [new file with mode: 0644]
asm/src/org/aspectj/asm/AsmManager.java
asm/src/org/aspectj/asm/IHierarchy.java
asm/src/org/aspectj/asm/IProgramElement.java
asm/src/org/aspectj/asm/IRelationship.java
asm/src/org/aspectj/asm/IRelationshipMap.java
asm/src/org/aspectj/asm/internal/AspectJElementHierarchy.java
asm/src/org/aspectj/asm/internal/ProgramElement.java
asm/src/org/aspectj/asm/internal/Relationship.java
asm/src/org/aspectj/asm/internal/RelationshipMap.java
bridge/src/org/aspectj/bridge/IMessage.java
bridge/src/org/aspectj/bridge/Message.java
bridge/src/org/aspectj/bridge/MessageHandler.java
bridge/src/org/aspectj/bridge/WeaveMessage.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverMessageHandler.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AsmInterTypeRelationshipProvider.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseTypeMunger.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmElementFormatter.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmHierarchyBuilder.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseAdapterUtils.java
org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java
org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/BcweaverJarMaker.java
testing/src/org/aspectj/testing/harness/bridge/IncCompilerRun.java
testing/src/org/aspectj/testing/xml/SoftMessage.java
tests/ajcTestSuite.dtd
tests/incModelTests.xml [new file with mode: 0644]
tests/incremental/model/intertype/primary/Alpha.java [new file with mode: 0644]
tests/incremental/model/intertype/secondary/BetaA.20.java [new file with mode: 0644]
tests/incremental/model/intertype/secondary/BetaA.30.java [new file with mode: 0644]
tests/incremental/model/introduction/introduction/CloneablePoint.20.java [new file with mode: 0644]
tests/incremental/model/introduction/introduction/CloneablePoint.java [new file with mode: 0644]
tests/incremental/model/introduction/introduction/ComparablePoint.java [new file with mode: 0644]
tests/incremental/model/introduction/introduction/HashablePoint.30.java [new file with mode: 0644]
tests/incremental/model/introduction/introduction/HashablePoint.java [new file with mode: 0644]
tests/incremental/model/introduction/introduction/Point.30.java [new file with mode: 0644]
tests/incremental/model/introduction/introduction/Point.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_addremove/primary/Alpha.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_addremove/primary/Beta.20.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_addremove/primary/Beta.delete.60.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_addremove/secondary/Delta.40.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_addremove/secondary/Delta.delete.60.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_addremove/secondary/Gamma.30.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_addremove/secondary/Gamma.delete.50.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_updating/primary/Alpha.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_updating/primary/Beta.20.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_updating/primary/Beta.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_updating/secondary/Delta.30.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_updating/secondary/Delta.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_updating/secondary/Gamma.40.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_updating/secondary/Gamma.50.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_updating/secondary/Gamma.60.java [new file with mode: 0644]
tests/incremental/model/sourcefiles_updating/secondary/Gamma.java [new file with mode: 0644]
tests/incremental/model/weaving/primary/Alpha.java [new file with mode: 0644]
tests/incremental/model/weaving/primary/BetaA.20.java [new file with mode: 0644]
tests/incremental/model/weaving/primary/BetaA.30.java [new file with mode: 0644]
tests/incremental/model/weaving/primary/BetaA.40.java [new file with mode: 0644]
tests/incremental/model/weaving/primary/BetaA.java [new file with mode: 0644]
tests/incremental/model/weaving2/primary/Alpha.java [new file with mode: 0644]
tests/incremental/model/weaving2/primary/BetaA.20.java [new file with mode: 0644]
tests/incremental/model/weaving2/primary/BetaA.delete.40.java [new file with mode: 0644]
tests/incremental/model/weaving2/primary/BetaA.java [new file with mode: 0644]
tests/incremental/model/weaving2/secondary/GammaA.30.java [new file with mode: 0644]
weaver/src/org/aspectj/weaver/AsmRelationshipProvider.java
weaver/src/org/aspectj/weaver/Checker.java
weaver/src/org/aspectj/weaver/ConcreteTypeMunger.java
weaver/src/org/aspectj/weaver/ICrossReferenceHandler.java
weaver/src/org/aspectj/weaver/NewConstructorTypeMunger.java
weaver/src/org/aspectj/weaver/NewFieldTypeMunger.java
weaver/src/org/aspectj/weaver/NewMethodTypeMunger.java
weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java
weaver/src/org/aspectj/weaver/Shadow.java
weaver/src/org/aspectj/weaver/WeaverMetrics.java [new file with mode: 0644]
weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java
weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java
weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java
weaver/src/org/aspectj/weaver/patterns/FastMatchInfo.java

index 34637e24fd0dcc5f40bcccd7f4e93cea56eea048..f98e08c0edaad40e2435d1d0577f990d311ce96d 100644 (file)
@@ -432,6 +432,16 @@ public class CompilerAdapter {
        }
 
 
+       /** Local helper method for splitting option strings */
+       private static List tokenizeString(String str) {
+               List tokens = new ArrayList();
+               StringTokenizer tok = new StringTokenizer(str);
+               while ( tok.hasMoreTokens() ) {
+                       tokens.add(tok.nextToken());    
+               }
+               return tokens;
+       }
+       
        /**
         * Helper method for configure build options.
      * This reads all command-line options specified
@@ -448,13 +458,25 @@ public class CompilerAdapter {
             return true;
         }
                
-               StringTokenizer tok = new StringTokenizer( nonStdOptions );
-               String[] args = new String[ tok.countTokens() ];
-               int argCount = 0;
-               while ( tok.hasMoreTokens() ) {
-                       args[argCount++] = tok.nextToken();     
+               // Break a string into a string array of non-standard options.
+               // Allows for one option to include a ' '.   i.e. assuming it has been quoted, it
+               // won't accidentally get treated as a pair of options (can be needed for xlint props file option)
+               List tokens = new ArrayList();
+               int ind = nonStdOptions.indexOf('\"');
+               int ind2 = nonStdOptions.indexOf('\"',ind+1);
+               if ((ind > -1) && (ind2 > -1)) { // dont tokenize within double quotes
+                       String pre = nonStdOptions.substring(0,ind);
+                       String quoted = nonStdOptions.substring(ind+1,ind2);
+                       String post = nonStdOptions.substring(ind2+1,nonStdOptions.length());
+                       tokens.addAll(tokenizeString(pre));
+                       tokens.add(quoted);
+                       tokens.addAll(tokenizeString(post));
+               } else {
+                       tokens.addAll(tokenizeString(nonStdOptions));
                }
-
+               String[] args = (String[])tokens.toArray(new String[]{});
+               
+               
                // set the non-standard options in an alternate build config
                // (we don't want to lose the settings we already have)
         CountingMessageHandler counter 
index fcc039e21d09434765ed9e3121735cf3691c1dee..d9b1e8c97fb33a565dcded0005166542f3a65bcc 100644 (file)
 
 package org.aspectj.ajde.ui;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
 
 import org.aspectj.ajde.Ajde;
-import org.aspectj.asm.*;
+import org.aspectj.asm.AsmManager;
+import org.aspectj.asm.IHierarchy;
+import org.aspectj.asm.IProgramElement;
+import org.aspectj.asm.IRelationshipMap;
 //import org.aspectj.asm.internal.*;
 
 /**
  * Prototype functionality for package view clients.
  */  
 public class StructureModelUtil {
-
+       
+       public static class ModelIncorrectException extends Exception {
+               public ModelIncorrectException(String s) {
+                       super(s);
+               }
+       }
+       
+       /**
+        * Check the properties of the current model.  The parameter string lists properties of the model
+        * that should be correct.  If any of the properties are incorrect, a ModelIncorrectException is
+        * thrown.
+        * 
+        * @param toCheck comma separated list of name=value pairs that should be found in the ModelInfo object
+        * @throws ModelIncorrectException thrown if any of the name=value pairs in toCheck are not found
+        */
+       public static void checkModel(String toCheck) throws ModelIncorrectException {
+               Properties modelProperties = AsmManager.ModelInfo.summarizeModel().getProperties();
+               
+               // Break toCheck into pieces and check each exists
+               StringTokenizer st = new StringTokenizer(toCheck,",=");
+               while (st.hasMoreTokens()) {
+                       String key = st.nextToken();
+                       String expValue = st.nextToken();
+                       boolean expectingZero = false;
+                       try {
+                               expectingZero = (Integer.parseInt(expValue)==0);
+                       } catch (NumberFormatException nfe) {
+                               // this is ok as expectingZero will be false
+                       }
+                   String value = modelProperties.getProperty(key);
+                   if (value == null) {
+                       if (!expectingZero)
+                         throw new ModelIncorrectException("Couldn't find '"+key+"' property for the model");  
+                   } else if (!value.equals(expValue)) {
+                       throw new ModelIncorrectException("Model property '"+key+"' incorrect:  Expected "+expValue+" but found "+value);
+                   }
+               }       
+       }
+       
        /**
         * This method returns a map from affected source lines in a class to
         * a List of aspects affecting that line.
index 4f32eedc78cf75331704e837e470f0f90e00ced7..2e6693d56d1fb0f30e428d77f41dba6faf0eb849 100644 (file)
@@ -38,7 +38,9 @@ public abstract class StructureViewNodeFactory {
 
                IStructureViewNode svNode = createDeclaration(node, icon, children);
                String nodeHandle = node.getHandleIdentifier();
-               if (nodeHandle != null) {       
+               // Don't put relationships on fields as they can then appear twice when building the outline - 
+               // once under clinit field-set nodes and once under the field declaration.
+               if (nodeHandle != null && !node.getKind().equals(IProgramElement.Kind.FIELD)) { 
                        List relationships = AsmManager.getDefault().getRelationshipMap().get(nodeHandle);
                        if (relationships != null) {
                                for (Iterator it = relationships.iterator(); it.hasNext(); ) {
index e70619504cffce35089792e1f458335d826990b0..a2155fd9baf3889716de504756a67b4592be2d6b 100644 (file)
@@ -38,6 +38,7 @@ public class AjdeTests extends TestCase {
                suite.addTestSuite(BuildCancellingTest.class);
                suite.addTestSuite(JarManifestTest.class);
                suite.addTestSuite(DuplicateManifestTest.class);
+               suite.addTestSuite(ShowWeaveMessagesTestCase.class);
                
         //$JUnit-END$
         return suite;
index d5902854bab2fd08d594fde2a9ba5ebf2a4d170a..bcf70db2efad5474e0aa8809cdbcacd80a09e61d 100644 (file)
@@ -73,16 +73,16 @@ public class AsmDeclarationsTest extends AjdeTestCase {
                assertNotNull(decWarnNode);
                assertEquals(decWarnNode.toLabelString(), decWarnMessage);      
                
-               String decParentsMessage = "declare parents: Point";
+               String decParentsMessage = "declare parents: implements Serializable";
                IProgramElement decParentsNode = model.findElementForSignature(aspect, IProgramElement.Kind.DECLARE_PARENTS, "declare parents");
                assertNotNull(decParentsNode);          
                assertEquals(decParentsNode.toLabelString(), decParentsMessage);                
                // check the next two relative to this one
                int declareIndex = decParentsNode.getParent().getChildren().indexOf(decParentsNode);
-               String decParentsPtnMessage = "declare parents: Point+";                
-               assertEquals(((IProgramElement)aspect.getChildren().get(declareIndex+1)).toLabelString(), decParentsPtnMessage);                        
-               String decParentsTPMessage = "declare parents: <type pattern>"; 
-               assertEquals(((IProgramElement)aspect.getChildren().get(declareIndex+2)).toLabelString(), decParentsTPMessage);
+               String decParentsPtnMessage = "declare parents: extends Observable";            
+               assertEquals(decParentsPtnMessage,((IProgramElement)aspect.getChildren().get(declareIndex+1)).toLabelString());                 
+               String decParentsTPMessage = "declare parents: extends Observable";     
+               assertEquals(decParentsTPMessage,((IProgramElement)aspect.getChildren().get(declareIndex+2)).toLabelString());
                
                String decSoftMessage = "declare soft: SizeException";
                IProgramElement decSoftNode = model.findElementForSignature(aspect, IProgramElement.Kind.DECLARE_SOFT, "declare soft");
index 407ad100417055cbbbf7ede124cf4cc19bd3c369..64b36527681101dea647a488f3a5b41b072a2d61 100644 (file)
@@ -35,12 +35,13 @@ public class AsmRelationshipsTest extends AjdeTestCase {
                IProgramElement dp = manager.getHierarchy().findElementForLabel(
                                aspect, 
                                IProgramElement.Kind.DECLARE_PARENTS, 
-                               "declare parents: Point");
+                               "declare parents: implements Serializable"/*Point"*/);
                
                assertNotNull(dp);
                List relations = manager.getRelationshipMap().get(dp);
-               
-//             assertTrue(false);
+                               
+               List rels = AsmManager.getDefault().getRelationshipMap().get(dp);
+               assertTrue(rels.size()>0);
                
 //             assertTrue(rel.getTargets().size() > 0);
 //             
index 5d07718e105abd407c3a4d106ac017ecbba52b82..007727ea1b961fb7cdfa2ba25709c7893d44ba21 100644 (file)
@@ -217,7 +217,7 @@ public class BuildCancellingTest extends AjdeTestCase {
                        programmableBPM,
                        false);
        
-//             Should just be A1 on the disk - uncomment this line to verify that!
+//             Should just be A1 on the disk - uncomment this line to verify that! (and uncomment diskContents())
 //             assertTrue("Incorrect disk contents found",diskContents("A1"));
 
                assertTrue("Should have cancelled after first class weave?:"+programmableBPM.numWovenClassMessages,
@@ -258,7 +258,7 @@ public class BuildCancellingTest extends AjdeTestCase {
                        programmableBPM,
                        false);
        
-//             Uncomment this line to verify disk contents
+//             Uncomment this line to verify disk contents(and uncomment diskContents())
 //             assertTrue("Incorrect disk contents found",diskContents("A1 Cl1 A2"));
 
                assertTrue("Should have cancelled after first class weave?:"+programmableBPM.numWovenClassMessages,
@@ -350,43 +350,43 @@ public class BuildCancellingTest extends AjdeTestCase {
 
        }
        
-       private boolean diskContents(String shouldExist) {
-               String[] fullList = new String[] { "A1","A2","A3","A4","Cl1","Cl2","Cl3","HW"};
-               boolean isOK = true;
-               for (int i = 0; i < fullList.length; i++) {
-                       String file = fullList[i];
-                       if (shouldExist.indexOf(file)!=-1) {
-                               // There should be a class file called this
-                               if (!openFile("bin/"+file+".class").exists()) {
-                                       isOK=false; 
-                                       System.out.println("Couldn't find this expected file: "+file+".class");
-                               }
-                       } else {
-                               // There should NOT be a class file called this
-                               if (openFile("bin/"+file+".class").exists()) {
-                                       isOK=false;
-                                       System.out.println("Found this file when not expected: "+file+".class");
-                               }
-                       }
-               }
-               return isOK;
-       }
-       
-       private int wovenClassesFound() {
-               int found = 0;
-               File fA1 = openFile("bin/A1.class");
-               File fA2 = openFile("bin/A2.class");
-               File fA3 = openFile("bin/A3.class");
-               File fA4 = openFile("bin/A4.class");
-               File fHW = openFile("bin/HW.class");
-
-               found+=(fA1.exists()?1:0);
-               found+=(fA2.exists()?1:0);
-               found+=(fA3.exists()?1:0);
-               found+=(fA4.exists()?1:0);
-               found+=(fHW.exists()?1:0);
-               return found;
-       }
+//     private boolean diskContents(String shouldExist) {
+//             String[] fullList = new String[] { "A1","A2","A3","A4","Cl1","Cl2","Cl3","HW"};
+//             boolean isOK = true;
+//             for (int i = 0; i < fullList.length; i++) {
+//                     String file = fullList[i];
+//                     if (shouldExist.indexOf(file)!=-1) {
+//                             // There should be a class file called this
+//                             if (!openFile("bin/"+file+".class").exists()) {
+//                                     isOK=false; 
+//                                     System.out.println("Couldn't find this expected file: "+file+".class");
+//                             }
+//                     } else {
+//                             // There should NOT be a class file called this
+//                             if (openFile("bin/"+file+".class").exists()) {
+//                                     isOK=false;
+//                                     System.out.println("Found this file when not expected: "+file+".class");
+//                             }
+//                     }
+//             }
+//             return isOK;
+//     }
+//     
+//     private int wovenClassesFound() {
+//             int found = 0;
+//             File fA1 = openFile("bin/A1.class");
+//             File fA2 = openFile("bin/A2.class");
+//             File fA3 = openFile("bin/A3.class");
+//             File fA4 = openFile("bin/A4.class");
+//             File fHW = openFile("bin/HW.class");
+//
+//             found+=(fA1.exists()?1:0);
+//             found+=(fA2.exists()?1:0);
+//             found+=(fA3.exists()?1:0);
+//             found+=(fA4.exists()?1:0);
+//             found+=(fHW.exists()?1:0);
+//             return found;
+//     }
        
 
        private boolean checkFor(String what) {
diff --git a/ajde/testsrc/org/aspectj/ajde/ShowWeaveMessagesTestCase.java b/ajde/testsrc/org/aspectj/ajde/ShowWeaveMessagesTestCase.java
new file mode 100644 (file)
index 0000000..8127ad3
--- /dev/null
@@ -0,0 +1,376 @@
+/* *******************************************************************
+ * Copyright (c) 2004 Contributors.
+ * 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 version
+ * ******************************************************************/
+
+package org.aspectj.ajde;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.aspectj.ajde.internal.CompilerAdapter;
+import org.aspectj.bridge.IMessage;
+import org.aspectj.util.FileUtil;
+
+/**
+ * Weaving messages are complicated things.  There are multiple places where weaving
+ * takes place and the places vary depending on whether we are doing a binary weave or
+ * going from source.  All places that output weaving messages are tagged:
+ *  // TAG: WeavingMessage
+ * so you can easily find them!
+ * 
+ * Advice is the simplest to deal with as that is advice weaving is always done in the weaver.
+ * 
+ * Next is intertype declarations.  These are also always done in the weaver but in the case
+ *   of a binary weave we don't know the originating source line for the ITD.
+ * 
+ * Finally, declares.
+ *   Declare Parents: extends       Can only be done when going from source, if attempted by a 
+ *                                  binary weave then an error message (compiler limitation) is
+ *                                  produced.
+ *   Declare Parents: implements    Is (currently!) done at both compile time and weave time.
+ *                                                                     If going from source then the message is produced by the
+ *                                                                 code in the compiler.  if going from binary then the message
+ *                                                                     is produced by the weaver.
+ *   Declare Soft:                  Comes out with 'advice' as a special kind of advice: softener advice
+ * 
+ * 
+ * Q: Where are the messages turned on/off?
+ * A: It is a bit messy.  See BuildArgParser.genBuildConfig().  Basically that method is the first time
+ *    we parse the option set.  Whether weaving messages are on or off is stored in the build config.
+ *    As soon as we have parser the options and determined that weave messages are on, we grab the 
+ *    top level message handler and tell it not to ignore WeaveInfo messages.
+ * 
+ * 
+ * TODO - Other forms of declare?  Do they need messages? e.g. declare precedence * 
+ */
+public class ShowWeaveMessagesTestCase extends AjdeTestCase {
+       
+       static {
+               // Switch this to true for a single iteration if you want to reconstruct the
+               // 'expected weaving messages' files.
+               regenerate = false;
+       }
+       
+       private static boolean regenerate;
+       private CompilerAdapter compilerAdapter;
+       public static final String PROJECT_DIR = "WeaveInfoMessagesTest";
+
+       public static final String binDir = "bin";
+       public static final String expectedResultsDir = "expected";
+                       
+                       
+       public ShowWeaveMessagesTestCase(String arg0) {
+               super(arg0);
+       }
+
+       /*
+        * Ensure the output directory in clean
+        */
+       protected void setUp() throws Exception {
+               super.setUp(PROJECT_DIR);
+               FileUtil.deleteContents(openFile(binDir));
+       }
+       
+       protected void tearDown() throws Exception {
+               super.tearDown();
+               FileUtil.deleteContents(openFile(binDir));
+       }
+
+
+
+
+       /**
+        * Weave all the possible kinds of advice and verify the messages that come out.
+        */
+       public void testWeaveMessagesAdvice() {
+               System.out.println("testWeaveMessagesAdvice: Building with One.lst");
+               compilerAdapter = new CompilerAdapter();
+               compilerAdapter.showInfoMessages(true);
+               compilerAdapter.compile((String) openFile("One.lst").getAbsolutePath(),new BPM(),false);
+               verifyWeavingMessages("advice",true);
+       }
+       
+
+
+
+       /**
+        * Weave field and method ITDs and check the weave messages that come out.
+        */
+       public void testWeaveMessagesITD() {
+               System.out.println("\n\n\n\n\n\ntestWeaveMessagesITD: Building with Two.lst");
+               compilerAdapter = new CompilerAdapter();
+               compilerAdapter.showInfoMessages(true);
+               compilerAdapter.compile((String) openFile("Two.lst").getAbsolutePath(),new BPM(),false);
+               verifyWeavingMessages("itd",true);
+       }
+       
+       
+       /**
+        * Weave "declare parents: implements" and check the weave messages that come out.
+        */
+       public void testWeaveMessagesDeclare() {
+               System.out.println("\n\n\n\n\n\ntestWeaveMessagesDeclare: Building with Three.lst");
+               compilerAdapter = new CompilerAdapter();
+               compilerAdapter.showInfoMessages(true);
+               compilerAdapter.compile((String) openFile("Three.lst").getAbsolutePath(),new BPM(),false);
+               verifyWeavingMessages("declare1",true);         
+       }
+       
+       /**
+        * Weave "declare parents: extends" and check the weave messages that come out.
+        * Can't do equivalent binary test - as can't do extends in binary.
+        */
+       public void testWeaveMessagesDeclareExtends() {
+               System.out.println("\n\n\n\n\n\ntestWeaveMessagesDeclareExtends: Building with Four.lst");
+               compilerAdapter = new CompilerAdapter();
+               compilerAdapter.showInfoMessages(true);
+               compilerAdapter.compile((String) openFile("Four.lst").getAbsolutePath(),new BPM(),false);
+               verifyWeavingMessages("declare.extends",true);          
+       }
+       
+       /**
+        * Weave "declare soft: type: pointcut" and check the weave messages that come out.
+        */
+       public void testWeaveMessagesDeclareSoft() {
+               System.out.println("\n\n\n\n\n\ntestWeaveMessagesDeclareSoft: Building with Five.lst");
+               compilerAdapter = new CompilerAdapter();
+               compilerAdapter.showInfoMessages(true);
+               compilerAdapter.compile((String) openFile("Five.lst").getAbsolutePath(),new BPM(),false);
+               verifyWeavingMessages("declare.soft",true);             
+       }
+       
+       
+       // BINARY WEAVING TESTS
+       
+       /**
+        * Binary weave variant of the advice weaving test above - to check messages are ok for
+        * binary weave.  Unlike the source level weave, in this test we are using an aspect on
+        * the aspectpath - which means it has already had its necessary parts woven - so the list 
+        * of weaving messages we expect is less.
+        */
+       public void testWeaveMessagesBinaryAdvice() {
+               System.out.println("\n\n\n\n\n\ntestWeaveMessagesBinaryAdvice: Simple.jar + AspectAdvice.jar");
+               Set inpath = new HashSet();
+               inpath.add(openFile("Simple.jar"));
+               ideManager.getProjectProperties().setInpath(inpath);
+               Set aspectpath = new HashSet();
+               aspectpath.add(openFile("AspectAdvice.jar"));
+               ideManager.getProjectProperties().setAspectPath(aspectpath);
+               assertTrue("Build failed", doSynchronousBuild("Empty.lst"));
+        List l = ideManager.getCompilationSourceLineTasks();
+        verifyWeavingMessages("advice.binary",true);
+       }
+       
+       public void testWeaveMessagesBinaryITD() {
+               System.out.println("\n\n\n\n\n\ntestWeaveMessagesBinaryITD: Simple.jar + AspectITD.jar");
+               Set inpath = new HashSet();
+               inpath.add(openFile("Simple.jar"));
+               ideManager.getProjectProperties().setInpath(inpath);
+               Set aspectpath = new HashSet();
+               aspectpath.add(openFile("AspectITD.jar"));
+               ideManager.getProjectProperties().setAspectPath(aspectpath);
+               assertTrue("Build failed", doSynchronousBuild("Empty.lst"));
+               List l = ideManager.getCompilationSourceLineTasks();
+               verifyWeavingMessages("itd",false);
+       }
+
+       
+       public void testWeaveMessagesBinaryDeclare() {
+               System.out.println("\n\n\n\n\n\ntestWeaveMessagesBinaryDeclare: Simple.jar + AspectDeclare.jar");
+               Set inpath = new HashSet();
+               inpath.add(openFile("Simple.jar"));
+               ideManager.getProjectProperties().setInpath(inpath);
+               Set aspectpath = new HashSet();
+               aspectpath.add(openFile("AspectDeclare.jar"));
+               ideManager.getProjectProperties().setAspectPath(aspectpath);
+               assertTrue("Build failed", doSynchronousBuild("Empty.lst"));
+               verifyWeavingMessages("declare1",false);        
+       }
+       
+       /**
+        * Weave "declare soft: type: pointcut" and check the weave messages that come out.
+        */
+       public void testWeaveMessagesBinaryDeclareSoft() {
+               System.out.println("\n\n\n\n\n\ntestWeaveMessagesBinaryDeclareSoft: Simple.jar + AspectDeclareSoft.jar");
+               Set inpath = new HashSet();
+               inpath.add(openFile("Simple.jar"));
+               ideManager.getProjectProperties().setInpath(inpath);
+               Set aspectpath = new HashSet();
+               aspectpath.add(openFile("AspectDeclareSoft.jar"));
+               ideManager.getProjectProperties().setAspectPath(aspectpath);
+               assertTrue("Build failed", doSynchronousBuild("Empty.lst"));
+               verifyWeavingMessages("declare.soft",false);    
+       }
+
+
+
+
+       // BINARY WEAVING WHEN WE'VE LOST THE SOURCE POINTERS
+
+       public void testWeaveMessagesBinaryAdviceNoDebugInfo() {
+               System.out.println("\n\n\n\n\n\ntestWeaveMessagesBinaryAdvice: Simple.jar + AspectAdvice.jar");
+               Set inpath = new HashSet();
+               inpath.add(openFile("Simple_nodebug.jar"));
+               ideManager.getProjectProperties().setInpath(inpath);
+               Set aspectpath = new HashSet();
+               aspectpath.add(openFile("AspectAdvice_nodebug.jar"));
+               ideManager.getProjectProperties().setAspectPath(aspectpath);
+               assertTrue("Build failed", doSynchronousBuild("Empty.lst"));
+               List l = ideManager.getCompilationSourceLineTasks();
+               verifyWeavingMessages("advice.binary.nodebug",true);
+       }
+       
+       public void testWeaveMessagesBinaryITDNoDebugInfo() {
+               System.out.println("\n\n\n\n\n\ntestWeaveMessagesBinaryITD: Simple.jar + AspectITD.jar");
+               Set inpath = new HashSet();
+               inpath.add(openFile("Simple_nodebug.jar"));
+               ideManager.getProjectProperties().setInpath(inpath);
+               Set aspectpath = new HashSet();
+               aspectpath.add(openFile("AspectITD_nodebug.jar"));
+               ideManager.getProjectProperties().setAspectPath(aspectpath);
+               assertTrue("Build failed", doSynchronousBuild("Empty.lst"));
+               List l = ideManager.getCompilationSourceLineTasks();
+               verifyWeavingMessages("itd.nodebug",true);
+       }
+       
+       public void testWeaveMessagesBinaryDeclareNoDebugInfo() {
+               System.out.println("\n\n\n\n\n\ntestWeaveMessagesBinaryDeclareNoDebugInfo: Simple.jar + AspectDeclare.jar");
+               Set inpath = new HashSet();
+               inpath.add(openFile("Simple_nodebug.jar"));
+               ideManager.getProjectProperties().setInpath(inpath);
+               Set aspectpath = new HashSet();
+               aspectpath.add(openFile("AspectDeclare_nodebug.jar"));
+               ideManager.getProjectProperties().setAspectPath(aspectpath);
+               assertTrue("Build failed", doSynchronousBuild("Empty.lst"));
+               verifyWeavingMessages("declare1.nodebug",true); 
+       }       
+       
+       /**
+        * Weave "declare soft: type: pointcut" and check the weave messages that come out.
+        */
+       public void testWeaveMessagesBinaryDeclareSoftNoDebugInfo() {
+               System.out.println("\n\n\n\n\n\ntestWeaveMessagesBinaryDeclareSoftNoDebugInfo: Simple.jar + AspectDeclareSoft.jar");
+               Set inpath = new HashSet();
+               inpath.add(openFile("Simple_nodebug.jar"));
+               ideManager.getProjectProperties().setInpath(inpath);
+               Set aspectpath = new HashSet();
+               aspectpath.add(openFile("AspectDeclareSoft_nodebug.jar"));
+               ideManager.getProjectProperties().setAspectPath(aspectpath);
+               assertTrue("Build failed", doSynchronousBuild("Empty.lst"));
+               verifyWeavingMessages("declare.soft.nodebug",true);     
+       }
+
+
+       private class BPM implements BuildProgressMonitor {
+               public void start(String configFile) {}
+
+                               public void setProgressText(String text) {}
+
+                               public void setProgressBarVal(int newVal) {     }
+
+                               public void incrementProgressBarVal() {}
+
+                               public void setProgressBarMax(int maxVal) {     }
+
+                               public int getProgressBarMax() {
+                                       return 0;
+                               }
+
+                               public void finish() {}
+               
+       }
+       
+
+       public void verifyWeavingMessages(String testid,boolean source) {
+               File expectedF = openFile(expectedResultsDir+File.separator+testid+".txt");
+               if (regenerate && source) {
+                       // Create the file
+                       saveWeaveMessages(expectedF);
+               } else {
+                       // Verify the file matches what we have
+                       compareWeaveMessages(expectedF);
+               }
+       }
+       
+       /**
+        * Compare weaving messages with what is in the file
+        */
+       private void compareWeaveMessages(File f) {
+               List fileContents = new ArrayList();
+               BufferedReader fr;
+               try {
+                       // Load the file in
+                       fr = new BufferedReader(new FileReader(f));
+                       String line = null;
+                       while ((line=fr.readLine())!=null) fileContents.add(line);
+                       
+                       // See if the messages match
+                       int msgCount = 0;
+                       List l = ideManager.getCompilationSourceLineTasks();
+                       for (Iterator iter = l.iterator(); iter.hasNext();) {
+                               IMessage msg = ((NullIdeTaskListManager.SourceLineTask) iter.next()).message;
+                               if (msg.getKind().equals(IMessage.WEAVEINFO)) {
+                                       if (!fileContents.contains(msg.getMessage())) {
+                                               fail("Could not find message '"+msg.getMessage()+"' in the expected results\n"+
+                                               stringify(fileContents));
+                                       } else {
+                                               fileContents.remove(msg.getMessage());
+                                       }
+                                       msgCount++;
+                               }
+                       }
+                       assertTrue("Didn't get these expected messages: "+fileContents,fileContents.size()==0);
+                       System.out.println("Successfully verified "+msgCount+" weaving messages");
+               } catch (Exception e) {
+                       fail("Unexpected exception saving weaving messages:"+e);
+               }
+       }
+       
+       private String stringify(List l) {
+               StringBuffer result = new StringBuffer();
+               for (Iterator iter = l.iterator(); iter.hasNext();) {
+                       String str = (String) iter.next();
+                       result.append(str);result.append("\n");
+               }
+               return result.toString();
+       }
+       
+       /**
+        * Store the weaving messages in the specified file.
+        */
+       private void saveWeaveMessages(File f) {
+               System.out.println("Saving weave messages into "+f.getName());
+               FileWriter fw;
+               try {
+                       fw = new FileWriter(f); 
+                       List l = ideManager.getCompilationSourceLineTasks();
+                       for (Iterator iter = l.iterator(); iter.hasNext();) {
+                               IMessage msg = ((NullIdeTaskListManager.SourceLineTask) iter.next()).message;
+                               if (msg.getKind().equals(IMessage.WEAVEINFO)) {
+                                       fw.write(msg.getMessage()+"\n");
+                               }
+                       }
+                       fw.close();
+               } catch (Exception e) {
+                       fail("Unexpected exception saving weaving messages:"+e);
+               }
+       }
+       
+       
+
+}
index 91a166af6149900ae5ab787ea22dbc3497b48ae3..0177bb4c259c5134a86ad7b40399064efe80b68a 100644 (file)
@@ -37,7 +37,25 @@ public class AsmManager {
     protected IHierarchy hierarchy;
     private List structureListeners = new ArrayList();
        private IRelationshipMap mapper;
+       
+
+       public static boolean attemptIncrementalModelRepairs = false;
+//     for debugging ...       
+//     static {
+//             setReporting("c:/model.nfo",true,true,true,true);
+//     }
+
 
+    // For offline debugging, you can now ask for the AsmManager to
+    // dump the model - see the method setReporting()
+       private static boolean dumpModel = false;
+       private static boolean dumpRelationships = false;
+       private static boolean dumpDeltaProcessing = false;
+       private static String  dumpFilename = "";
+       private static boolean reporting = false;
+
+
+       
     protected AsmManager() {
        hierarchy = new AspectJElementHierarchy();
 //     List relationships = new ArrayList();
@@ -144,11 +162,17 @@ public class AsmManager {
     public void writeStructureModel(String configFilePath) {
         try {
             String filePath = genExternFilePath(configFilePath);
-            ObjectOutputStream s = new ObjectOutputStream(new FileOutputStream(filePath));
-            s.writeObject(hierarchy);
+            FileOutputStream fos = new FileOutputStream(filePath);
+            ObjectOutputStream s = new ObjectOutputStream(fos);
+            s.writeObject(hierarchy); // Store the program element tree
+            s.writeObject(mapper); // Store the relationships
             s.flush();
+            fos.flush();
+            fos.close();
+            s.close();
         } catch (Exception e) {
-            // ignore
+            // System.err.println("AsmManager: Unable to write structure model: "+configFilePath+" because of:");
+            // e.printStackTrace();
         }
     }
   
@@ -157,6 +181,7 @@ public class AsmManager {
         * @param       configFilePath          path to an ".lst" file
         */
     public void readStructureModel(String configFilePath) {
+       boolean hierarchyReadOK = false;
         try {
             if (configFilePath == null) {
                hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
@@ -165,9 +190,23 @@ public class AsmManager {
                    FileInputStream in = new FileInputStream(filePath);
                    ObjectInputStream s = new ObjectInputStream(in);
                    hierarchy = (AspectJElementHierarchy)s.readObject();
+                   hierarchyReadOK = true;
+                   mapper = (RelationshipMap)s.readObject();
+                   ((RelationshipMap)mapper).setHierarchy(hierarchy);
             }
+        } catch (FileNotFoundException fnfe) {
+               // That is OK
+                       hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
+               } catch (EOFException eofe) {
+                       // Might be an old format sym file that is missing its relationships
+                       if (!hierarchyReadOK) {
+                               System.err.println("AsmManager: Unable to read structure model: "+configFilePath+" because of:");
+                               eofe.printStackTrace();
+                               hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
+                       }
         } catch (Exception e) {
-               //System.err.println("AJDE Message: could not read structure model: " + e);
+            // System.err.println("AsmManager: Unable to read structure model: "+configFilePath+" because of:");
+            // e.printStackTrace();
             hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
         } finally {
                notifyListeners();      
@@ -298,7 +337,444 @@ public class AsmManager {
                        }
                        return ret;
                }
-       };
+       }
+
+       public static void setReporting(String filename,boolean dModel,boolean dRels,boolean dDeltaProcessing,boolean deletefile) {
+               reporting         = true;
+               dumpModel         = dModel;
+               dumpRelationships = dRels;
+               dumpDeltaProcessing = dDeltaProcessing;
+               if (deletefile) new File(filename).delete();
+               dumpFilename      = filename;
+       }
+       
+       public static boolean isReporting() {
+               return reporting;
+       }
+       
+
+
+       public void reportModelInfo(String reasonForReport) {
+               if (!dumpModel && !dumpRelationships) return;
+               try {
+                       FileWriter fw = new FileWriter(dumpFilename,true);
+                       BufferedWriter bw = new BufferedWriter(fw);
+                       if (dumpModel) {
+                               bw.write("=== MODEL STATUS REPORT ========= "+reasonForReport+"\n");
+                               dumptree(bw,AsmManager.getDefault().getHierarchy().getRoot(),0);
+                               
+                               bw.write("=== END OF MODEL REPORT =========\n");
+                       }
+                       if (dumpRelationships) {
+                               bw.write("=== RELATIONSHIPS REPORT ========= "+reasonForReport+"\n");
+                               dumprels(bw);
+                               bw.write("=== END OF RELATIONSHIPS REPORT ==\n");
+                       }
+                       Properties p = ModelInfo.summarizeModel().getProperties();
+                       Enumeration pkeyenum = p.keys();
+                       bw.write("=== Properties of the model and relationships map =====\n");
+                       while (pkeyenum.hasMoreElements()) {
+                               String pkey = (String)pkeyenum.nextElement();
+                               bw.write(pkey+"="+p.getProperty(pkey)+"\n");
+                       }
+                       bw.flush();
+                       fw.close();
+               } catch (IOException e) {
+                       System.err.println("InternalError: Unable to report model information:");
+                       e.printStackTrace();
+               }
+       }
+       
+
+       private void dumptree(Writer w,IProgramElement node,int indent) throws IOException {
+               for (int i =0 ;i<indent;i++) w.write(" ");
+               w.write(node+"  ["+(node==null?"null":node.getKind().toString())+"]\n");
+               if (node!=null) 
+               for (Iterator i = node.getChildren().iterator();i.hasNext();) {
+                       dumptree(w,(IProgramElement)i.next(),indent+2);
+               }
+       }
+       
+       private void dumprels(Writer w) throws IOException {
+               IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap();
+               int ctr = 1;
+               Set entries = irm.getEntries();
+               for (Iterator iter = entries.iterator(); iter.hasNext();) {
+                       String hid = (String) iter.next();
+                       List rels =  irm.get(hid);
+                       for (Iterator iterator = rels.iterator(); iterator.hasNext();) {
+                               IRelationship ir = (IRelationship) iterator.next();
+                               List targets = ir.getTargets();
+                               for (Iterator iterator2 = targets.iterator();
+                                       iterator2.hasNext();
+                                       ) {
+                                       String thid = (String) iterator2.next();
+                                       w.write("Hid:"+(ctr++)+":(targets="+targets.size()+") "+hid+" ("+ir.getName()+") "+thid+"\n");
+                               }
+                       }
+               }
+       }
+       
+       //===================== DELTA PROCESSING CODE ============== start ==========//
+       
+       // This code is *SLOW* but it isnt worth fixing until we address the
+       // bugs in binary weaving.
+       public void fixupStructureModel(Writer fw,List filesToBeCompiled,Set files_added,Set files_deleted) throws IOException {
+               // Three kinds of things to worry about:
+               // 1. New files have been added since the last compile
+               // 2. Files have been deleted since the last compile
+               // 3. Files have 'changed' since the last compile (really just those in config.getFiles())
+               
+               //  List files = config.getFiles();
+               IHierarchy model = AsmManager.getDefault().getHierarchy();
+               
+               boolean modelModified = false;
+               // Files to delete are: those to be compiled + those that have been deleted
+               
+               Set filesToRemoveFromStructureModel = new HashSet(filesToBeCompiled);
+               filesToRemoveFromStructureModel.addAll(files_deleted);
+               
+               for (Iterator iter = filesToRemoveFromStructureModel.iterator(); iter.hasNext();) {
+                       File fileForCompilation = (File) iter.next();
+                       String correctedPath = AsmManager.getDefault().getCanonicalFilePath(fileForCompilation);
+                       IProgramElement progElem = (IProgramElement)model.findInFileMap(correctedPath);
+                       if (progElem!=null) {
+                               // Found it, let's remove it
+                               if (dumpDeltaProcessing) {
+                                       fw.write("Deleting "+progElem+" node for file "+fileForCompilation+"\n");
+                               }
+                               removeNode(progElem);
+                               verifyAssumption(
+                                       model.removeFromFileMap(correctedPath.toString()),
+                                       "Whilst repairing model, couldn't remove entry for file: "+correctedPath.toString()+" from the filemap");
+                               modelModified = true;
+                       } 
+               }
+               if (modelModified) {
+                       model.flushTypeMap();
+                       model.flushHandleMap();
+               }
+       }
+       
+       public void processDelta(List filesToBeCompiled,Set files_added,Set files_deleted) {
+
+               try {
+                       Writer fw = null;
+                       
+                       // Are we recording this ?
+                       if (dumpDeltaProcessing) {
+                               FileWriter filew = new FileWriter(dumpFilename,true);
+                               fw = new BufferedWriter(filew);
+                               fw.write("=== Processing delta changes for the model ===\n");
+                               fw.write("Files for compilation:#"+filesToBeCompiled.size()+":"+filesToBeCompiled+"\n");
+                               fw.write("Files added          :#"+files_added.size()+":"+files_added+"\n");
+                               fw.write("Files deleted        :#"+files_deleted.size()+":"+files_deleted+"\n");
+                       }
+                       
+                       long stime = System.currentTimeMillis();
+                       
+                       fixupStructureModel(fw,filesToBeCompiled,files_added,files_deleted);
+                       
+                       long etime1 = System.currentTimeMillis(); // etime1-stime = time to fix up the model
+               
+                       IHierarchy model = AsmManager.getDefault().getHierarchy();
+                       
+                       // Some of this code relies on the fact that relationships are always in pairs, so you know
+                       // if you are the target of a relationship because you are also the source of a relationship
+                       // This seems a valid assumption for now...
+               
+                       //TODO Speed this code up by making this assumption:
+                       // the only piece of the handle that is interesting is the file name.  We are working at file granularity, if the
+                       // file does not exist (i.e. its not in the filemap) then any handle inside that file cannot exist.
+                       if (dumpDeltaProcessing) fw.write("Repairing relationships map:\n");
+               
+                       // Now sort out the relationships map
+                       IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap();
+                       Set sourcesToRemove = new HashSet(); 
+                       Set nonExistingHandles = new HashSet(); // Cache of handles that we *know* are invalid
+                       int srchandlecounter = 0;
+                       int tgthandlecounter = 0;
+                       
+                       // Iterate over the source handles in the relationships map
+                       Set keyset = irm.getEntries(); // These are source handles
+                       for (Iterator keyiter = keyset.iterator(); keyiter.hasNext();) {
+                               String hid = (String) keyiter.next();
+                               srchandlecounter++;
+                               
+                               // Do we already know this handle points to nowhere?
+                               if (nonExistingHandles.contains(hid)) {
+                                       sourcesToRemove.add(hid);
+                               } else {
+                                       // We better check if it actually exists
+                                       IProgramElement existingElement = model.getElement(hid);
+                                       if (dumpDeltaProcessing) fw.write("Looking for handle ["+hid+"] in model, found: "+existingElement+"\n");
+                         
+                                       // Did we find it?
+                                       if (existingElement == null) {
+                                               // No, so delete this relationship
+                                               sourcesToRemove.add(hid);
+                                               nonExistingHandles.add(hid); // Speed up a bit you swine
+                                       } else {
+                                               // Ok, so the source is valid, what about the targets?
+                                               List relationships = irm.get(hid);
+                                               List relationshipsToRemove = new ArrayList();
+                                               // Iterate through the relationships against this source handle
+                                               for (Iterator reliter = relationships.iterator();reliter.hasNext();) {
+                                                       IRelationship rel = (IRelationship) reliter.next();
+                                                       List targets = rel.getTargets();
+                                                       List targetsToRemove = new ArrayList();
+                                       
+                                                       // Iterate through the targets for this relationship
+                                                       for (Iterator targetIter = targets.iterator();targetIter.hasNext();) {
+                                                               String targethid = (String) targetIter.next();
+                                                               tgthandlecounter++;
+                                                               // Do we already know it doesn't exist?
+                                                               if (nonExistingHandles.contains(targethid)) {
+                                                                       if (dumpDeltaProcessing) fw.write("Target handle ["+targethid+"] for srchid["+hid+"]rel["+rel.getName()+"] does not exist\n");
+                                                                       targetsToRemove.add(targethid);
+                                                               } else {
+                                                                       // We better check
+                                                                       IProgramElement existingTarget = model.getElement(targethid);
+                                                                       if (existingTarget == null) {
+                                                                               if (dumpDeltaProcessing) fw.write("Target handle ["+targethid+"] for srchid["+hid+"]rel["+rel.getName()+"] does not exist\n");
+                                                                               targetsToRemove.add(targethid);
+                                                                               nonExistingHandles.add(targethid);
+                                                                       }
+                                                               }
+                                                       }
+                                                       
+                                                       // Do we have some targets that need removing?
+                                                       if (targetsToRemove.size()!=0) {
+                                                               // Are we removing *all* of the targets for this relationship (i.e. removing the relationship)
+                                                               if (targetsToRemove.size()==targets.size()) {
+                                                                       if (dumpDeltaProcessing) fw.write("No targets remain for srchid["+hid+"] rel["+rel.getName()+"]: removing it\n");
+                                                                       relationshipsToRemove.add(rel);                                                 
+                                                               } else {
+                                                                       // Remove all the targets that are no longer valid
+                                                                       for (Iterator targsIter = targetsToRemove.iterator();targsIter.hasNext();) {
+                                                                               String togo = (String) targsIter.next();
+                                                                               targets.remove(togo);
+                                                                       }
+                                                                       // Should have already been caught above, but lets double check ...
+                                                                       if (targets.size()==0) {
+                                                                               if (dumpDeltaProcessing) fw.write("No targets remain for srchid["+hid+"] rel["+rel.getName()+"]: removing it\n");
+                                                                               relationshipsToRemove.add(rel); // TODO Should only remove this relationship for the srchid?
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                               // Now, were any relationships emptied during that processing and so need removing for this source handle
+                                               if (relationshipsToRemove.size()>0) {
+                                                       // Are we removing *all* of the relationships for this source handle?
+                                                       if (relationshipsToRemove.size() == relationships.size()) { 
+                                                               // We know they are all going to go, so just delete the source handle.
+                                                               sourcesToRemove.add(hid);
+                                                       } else {
+                                                               for (int i = 0 ;i<relationshipsToRemove.size();i++) {
+                                                                       IRelationship irel = (IRelationship)relationshipsToRemove.get(i);
+                                                                       verifyAssumption(irm.remove(hid,irel),"Failed to remove relationship "+irel.getName()+" for shid "+hid);
+                                                               }
+                                                               List rels = irm.get(hid);
+                                                               if (rels==null || rels.size()==0) sourcesToRemove.add(hid);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       // Remove sources that have no valid relationships any more
+                       for (Iterator srciter = sourcesToRemove.iterator(); srciter.hasNext();) {
+                               String hid = (String) srciter.next();
+                               irm.removeAll(hid);
+                               IProgramElement ipe = model.getElement(hid);
+                               if (ipe!=null) {
+                                       // If the relationship was hanging off a 'code' node, delete it.
+                                       if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
+                                               removeSingleNode(ipe);
+                                       } 
+                               }
+                       }
+                       long etime2 = System.currentTimeMillis(); // etime2-stime = time to repair the relationship map
+                       if (dumpDeltaProcessing) {
+                               fw.write("===== Delta Processing timing ==========\n");
+                               fw.write("Hierarchy="+(etime1-stime)+"ms   Relationshipmap="+(etime2-etime1)+"ms\n");
+                               fw.write("===== Traversal ========================\n");
+                               fw.write("Source handles processed="+srchandlecounter+"\n");
+                               fw.write("Target handles processed="+tgthandlecounter+"\n");
+                               fw.write("========================================\n");
+                               fw.flush();fw.close();
+                       }
+                       reportModelInfo("After delta processing");
+               } catch (IOException e) {
+                       e.printStackTrace();
+               }
+
+       }
+    
+       /**
+        * Removes a specified program element from the structure model.
+        * We go to the parent of the program element, ask for all its children
+        * and remove the node we want to delete from the list of children.
+        */
+       private void removeSingleNode(IProgramElement progElem) {
+               verifyAssumption(progElem!=null);
+               boolean deleteOK = false;
+               IProgramElement parent = progElem.getParent();
+               List kids = parent.getChildren();
+               for (int i =0 ;i<kids.size();i++) {
+                 if (kids.get(i).equals(progElem)) {
+                         kids.remove(i); 
+                         deleteOK=true;
+                         break;
+                 }
+               }
+               verifyAssumption(deleteOK);
+       }
+       
+       
+       /**
+        * Removes a specified program element from the structure model.
+        * Two processing stages:
+        * <p>First: We go to the parent of the program element, ask for all its children
+        *    and remove the node we want to delete from the list of children.
+        * <p>Second:We check if that parent has any other children.  If it has no other
+        *    children and it is either a CODE node or a PACKAGE node, we delete it too.
+        */
+       private void removeNode(IProgramElement progElem) {
+               
+               StringBuffer flightrecorder = new StringBuffer();
+               try {
+                       flightrecorder.append("In removeNode, about to chuck away: "+progElem+"\n");
+               
+                       verifyAssumption(progElem!=null);
+                       boolean deleteOK = false;
+                       IProgramElement parent = progElem.getParent();
+                       flightrecorder.append("Parent of it is "+parent+"\n");
+                       List kids = parent.getChildren();
+                       flightrecorder.append("Which has "+kids.size()+" kids\n");
+                       for (int i =0 ;i<kids.size();i++) {
+                               flightrecorder.append("Comparing with "+kids.get(i)+"\n");
+                               if (kids.get(i).equals(progElem)) {
+                                       kids.remove(i); 
+                                       flightrecorder.append("Removing it\n");
+                                       deleteOK=true;
+                                       break;
+                               }
+                       }
+                       verifyAssumption(deleteOK,flightrecorder.toString());
+                       // Are there any kids left for this node?
+                       if (parent.getChildren().size()==0  && parent.getParent()!=null && 
+                               (parent.getKind().equals(IProgramElement.Kind.CODE) ||
+                               parent.getKind().equals(IProgramElement.Kind.PACKAGE))) {
+                               // This node is on its own, we should trim it too *as long as its not a structural node* which we currently check by making sure its a code node
+                               // We should trim if it
+                               // System.err.println("Deleting parent:"+parent);
+                               removeNode(parent);
+                       }
+               } catch (NullPointerException npe ){
+                       // Occurred when commenting out other 2 ras classes in wsif?? reproducable?
+                       System.err.println(flightrecorder.toString());
+                       npe.printStackTrace();
+               }
+       }
+       
+       
+       public static void verifyAssumption(boolean b,String info) {
+               if (!b) {
+                       System.err.println("=========== ASSERTION IS NOT TRUE =========v");
+                       System.err.println(info);
+                       Thread.dumpStack();
+                       System.err.println("=========== ASSERTION IS NOT TRUE =========^");             
+                       throw new RuntimeException("Assertion is false");
+               } 
+       }
+       
+       public static void verifyAssumption(boolean b) {
+               if (!b) {
+                       Thread.dumpStack();
+                       throw new RuntimeException("Assertion is false");
+               } 
+       }
+       
+
+       //===================== DELTA PROCESSING CODE ==============  end  ==========//
+       
+       /**
+        * A ModelInfo object captures basic information about the structure model.
+        * It is used for testing and producing debug info.
+        */
+       public static class ModelInfo {
+               private Hashtable nodeTypeCount = new Hashtable();
+               private Properties extraProperties = new Properties();
+               
+               private ModelInfo(IHierarchy hierarchy,IRelationshipMap relationshipMap) {
+                 IProgramElement ipe = hierarchy.getRoot();
+                 walkModel(ipe);
+                 recordStat("FileMapSize",
+                       new Integer(hierarchy.getFileMapEntrySet().size()).toString());
+                 recordStat("RelationshipMapSize",
+                       new Integer(relationshipMap.getEntries().size()).toString());   
+               }
+               
+               private void walkModel(IProgramElement ipe) {
+                       countNode(ipe);
+                       List kids = ipe.getChildren();
+                       for (Iterator iter = kids.iterator(); iter.hasNext();) {
+                               IProgramElement nextElement = (IProgramElement) iter.next();
+                               walkModel(nextElement);
+                       }
+               }
+               
+               private void countNode(IProgramElement ipe) {
+                       String node = ipe.getKind().toString();
+                       Integer ctr = (Integer)nodeTypeCount.get(node);
+                       if (ctr==null) {
+                               nodeTypeCount.put(node,new Integer(1));
+                       } else {
+                               ctr = new Integer(ctr.intValue()+1);
+                               nodeTypeCount.put(node,ctr);
+                       }
+               }
+               
+               public String toString() {
+                       StringBuffer sb = new StringBuffer();
+                       sb.append("Model node summary:\n");
+                       Enumeration nodeKeys = nodeTypeCount.keys();
+                       while (nodeKeys.hasMoreElements()) {
+                               String key = (String)nodeKeys.nextElement();
+                               Integer ct = (Integer)nodeTypeCount.get(key);
+                               sb.append(key+"="+ct+"\n");
+                       }
+                       sb.append("Model stats:\n");
+                       Enumeration ks = extraProperties.keys();
+                       while (ks.hasMoreElements()) {
+                               String k = (String)ks.nextElement();
+                               String v = extraProperties.getProperty(k);
+                               sb.append(k+"="+v+"\n");
+                       }
+                       return sb.toString();
+               }
+               
+               public Properties getProperties() {
+                       Properties p = new Properties();
+                       Enumeration nodeKeys = nodeTypeCount.keys();
+                       while (nodeKeys.hasMoreElements()) {
+                               String key = (String)nodeKeys.nextElement();
+                               Integer ct = (Integer)nodeTypeCount.get(key);
+                               p.setProperty(key,ct.toString());
+                       }
+                       p.putAll(extraProperties);
+                       return p;
+               }
+
+               public void recordStat(String string, String string2) {
+                       extraProperties.setProperty(string,string2);
+               }
+               
+               public static ModelInfo summarizeModel() {
+                       return new ModelInfo(AsmManager.getDefault().getHierarchy(),
+                                                                AsmManager.getDefault().getRelationshipMap());
+               }
+       }
        
 }
 
index 793b014207ac72ed285eff06f7fdd088c73811c5..95b00996b1876a0395c46b106bc52a3a0ac7f612 100644 (file)
@@ -31,6 +31,7 @@ public interface IHierarchy extends Serializable {
        public IProgramElement getRoot();
        public void setRoot(IProgramElement root);
        public void addToFileMap(Object key, Object value);
+       public boolean removeFromFileMap(Object key);
        public void setFileMap(HashMap fileMap);
        public Object findInFileMap(Object key);
        public Set getFileMapEntrySet();
@@ -94,4 +95,8 @@ public interface IHierarchy extends Serializable {
        public String getConfigFile();
        
        public void setConfigFile(String configFile);
+
+       public void flushTypeMap();
+
+       public void flushHandleMap();
 }
\ No newline at end of file
index 83374889a70b8a88300582e8b8bbc917dea1f8c2..476b6aaa000b52e56039086353a3bb560162f8e5 100644 (file)
@@ -28,6 +28,23 @@ public interface IProgramElement extends Serializable {
 
        public void setChildren(List children); 
        public void addChild(IProgramElement child);
+       
+       // Extra stuff
+       // Could be just a string but may prove more useful as an object in the long run ...
+       public static class ExtraInformation implements Serializable {
+               private String extraInfo;
+               public ExtraInformation() { extraInfo = "";}
+       
+               public void   setExtraAdviceInformation(String string) {extraInfo = string;}
+               public String getExtraAdviceInformation()              {return extraInfo;}
+               
+               public String toString() {
+                       return "ExtraInformation: ["+extraInfo+"]";
+               }
+       }
+       
+       public void setExtraInfo(ExtraInformation info);
+       public ExtraInformation getExtraInfo();
 
        public IProgramElement getParent();
        public void setParent(IProgramElement parent);
index 18a11da0e7bed56a3eaa628c060719e5cc6ecb8b..53b1182620b92c5156a7e9997606768b8fe29c7d 100644 (file)
@@ -27,17 +27,33 @@ public interface IRelationship extends Serializable {
        
        public String getSourceHandle();
        
+       public boolean addTarget(String handle);
+       
        public Kind getKind();
+       
+       public boolean hasRuntimeTest();
                
        /**
         * Uses "typesafe enum" pattern.
         */
        public static class Kind implements Serializable {
                
-               public static final Kind ADVICE = new Kind("advice");
-               public static final Kind DECLARE = new Kind("declare");
-               public static final Kind DECLARE_INTER_TYPE = new Kind("inter-type declaration");
-               public static final Kind[] ALL = { ADVICE, DECLARE, DECLARE_INTER_TYPE };
+               public static final Kind DECLARE_WARNING       = new Kind("declare warning");
+               public static final Kind DECLARE_ERROR         = new Kind("declare error");
+               public static final Kind ADVICE_AROUND         = new Kind("around advice");
+               public static final Kind ADVICE_AFTERRETURNING = new Kind("after returning advice");
+               public static final Kind ADVICE_AFTERTHROWING  = new Kind("after throwing advice");
+               public static final Kind ADVICE_AFTER          = new Kind("after advice");
+               public static final Kind ADVICE_BEFORE         = new Kind("before advice");
+               public static final Kind ADVICE                = new Kind("advice");
+               public static final Kind DECLARE               = new Kind("declare");
+               public static final Kind DECLARE_INTER_TYPE    = new Kind("inter-type declaration");
+               
+               public static final Kind[] ALL = { 
+                       DECLARE_WARNING, DECLARE_ERROR,
+                       ADVICE_AROUND,ADVICE_AFTERRETURNING,ADVICE_AFTERTHROWING,ADVICE_AFTER,ADVICE_BEFORE,
+                       ADVICE, DECLARE, DECLARE_INTER_TYPE };
+                       
                private final String name;
                
                private Kind(String name) {
index 7eb31335fd7eab16b81d75d71ef58a7a8fc0b394..ff88efbc5964a48d4aa50fd25086835c7be23658 100644 (file)
@@ -14,6 +14,7 @@ package org.aspectj.asm;
 
 import java.io.Serializable;
 import java.util.List;
+import java.util.Set;
 
 //import org.aspectj.asm.IRelationship.Kind;
 
@@ -50,21 +51,33 @@ public interface IRelationshipMap extends Serializable {
         * 
         * @return      null if the relationship is not found.
         */
-       public IRelationship get(IProgramElement source, IRelationship.Kind kind, String relationshipName);
+       public IRelationship get(IProgramElement source, IRelationship.Kind kind, 
+                                String relationshipName,boolean runtimeTest,
+                                boolean createIfMissing);
 
+       /**
+        * Return a relationship matching the kind and name for the given element.  
+        * 
+        * @return      null if the relationship is not found.
+        */
+    public IRelationship get(IProgramElement source, IRelationship.Kind kind,
+      String relationshipName);
+      
        /**
         * Return a relationship matching the kind and name for the given element.
         * Creates the relationship if not found.
         * 
         * @return      null if the relationship is not found.
         */
-       public IRelationship get(String source, IRelationship.Kind kind, String relationshipName);
+       public IRelationship get(String source, IRelationship.Kind kind,
+                                String relationshipName, boolean runtimeTest,
+                                boolean createIfMissing);
        
        public void put(IProgramElement source, IRelationship relationship);
 
        public void put(String handle, IRelationship relationship);
        
-       public void remove(String handle, IRelationship relationship);
+       public boolean remove(String handle, IRelationship relationship);
        
        public void removeAll(String source);
        
@@ -72,5 +85,7 @@ public interface IRelationshipMap extends Serializable {
         * Clear all of the relationships in the map.
         */
        public void clear();
+       
+       public Set getEntries();
  
 }
index 0a36642ab96b7b7792495323ac925fecc3a99f63..da1b09e3809305c956b27eb5061d947860fbb780 100644 (file)
@@ -8,6 +8,7 @@
  *  
  * Contributors: 
  *     Mik Kersten     initial implementation 
+ *     Andy Clement    Extensions for better IDE representation
  * ******************************************************************/
 
 
@@ -32,7 +33,19 @@ public class AspectJElementHierarchy implements IHierarchy {
     private Map typeMap = null;
     
        public IProgramElement getElement(String handle) {
-               throw new RuntimeException("unimplemented");
+               IProgramElement cachedEntry = (IProgramElement)handleMap.get(handle);
+               if (cachedEntry!=null) return cachedEntry;
+               
+               StringTokenizer st = new StringTokenizer(handle, ProgramElement.ID_DELIM);
+               String file = st.nextToken();
+               int line = new Integer(st.nextToken()).intValue();
+               // int col = new Integer(st.nextToken()).intValue(); TODO: use column number when available
+               String canonicalSFP = AsmManager.getDefault().getCanonicalFilePath(new File(file));
+               IProgramElement ret = findNodeForSourceLineHelper(root,canonicalSFP, line);
+               if (ret!=null) {
+                       handleMap.put(handle,ret);
+               }
+               return ret;
        }
 
     public IProgramElement getRoot() {
@@ -48,6 +61,10 @@ public class AspectJElementHierarchy implements IHierarchy {
        public void addToFileMap( Object key, Object value ){
                fileMap.put( key, value );
        }
+       
+       public boolean removeFromFileMap(Object key) {
+               return (fileMap.remove(key)!=null);
+       }
 
        public void setFileMap(HashMap fileMap) {
                  this.fileMap = fileMap;
@@ -336,5 +353,14 @@ public class AspectJElementHierarchy implements IHierarchy {
        protected void cache(String handle, ProgramElement pe) {
                handleMap.put(handle,pe);
        }
+
+       public void flushTypeMap() {
+               typeMap.clear();
+               
+       }
+
+       public void flushHandleMap() {
+               handleMap.clear();
+       }
 }
 
index 3cff3287dc1d70435c1d9f1a453377f9c309dc75..913a1cebceebd5a30fc81a6df0f97f7064e2eb6a 100644 (file)
@@ -8,16 +8,22 @@
  *  
  * Contributors: 
  *     Mik Kersten     initial implementation 
+ *     Andy Clement    Extensions for better IDE representation
  * ******************************************************************/
 
 
 package org.aspectj.asm.internal;
 
-import java.io.*;
-import java.util.*;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 
-import org.aspectj.asm.*;
-import org.aspectj.bridge.*;
+import org.aspectj.asm.AsmManager;
+import org.aspectj.asm.HierarchyWalker;
+import org.aspectj.asm.IProgramElement;
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
 
 
 /**
@@ -55,6 +61,8 @@ public class ProgramElement implements IProgramElement {
        private List parameterTypes = null;
        
        private String details = null;
+       
+       private ExtraInformation info;
     
        /**
         * Used during de-externalization.
@@ -126,6 +134,10 @@ public class ProgramElement implements IProgramElement {
        public Accessibility getAccessibility() {
                return accessibility;
        }
+       
+       public void setAccessibility(Accessibility a) {
+               accessibility=a;
+       }
 
        public String getDeclaringType() {
                return declaringType;
@@ -388,6 +400,9 @@ public class ProgramElement implements IProgramElement {
                return sb.toString();
        }
 
+       
+       public static boolean shortITDNames = true;
+       
        /**
         * TODO: move the "parent != null"==>injar heuristic to more explicit 
         */
@@ -396,13 +411,20 @@ public class ProgramElement implements IProgramElement {
                if (kind == Kind.CODE || kind == Kind.INITIALIZER) {
                        label = parent.getParent().getName() + ": ";
                } else if (kind.isInterTypeMember()) {
-                       int dotIndex = name.indexOf('.');  
-                       if (dotIndex != -1) {
-                               return parent.getName() + ": " + toLabelString().substring(dotIndex+1);
+                       if (shortITDNames) {
+                               // if (name.indexOf('.')!=-1) return toLabelString().substring(name.indexOf('.')+1);
+                               label="";
                        } else {
+                         int dotIndex = name.indexOf('.');  
+                         if (dotIndex != -1) {
+                               return parent.getName() + ": " + toLabelString().substring(dotIndex+1);
+                         } else {
                                label = parent.getName() + '.'; 
+                         }
                        }
-               } else if (kind == Kind.CLASS || kind == Kind.ASPECT) {
+               } else if (kind == Kind.CLASS || kind == Kind.ASPECT || kind == Kind.INTERFACE) {
+                       label = "";
+               } else if (kind.equals(Kind.DECLARE_PARENTS)) {
                        label = "";
                } else { 
                        if (parent != null) {
@@ -487,5 +509,15 @@ public class ProgramElement implements IProgramElement {
                        hierarchy.cache(handle,this);
                }
        }
+
+       public void setExtraInfo(ExtraInformation info) {
+               this.info = info;
+               
+       }
+
+       public ExtraInformation getExtraInfo() {
+               return info;
+       }
+
 }
 
index 68ee50e3f70246b0daf55da3456f26afd5b40612..c47fb159ee5259290d7754f18331ec7dfd330bc3 100644 (file)
@@ -8,6 +8,7 @@
  *  
  * Contributors: 
  *     Mik Kersten     initial implementation 
+ *     Andy Clement    Extensions for better IDE representation
  * ******************************************************************/
 
 
@@ -15,7 +16,6 @@ package org.aspectj.asm.internal;
 
 import java.util.List;
 
-//import org.aspectj.asm.*;
 import org.aspectj.asm.IRelationship;
 //import org.aspectj.asm.IRelationship.Kind;
 
@@ -29,17 +29,20 @@ public class Relationship implements IRelationship {
        private Kind kind;
        private String sourceHandle;
        private List targets;
+       private boolean hasRuntimeTest;
        
        public Relationship(
                String name, 
                Kind kind,
                String sourceHandle,
-               List targets) {
+               List targets,
+               boolean runtimeTest) {
                        
                this.name = name;
                this.kind = kind;
                this.sourceHandle = sourceHandle;
                this.targets = targets;
+               this.hasRuntimeTest = runtimeTest;
        }       
        
        public String getName() {
@@ -61,5 +64,15 @@ public class Relationship implements IRelationship {
        public List getTargets() {
                return targets;
        }
+       
+       public boolean addTarget(String handle) {
+               if (targets.contains(handle)) return false;
+               targets.add(handle);
+               return true;
+       }
+       
+       public boolean hasRuntimeTest() {
+               return hasRuntimeTest;
+       }
 
 }
index ce05fd5c68296cd19c72497f24a59c4b9447783f..b70887af6d8375f406b46ff6a8746ac16095cfdf 100644 (file)
@@ -15,6 +15,7 @@ package org.aspectj.asm.internal;
 import java.util.*;
 
 import org.aspectj.asm.*;
+import org.aspectj.asm.IRelationship.Kind;
 
 /**
  * TODO: add a remove, and a clear all
@@ -24,12 +25,20 @@ import org.aspectj.asm.*;
  */
 public class RelationshipMap extends HashMap implements IRelationshipMap {
        
-       private IHierarchy hierarchy;
+       // As this gets serialized, make the hierarchy transient and
+       // settable
+       private transient IHierarchy hierarchy;
+       
+       public RelationshipMap() { }
        
        public RelationshipMap(IHierarchy hierarchy) {
                this.hierarchy = hierarchy;
        }
 
+       public void setHierarchy(IHierarchy hierarchy) {
+               this.hierarchy = hierarchy;
+       }
+       
        public List get(String handle) {
                List relationships = (List)super.get(handle);
                if (relationships == null) {
@@ -43,48 +52,67 @@ public class RelationshipMap extends HashMap implements IRelationshipMap {
                return get(source.getHandleIdentifier());
        }
 
-       public IRelationship get(String source, IRelationship.Kind kind, String relationshipName) {
+       public IRelationship get(String source, IRelationship.Kind kind, 
+                                String relationshipName,boolean runtimeTest,boolean createIfMissing) {
                List relationships = get(source);
                if (relationships == null) {
+                       if (!createIfMissing) return null;
                        relationships = new ArrayList();
-                       IRelationship rel = new Relationship(relationshipName, kind, source, new ArrayList());
+                       IRelationship rel = new Relationship(relationshipName, kind, source, new ArrayList(),runtimeTest);
                        relationships.add(rel);
                        super.put(source, relationships);
                        return rel;
                } else {
                        for (Iterator it = relationships.iterator(); it.hasNext(); ) {
                                IRelationship curr = (IRelationship)it.next();
-                               if (curr.getKind() == kind && curr.getName().equals(relationshipName)) {
+                               if (curr.getKind() == kind && 
+                                   curr.getName().equals(relationshipName) &&
+                                   curr.hasRuntimeTest() == runtimeTest) {
                                        return curr;
                                }
                        }
+                       if (createIfMissing) {
+                               // At this point we did find some relationships for 'source' but not one that looks like what we are
+                               // after (either the kind or the name or the dynamictests setting don't match)
+                               IRelationship rel = new Relationship(relationshipName, kind, source, new ArrayList(),runtimeTest);
+                               relationships.add(rel);
+                               return rel;
+                       }
                }
                return null;
        }
 
-       public IRelationship get(IProgramElement source, IRelationship.Kind kind, String relationshipName) {
-               return get(source.getHandleIdentifier(), kind, relationshipName);
+       public IRelationship get(IProgramElement source, IRelationship.Kind kind, String relationshipName, boolean runtimeTest,boolean createIfMissing) {
+               return get(source.getHandleIdentifier(), kind, relationshipName,runtimeTest,createIfMissing);
        }
        
-       public void remove(String source, IRelationship relationship) {
+       public IRelationship get(IProgramElement source, Kind kind, String relationshipName) {
+               return get(source,kind,relationshipName,false,true);
+       }
+       
+       public boolean remove(String source, IRelationship relationship) {
                List list = (List)super.get(source);
                if (list != null) {
-                       boolean matched = false;
-                       for (Iterator it = list.iterator(); it.hasNext(); ) {
-                               IRelationship curr = (IRelationship)it.next();
-                               if (curr.getName().equals(relationship.getName())) {
-                                       curr.getTargets().addAll(relationship.getTargets());
-                                       matched = true;
-                               }
-                       }
-                       if (!matched) list.remove(relationship);
+                       return list.remove(relationship);
+//                     boolean matched = false;
+//                     for (Iterator it = list.iterator(); it.hasNext(); ) {
+//                             IRelationship curr = (IRelationship)it.next();
+//                             if (curr.getName().equals(relationship.getName())) {
+//                                     curr.getTargets().addAll(relationship.getTargets());
+//                                     matched = true;
+//                             }
+//                     }
+//                     if (!matched) list.remove(relationship);
                }               
+               return false;
        }
 
        public void removeAll(String source) {
                super.remove(source);   
        }
        
+       public Object put(Object o, Object p) {throw new RuntimeException("Fuck off!");
+       }
        public void put(String source, IRelationship relationship) {
                System.err.println(">> for: " + source + ", put::" + relationship);
                
@@ -103,7 +131,11 @@ public class RelationshipMap extends HashMap implements IRelationshipMap {
                                        matched = true;
                                }
                        }
-                       if (matched) list.add(relationship);
+                       if (matched) {
+                               // bug?
+                               System.err.println("matched = true");
+                       }
+                       if (matched) list.add(relationship); // Is this a bug, will it give us double entries?
                }
        }
 
@@ -115,4 +147,9 @@ public class RelationshipMap extends HashMap implements IRelationshipMap {
                super.clear();
        }
 
+       public Set getEntries() {
+               return keySet();
+       }
+
+
 }
index 2bafc7d7a5b1158dc97f6e0fae500cf8cff98273..fcb8070166f681b31f9a733475b8f92eade3d8d1 100644 (file)
@@ -27,6 +27,7 @@ public interface IMessage {
        public static final IMessage[] RA_IMessage = new IMessage[0];
 
        // int values must sync with KINDS order below
+       public static final Kind WEAVEINFO = new Kind("weaveinfo",5);
        public static final Kind INFO = new Kind("info", 10);
        public static final Kind DEBUG = new Kind("debug", 20);
        public static final Kind WARNING = new Kind("warning", 30);
@@ -43,7 +44,7 @@ public interface IMessage {
        public static final List KINDS =
                Collections.unmodifiableList(
                        Arrays.asList(
-                               new Kind[] { INFO, DEBUG, WARNING, ERROR, FAIL, ABORT }));
+                               new Kind[] { WEAVEINFO, INFO, DEBUG, WARNING, ERROR, FAIL, ABORT }));
 
        /** @return non-null String with simple message */
        String getMessage();
@@ -69,6 +70,9 @@ public interface IMessage {
        /** @return true if something failed   */
        boolean isFailed();
 
+       /** Caller can verify if this message came about because of a DEOW */
+       boolean getDeclared();
+       
        /** @return Throwable associated with this message, or null if none */
        Throwable getThrown();
 
index af032b6de40b3b3eea8879eaefed24ad460b21ec..1ddb18d697654a5945056d3e125a34a6c2b96dc1 100644 (file)
@@ -30,6 +30,7 @@ public class Message implements IMessage {
     private final ISourceLocation sourceLocation;
     private final String details;
     private final List/*SourceLocation*/ extraSourceLocations;
+    private final boolean declared; // Is it a DEOW ?
         
     /**
      * Create a (compiler) error or warning message
@@ -46,7 +47,7 @@ public class Message implements IMessage {
        this(message, "",(isError ? IMessage.ERROR : IMessage.WARNING), location, null, 
                        (extraSourceLocations.length > 0 ? extraSourceLocations : null));
     }
-    
+        
        /**
         * Create a message, handling null values for message and kind
         * if thrown is not null.
@@ -61,25 +62,31 @@ public class Message implements IMessage {
         */
        public Message(String message, String details, IMessage.Kind kind, 
                ISourceLocation sourceLocation, Throwable thrown, ISourceLocation[] extraSourceLocations) {
+               this(message,details,kind,sourceLocation,thrown,extraSourceLocations,false);
+       }
+       
+       public Message(String message, String details, IMessage.Kind kind,
+                      ISourceLocation sLoc, Throwable thrown, ISourceLocation[] otherLocs,
+                      boolean declared) {
                this.details = details;
                this.message = ((message!=null) ? message : ((thrown==null) ? null : thrown.getMessage()));
                this.kind = kind;
-               this.sourceLocation = sourceLocation;
+               this.sourceLocation = sLoc;
                this.thrown = thrown;
-        
-               if (extraSourceLocations != null) {
+        if (otherLocs != null) {
                        this.extraSourceLocations 
-                = Collections.unmodifiableList(Arrays.asList(extraSourceLocations));
+                       = Collections.unmodifiableList(Arrays.asList(otherLocs));
+               }
+               else {
+                       this.extraSourceLocations = Collections.EMPTY_LIST;
                }
-        else {
-            this.extraSourceLocations = Collections.EMPTY_LIST;
-        }
                if (null == this.kind) {
                         throw new IllegalArgumentException("null kind");
                }
-        if (null == this.message) {
-            throw new IllegalArgumentException("null message");
-        }
+               if (null == this.message) {
+                       throw new IllegalArgumentException("null message");
+               }               
+               this.declared = declared;
        }
     
     /**
@@ -130,6 +137,11 @@ public class Message implements IMessage {
         return kind == IMessage.ABORT;
     }    
     
+    /** Caller can verify if this message came about because of a DEOW */
+    public boolean getDeclared() {
+       return declared;
+    }
+    
     /** 
      * @return true if kind == IMessage.FAIL
      */
index 6882306e8a78dc53fcb34485cfdb718c497f8230..7187b2c4685d2f4ce909861c54023a347bd6ef94 100644 (file)
@@ -55,6 +55,7 @@ public class MessageHandler implements IMessageHolder {
         messages = new ArrayList();
         ignoring = new ArrayList();
         init(accumulateOnly);
+        ignore(IMessage.WEAVEINFO); // Off by default, need to explicitly be enabled (see -showWeaveInfo)
     }
     
     /**
@@ -76,7 +77,9 @@ public class MessageHandler implements IMessageHolder {
             messages.clear();
         }
         if (0 < ignoring.size()) {
+               boolean ignoringWeaveMessages = isIgnoring(IMessage.WEAVEINFO);
             ignoring.clear();
+            if (ignoringWeaveMessages) ignore(IMessage.WEAVEINFO);
         }
         if (null != interceptor) {
             interceptor = null;
diff --git a/bridge/src/org/aspectj/bridge/WeaveMessage.java b/bridge/src/org/aspectj/bridge/WeaveMessage.java
new file mode 100644 (file)
index 0000000..e15abea
--- /dev/null
@@ -0,0 +1,75 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation
+ * 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 IBM     initial implementation 30-May-2004
+ * ******************************************************************/
+
+package org.aspectj.bridge;
+
+public class WeaveMessage extends Message {
+
+    // Kinds of weaving message we can produce
+
+       public static WeaveMessageKind WEAVEMESSAGE_DECLAREPARENTSIMPLEMENTS = 
+         new WeaveMessageKind(1,"Extending interface set for type '%1' (%2) to include '%3' (%4)");
+              
+       public static WeaveMessageKind WEAVEMESSAGE_ITD =
+         new WeaveMessageKind(2,"Type '%1' (%2) has intertyped %3 from '%4' (%5)");
+      
+    // %6 is information like "[with runtime test]"
+       public static WeaveMessageKind WEAVEMESSAGE_ADVISES = 
+         new WeaveMessageKind(3,"Type '%1' (%2) advised by %3 advice from '%4' (%5)%6");
+
+       public static WeaveMessageKind WEAVEMESSAGE_DECLAREPARENTSEXTENDS = 
+         new WeaveMessageKind(4,"Setting superclass of type '%1' (%2) to '%3' (%4)");
+
+       public static WeaveMessageKind WEAVEMESSAGE_SOFTENS = 
+         new WeaveMessageKind(5,"Softening exceptions in type '%1' (%2) as defined by aspect '%3' (%4)");
+
+
+    // private ctor - use the static factory method
+       private WeaveMessage(String message) {
+               super(message, IMessage.WEAVEINFO, null, null);
+       }    
+
+    /**
+     * Static helper method for constructing weaving messages.
+     * @param kind what kind of message (e.g. declare parents)
+     * @param inserts inserts for the message (inserts are marked %n in the message)
+     * @param affectedtypename the type which is being advised/declaredUpon
+     * @param aspectname the aspect that defined the advice or declares
+     * @return new weaving message
+     */
+       public static WeaveMessage constructWeavingMessage(
+         WeaveMessageKind kind,
+         String[] inserts) {
+               StringBuffer str = new StringBuffer(kind.getMessage());
+               int pos = -1;
+               while ((pos=str.indexOf("%"))!=-1) {
+                       int n = Character.getNumericValue(str.charAt(pos+1));
+                       str.replace(pos,pos+2,inserts[n-1]);
+               }
+               return new WeaveMessage(str.toString());
+       }
+       
+       
+       
+       public static class WeaveMessageKind {
+       
+               private int id;
+               private String message;
+       
+               public WeaveMessageKind(int id,String message) {
+                       this.id = id;
+                       this.message = message;
+               }
+       
+               public String getMessage() { return message; }
+       }
+}
index 3d795f25f10ad23ed3f9a915c7749c5fd0cdc883..3928ddc4413fac8a5afe20800a396fa486ec62bd 100644 (file)
@@ -114,6 +114,20 @@ public class BuildArgParser extends Main {
                        
                        AjcConfigParser parser = new AjcConfigParser(buildConfig, handler);
                        parser.parseCommandLine(args);
+                       
+                       boolean swi = buildConfig.getShowWeavingInformation();
+                       // Now jump through firey hoops to turn them on/off
+                       if (handler instanceof CountingMessageHandler) {
+                               IMessageHandler delegate = ((CountingMessageHandler)handler).delegate;
+                               // Without dontIgnore() on the IMessageHandler interface, we have to do this *blurgh*
+                               if (delegate instanceof MessageHandler) {
+                                       if (swi) 
+                                         ((MessageHandler)delegate).dontIgnore(IMessage.WEAVEINFO);
+                                       else 
+                                         ((MessageHandler)delegate).ignore(IMessage.WEAVEINFO);
+                               }
+                       }
+                       
             
             boolean incrementalMode = buildConfig.isIncrementalMode()
                || buildConfig.isIncrementalFileMode();
@@ -460,6 +474,8 @@ public class BuildArgParser extends Main {
                }
                        } else if (arg.equals("-XnoInline")) {
                                buildConfig.setXnoInline(true);
+            } else if (arg.startsWith("-showWeaveInfo")) {
+                buildConfig.setShowWeavingInformation(true);
                        } else if (arg.equals("-Xlintfile")) { 
                                if (args.size() > nextArgIndex) {
                                        File lintSpecFile = makeFile(((ConfigParser.Arg)args.get(nextArgIndex)).getValue());
index 306813e8dc24d38466b9977bdf5e5df2ef965619..0dd92150a4ecb1240bc935c8f0ddc364154af325 100644 (file)
@@ -26,6 +26,7 @@ AspectJ-specific options:\n\
 \t                    (<list> uses classpath delimiter)\n\
 \t-outjar <file>      put output classes in zip file <file>\n\
 \t-argfile <file>     specify line-delimited list of source files\n\
+\t-showWeaveInfo      display information about weaving\n\
 \t-incremental        continuously-running compiler, needs -sourceroots\n\
 \t                    (reads stdin: enter to recompile and ''q'' to quit)\n\
 \t-sourceroots <dirs> compile all .aj and .java files in <dirs>\n\
index 734fd8816a78e9ca8c6a0ca17f33a98cadd8e776..d7925cb8f3b047aa7b50df0c7541913bc505a19a 100644 (file)
@@ -100,8 +100,18 @@ public class WeaverMessageHandler implements IMessageHandler {
                                                                                                  problemSource,        
                                                                                                  usedBinarySourceFileName);
                problem.setSeeAlsoProblems(seeAlso);
+               
+               StringBuffer details = new StringBuffer();
+               // Stick more info in supplementary message info
                if (message.getDetails() != null) {
-                       problem.setSupplementaryMessageInfo(message.getDetails());
+                       details.append(message.getDetails());
+               }
+               // Remember if this message was due to a deow
+               if (message.getDeclared()) {
+                       details.append("[deow=true]");
+               }
+               if (details.length()!=0) { 
+                       problem.setSupplementaryMessageInfo(details.toString());
                }
                compiler.problemReporter.record(problem, problemSource, referenceContext);
                return true;
index 05465c469b7a4fcc3c7016e2b988e2a34e015350..6612e66cede74141d387c699f92e99aa2d177c0c 100644 (file)
 
 package org.aspectj.ajdt.internal.compiler.lookup;
 
-import java.util.*;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 import org.aspectj.ajdt.internal.compiler.ast.AspectDeclaration;
-//import org.aspectj.ajdt.internal.compiler.ast.DeclareDeclaration;
 import org.aspectj.ajdt.internal.compiler.ast.PointcutDeclaration;
-//import org.aspectj.asm.*;
-//import org.aspectj.asm.IProgramElement;
-//import org.aspectj.asm.internal.Relationship;
+import org.aspectj.asm.AsmManager;
 import org.aspectj.bridge.IMessage;
-import org.aspectj.weaver.*;
+import org.aspectj.bridge.WeaveMessage;
+import org.aspectj.weaver.AsmRelationshipProvider;
+import org.aspectj.weaver.ConcreteTypeMunger;
+import org.aspectj.weaver.ResolvedTypeMunger;
+import org.aspectj.weaver.ResolvedTypeX;
+import org.aspectj.weaver.TypeX;
+import org.aspectj.weaver.WeaverStateInfo;
+import org.aspectj.weaver.World;
 import org.aspectj.weaver.bcel.LazyClassGen;
-import org.aspectj.weaver.patterns.*;
+import org.aspectj.weaver.patterns.DeclareParents;
+import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
-import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
 
 /**
@@ -304,8 +321,17 @@ public class AjLookupEnvironment extends LookupEnvironment {
                                        needOldStyleWarning = false;
                                }
                                onType.addInterTypeMunger(munger);
-
-                               AsmInterTypeRelationshipProvider.addRelationship(onType, munger);
+                               //TODO: Andy Should be done at weave time.
+                               // Unfortunately we can't do it at weave time unless the type mungers remember where
+                               // they came from.  Thats why we do it here during complation because at this time
+                               // they do know their source location.  I've put a flag in ResolvedTypeMunger that
+                               // records whether type mungers are currently set to remember their source location.
+                               // The flag is currently set to false, it should be set to true when we do the
+                               // work to version all AspectJ attributes.
+                               // (When done at weave time, it is done by invoking addRelationship() on 
+                               // AsmRelationshipProvider (see BCELTypeMunger)
+                               if (!ResolvedTypeMunger.persistSourceLocation) // Do it up front if we bloody have to
+                                AsmInterTypeRelationshipProvider.addRelationship(onType, munger);
                        }
                }
                
@@ -338,15 +364,39 @@ public class AjLookupEnvironment extends LookupEnvironment {
                                                                                onType + ": " + dangerousInterfaces.get(parent),
                                                                                onType.getSourceLocation(), null);
                                }
+                               AsmRelationshipProvider.addDeclareParentsRelationship(declareParents.getSourceLocation(),factory.fromEclipse(sourceType));
                                addParent(sourceType, parent);
                        }
                }
        }
 
+       private void reportDeclareParentsMessage(WeaveMessage.WeaveMessageKind wmk,SourceTypeBinding sourceType,ResolvedTypeX parent) {
+               if (!factory.getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) {
+                       String filename = new String(sourceType.getFileName());
+                       if (filename.lastIndexOf(File.separator)!=-1)
+                       filename = filename.substring(filename.lastIndexOf(File.separator)+1);
+
+                       factory.getWorld().getMessageHandler().handleMessage(
+                       WeaveMessage.constructWeavingMessage(wmk,
+                               new String[]{CharOperation.toString(sourceType.compoundName),
+                                               filename,
+                                               parent.getClassName(),
+                                               parent.getSourceLocation().getSourceFile().getName()}));
+               }
+       }
+
+
        private void addParent(SourceTypeBinding sourceType, ResolvedTypeX parent) {
                ReferenceBinding parentBinding = (ReferenceBinding)factory.makeTypeBinding(parent); 
+               
                if (parentBinding.isClass()) {
                        sourceType.superclass = parentBinding;
+                       
+                       // TAG: WeavingMessage    DECLARE PARENTS: EXTENDS
+                       // Compiler restriction: Can't do EXTENDS at weave time
+                       // So, only see this message if doing a source compilation
+                       reportDeclareParentsMessage(WeaveMessage.WEAVEMESSAGE_DECLAREPARENTSEXTENDS,sourceType,parent);
+                       
                } else {
                        ReferenceBinding[] oldI = sourceType.superInterfaces;
                        ReferenceBinding[] newI;
@@ -361,6 +411,12 @@ public class AjLookupEnvironment extends LookupEnvironment {
                        }
                        sourceType.superInterfaces = newI;
                        warnOnAddedInterface(factory.fromEclipse(sourceType),parent);
+                       
+
+                       // TAG: WeavingMessage    DECLARE PARENTS: IMPLEMENTS
+                       // This message will come out of BcelTypeMunger.munge if doing a binary weave
+                       reportDeclareParentsMessage(WeaveMessage.WEAVEMESSAGE_DECLAREPARENTSIMPLEMENTS,sourceType,parent);
+                       
                }
                
        }
index 9bb093190f320f04a79c3daf53b4c0db6f5a3d6d..bb97a6ddde36fbc5cb5a16141c3409c84264a7b3 100644 (file)
@@ -55,11 +55,11 @@ public class AsmInterTypeRelationshipProvider {
                                
                        IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap();
                        if (sourceHandle != null && targetHandle != null) {
-                               IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARES);
-                               foreward.getTargets().add(targetHandle);
+                               IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARES,false,true);
+                               foreward.addTarget(targetHandle);
                                
-                               IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARED_BY);
-                               back.getTargets().add(sourceHandle);  
+                               IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARED_BY,false,true);
+                               back.addTarget(sourceHandle);
                        }
                }
        }
index 33a4f2a7894b2772683197f13b69b0f8b2385197..f9300e7ccc47c0ecfa0e7704dedb8cdadbc01066 100644 (file)
@@ -48,6 +48,9 @@ public class EclipseTypeMunger extends ConcreteTypeMunger {
                        this.sourceLocation =
                                new EclipseSourceLocation(sourceMethod.compilationResult, 
                                                sourceMethod.sourceStart, sourceMethod.sourceEnd);
+                       // Piece of magic that tells type mungers where they came from.
+                       // Won't be persisted unless ResolvedTypeMunger.persistSourceLocation is true.
+                       munger.setSourceLocation(sourceLocation);
                }
                targetTypeX = munger.getSignature().getDeclaringType().resolve(world.getWorld());
                //targetBinding = (ReferenceBinding)world.makeTypeBinding(targetTypeX);
index 74f5c4767fe47f9b360cf67ed3a5e337991c8228..34474602d56a7c58c69eb3fe48dac7954420a964 100644 (file)
@@ -348,6 +348,15 @@ public class AjBuildConfig { // XXX needs bootclasspath?
         if (!isXserializableAspects() && global.isXserializableAspects()) {
             setXserializableAspects(true);
         }
+        if (!isXlazyTjp() && global.isXlazyTjp()) {
+               setXlazyTjp(true);
+        }
+        if (!isXreweavable() && global.isXreweavable()) {
+               setXreweavable(true);
+        }
+        if (!getXreweavableCompressClasses() && global.getXreweavableCompressClasses()) {
+               setXreweavableCompressClasses(true);
+        }
     }
 
     void join(Collection local, Collection global) {
@@ -490,4 +499,12 @@ public class AjBuildConfig { // XXX needs bootclasspath?
                options.generateModel = structureModelMode;
        }
        
+       
+       public void setShowWeavingInformation(boolean b) {
+               options.showWeavingInformation = true;
+       }
+       
+       public boolean getShowWeavingInformation() { 
+               return options.showWeavingInformation;
+       }
 }
index ab428758ad22a429699f1da4366e93bf88974ab1..3ca85e0a653177dcd90822826e23b95be3d1d7d1 100644 (file)
@@ -141,11 +141,11 @@ public class AjBuildManager implements IOutputClassFileNameProvider,IBinarySourc
             // if (batch) {
                 setBuildConfig(buildConfig);
             //}
-//            if (batch) {
-//                if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {  
-                       setupModel();
+            if (batch || !AsmManager.attemptIncrementalModelRepairs) {
+//                if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) { 
+                       setupModel(buildConfig);
 //                }
-//            }
+            }
             if (batch) {
                 initBcelWorld(handler);
             }
@@ -168,6 +168,10 @@ public class AjBuildManager implements IOutputClassFileNameProvider,IBinarySourc
                 if (handler.hasErrors()) {
                     return false;
                 }
+
+                               if (AsmManager.isReporting())
+                                   AsmManager.getDefault().reportModelInfo("After a batch build");
+               
             } else {
 // done already?
 //                if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {  
@@ -176,9 +180,13 @@ public class AjBuildManager implements IOutputClassFileNameProvider,IBinarySourc
                 // System.err.println("XXXX start inc ");
                 binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(true);
                 List files = state.getFilesToCompile(true);
-                               boolean hereWeGoAgain = !(files.isEmpty() && binarySourcesForTheNextCompile.isEmpty());
+                               if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode())
+                               if (AsmManager.attemptIncrementalModelRepairs)
+                                   AsmManager.getDefault().processDelta(files,state.addedFiles,state.deletedFiles);
+                boolean hereWeGoAgain = !(files.isEmpty() && binarySourcesForTheNextCompile.isEmpty());
                 for (int i = 0; (i < 5) && hereWeGoAgain; i++) {
                     // System.err.println("XXXX inc: " + files);
+               
                     performCompilation(files);
                     if (handler.hasErrors() || (progressListener!=null && progressListener.isCancelledRequested())) {
                         return false;
@@ -186,9 +194,21 @@ public class AjBuildManager implements IOutputClassFileNameProvider,IBinarySourc
                     binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(false);
                     files = state.getFilesToCompile(false);
                     hereWeGoAgain = !(files.isEmpty() && binarySourcesForTheNextCompile.isEmpty());
+                    // TODO Andy - Needs some thought here...
+                    // I think here we might want to pass empty addedFiles/deletedFiles as they were
+                    // dealt with on the first call to processDelta - we are going through this loop
+                    // again because in compiling something we found something else we needed to
+                    // rebuild.  But what case causes this?
+                    if (hereWeGoAgain) 
+                                         if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode())
+                                           if (AsmManager.attemptIncrementalModelRepairs)
+                                                 AsmManager.getDefault().processDelta(files,state.addedFiles,state.deletedFiles);
                 }
                 if (!files.isEmpty()) {
                     return batchBuild(buildConfig, baseHandler);
+                } else {                
+                       if (AsmManager.isReporting()) 
+                                   AsmManager.getDefault().reportModelInfo("After an incremental build");
                 }
             }
 
@@ -391,31 +411,72 @@ public class AjBuildManager implements IOutputClassFileNameProvider,IBinarySourc
                }
        }
        
+
+//     public static void dumprels() {
+//             IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap();
+//             int ctr = 1;
+//             Set entries = irm.getEntries();
+//             for (Iterator iter = entries.iterator(); iter.hasNext();) {
+//                     String hid = (String) iter.next();
+//                     List rels =  irm.get(hid);
+//                     for (Iterator iterator = rels.iterator(); iterator.hasNext();) {
+//                             IRelationship ir = (IRelationship) iterator.next();
+//                             List targets = ir.getTargets();
+//                             for (Iterator iterator2 = targets.iterator();
+//                                     iterator2.hasNext();
+//                                     ) {
+//                                     String thid = (String) iterator2.next();
+//                                     System.err.println("Hid:"+(ctr++)+":(targets="+targets.size()+") "+hid+" ("+ir.getName()+") "+thid);
+//                             }
+//                     }
+//             }
+//     }
+       
+       
     /**
      * Responsible for managing the ASM model between builds.  Contains the policy for
      * maintaining the persistance of elements in the model.
      * 
      * TODO: implement incremental policy.
      */
-     private void setupModel() {
-        String rootLabel = "<root>";
+     private void setupModel(AjBuildConfig config) {
                IHierarchy model = AsmManager.getDefault().getHierarchy();
-               AsmManager.getDefault().getRelationshipMap().clear();
+               String rootLabel = "<root>";
+               
+                       AsmManager.getDefault().getRelationshipMap().clear();
                
-        IProgramElement.Kind kind = IProgramElement.Kind.FILE_JAVA;
-        if (buildConfig.getConfigFile() != null) {
-            rootLabel = buildConfig.getConfigFile().getName();
-            model.setConfigFile(
-                buildConfig.getConfigFile().getAbsolutePath()
-            );
-            kind = IProgramElement.Kind.FILE_LST;  
-        }
-        model.setRoot(new ProgramElement(rootLabel, kind, new ArrayList()));
+               IProgramElement.Kind kind = IProgramElement.Kind.FILE_JAVA;
+               if (buildConfig.getConfigFile() != null) {
+               rootLabel = buildConfig.getConfigFile().getName();
+               model.setConfigFile(
+                       buildConfig.getConfigFile().getAbsolutePath()
+               );
+               kind = IProgramElement.Kind.FILE_LST;  
+               }
+               model.setRoot(new ProgramElement(rootLabel, kind, new ArrayList()));
                 
-        model.setFileMap(new HashMap());
-        setStructureModel(model);            
+               model.setFileMap(new HashMap());
+               setStructureModel(model);
     }
     
+//    
+//    private void dumplist(List l) {
+//     System.err.println("---- "+l.size());
+//     for (int i =0 ;i<l.size();i++) System.err.println(i+"\t "+l.get(i));
+//    }
+//    private void accumulateFileNodes(IProgramElement ipe,List store) {
+//     if (ipe.getKind()==IProgramElement.Kind.FILE_JAVA ||
+//         ipe.getKind()==IProgramElement.Kind.FILE_ASPECTJ) {
+//             if (!ipe.getName().equals("<root>")) {
+//                     store.add(ipe);
+//                     return;
+//             }
+//     }
+//     for (Iterator i = ipe.getChildren().iterator();i.hasNext();) {
+//             accumulateFileNodes((IProgramElement)i.next(),store);
+//     }
+//    }
+    
     /** init only on initial batch compile? no file-specific options */
        private void initBcelWorld(IMessageHandler handler) throws IOException {
                bcelWorld = new BcelWorld(buildConfig.getClasspath(), handler, null);
index 3c7ae7c3886efe1534cdbfa75ce7cb5a493c6463..f65ad2b3eaa745c43b0cc38fb7ae7513ad9dfbf2 100644 (file)
@@ -64,6 +64,7 @@ public class AjCompilerOptions extends CompilerOptions {
        public boolean xNoInline = false;
        public boolean xReweavable = false;
        public boolean xReweavableCompress = false;
+       public boolean showWeavingInformation = false;
        
        // these next three not exposed by IDEs
        public boolean generateModel = false;
index 1f8a81a7d72afe582697f4385d6411fb6e84ac0d..4a2620873ae67d228a660d8aa8b2e892b5ddf5a4 100644 (file)
@@ -15,7 +15,9 @@ package org.aspectj.ajdt.internal.core.builder;
 import java.util.*;
 
 import org.aspectj.ajdt.internal.compiler.ast.*;
+import org.aspectj.ajdt.internal.compiler.lookup.AjLookupEnvironment;
 import org.aspectj.asm.IProgramElement;
+import org.aspectj.asm.internal.ProgramElement;
 import org.aspectj.weaver.*;
 import org.aspectj.weaver.patterns.*;
 import org.eclipse.jdt.internal.compiler.ast.*;
@@ -98,11 +100,36 @@ public class AsmElementFormatter {
                                node.setDetails("\"" + genDeclareMessage(deow.getMessage()) + "\"");
                                
                        } else if (declare.declareDecl instanceof DeclareParents) {
+
                                node.setKind( IProgramElement.Kind.DECLARE_PARENTS);
                                DeclareParents dp = (DeclareParents)declare.declareDecl;
                                node.setName(name + DECLARE_PARENTS);
-                               node.setDetails(genTypePatternLabel(dp.getChild()));    
                                
+                               String kindOfDP = null;
+                               StringBuffer details = new StringBuffer("");
+                               TypePattern[] newParents = dp.getParents().getTypePatterns();
+                               for (int i = 0; i < newParents.length; i++) {
+                                       TypePattern tp = newParents[i];
+                                       TypeX tx = tp.getExactType();
+                                       if (kindOfDP == null) {
+                                         kindOfDP = "implements ";
+                                         try {
+                                               ResolvedTypeX rtx = tx.resolve(((AjLookupEnvironment)declare.scope.environment()).factory.getWorld());
+                                               if (!rtx.isInterface()) kindOfDP = "extends ";
+                                         } catch (Throwable t) {
+                                               // What can go wrong???? who knows!
+                                         }
+                                         
+                                       }
+                                       String typename= tp.toString();
+                                       if (typename.lastIndexOf(".")!=-1) {
+                                               typename=typename.substring(typename.lastIndexOf(".")+1);
+                                       }
+                                       details.append(typename);
+                                       if ((i+1)<newParents.length) details.append(",");
+                               }
+                               node.setDetails(kindOfDP+details.toString());
+
                        } else if (declare.declareDecl instanceof DeclareSoft) {
                                node.setKind( IProgramElement.Kind.DECLARE_SOFT);
                                DeclareSoft ds = (DeclareSoft)declare.declareDecl;
@@ -125,17 +152,30 @@ public class AsmElementFormatter {
                        InterTypeDeclaration itd = (InterTypeDeclaration)methodDeclaration;
                        String name = itd.onType.toString() + "." + new String(itd.getDeclaredSelector()); 
                        if (methodDeclaration instanceof InterTypeFieldDeclaration) {
-                               node.setKind(IProgramElement.Kind.INTER_TYPE_FIELD);                            
+                               node.setKind(IProgramElement.Kind.INTER_TYPE_FIELD);
+                               node.setName(name);
                        } else if (methodDeclaration instanceof InterTypeMethodDeclaration) {
                                node.setKind(IProgramElement.Kind.INTER_TYPE_METHOD);
-//                             InterTypeMethodDeclaration itmd = (InterTypeMethodDeclaration)methodDeclaration;
+                               node.setName(name);
                        } else if (methodDeclaration instanceof InterTypeConstructorDeclaration) {
                                node.setKind(IProgramElement.Kind.INTER_TYPE_CONSTRUCTOR);
+                               
+       //                      StringBuffer argumentsSignature = new StringBuffer("fubar");
+//                             argumentsSignature.append("(");
+//                             if (methodDeclaration.arguments!=null && methodDeclaration.arguments.length>1) {
+//             
+//                             for (int i = 1;i<methodDeclaration.arguments.length;i++) {
+//                                     argumentsSignature.append(methodDeclaration.arguments[i]);
+//                                     if (i+1<methodDeclaration.arguments.length) argumentsSignature.append(",");
+//                             }
+//                             }
+//                             argumentsSignature.append(")");
 //                             InterTypeConstructorDeclaration itcd = (InterTypeConstructorDeclaration)methodDeclaration;                              
+                               node.setName(itd.onType.toString() + "." + itd.onType.toString()/*+argumentsSignature.toString()*/);
                        } else {
                                node.setKind(IProgramElement.Kind.ERROR);
+                               node.setName(name);
                        }
-                       node.setName(name);
                        node.setCorrespondingType(itd.returnType.toString());
                        if (node.getKind() != IProgramElement.Kind.INTER_TYPE_FIELD) {
                                setParameters(methodDeclaration, node);
index f4aa53488d718a465ce32cef587be40bef304744..ec4aa6c63f5178c457d1b2f964362cd4c0dd8dd8 100644 (file)
 
 package org.aspectj.ajdt.internal.core.builder;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.ListIterator;
-import java.util.Stack;
+import java.io.*;
+import java.util.*;
 
 import org.aspectj.ajdt.internal.compiler.ast.AspectDeclaration;
+import org.aspectj.ajdt.internal.compiler.ast.DeclareDeclaration;
+import org.aspectj.ajdt.internal.compiler.ast.InterTypeDeclaration;
+import org.aspectj.ajdt.internal.compiler.ast.InterTypeFieldDeclaration;
+import org.aspectj.ajdt.internal.compiler.ast.InterTypeMethodDeclaration;
+import org.aspectj.ajdt.internal.compiler.lookup.AjLookupEnvironment;
 import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
-import org.aspectj.asm.IHierarchy;
-import org.aspectj.asm.IProgramElement;
+import org.aspectj.asm.*;
 import org.aspectj.asm.internal.ProgramElement;
-import org.aspectj.bridge.ISourceLocation;
-import org.aspectj.bridge.SourceLocation;
+import org.aspectj.bridge.*;
 import org.aspectj.util.LangUtil;
 import org.aspectj.weaver.Member;
-import org.eclipse.jdt.internal.compiler.ASTVisitor;
-import org.eclipse.jdt.internal.compiler.CompilationResult;
-import org.eclipse.jdt.internal.compiler.ast.ASTNode;
-import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.ExtendedStringLiteral;
-import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.ImportReference;
-import org.eclipse.jdt.internal.compiler.ast.Initializer;
-import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
-import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
-import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
-import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
-import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
+import org.aspectj.weaver.ResolvedMember;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
 import org.eclipse.jdt.internal.compiler.problem.ProblemHandler;
 
 /**
@@ -140,7 +125,8 @@ public class AsmHierarchyBuilder extends ASTVisitor {
         final IProgramElement addToNode = genAddToNode(unit, structureModel);
         
         // -- remove duplicates before adding (XXX use them instead?)
-        for (ListIterator itt = addToNode.getChildren().listIterator(); itt.hasNext(); ) {
+        if (addToNode!=null && addToNode.getChildren()!=null) {
+          for (ListIterator itt = addToNode.getChildren().listIterator(); itt.hasNext(); ) {
             IProgramElement child = (IProgramElement)itt.next();
             ISourceLocation childLoc = child.getSourceLocation();
             if (null == childLoc) {
@@ -149,6 +135,7 @@ public class AsmHierarchyBuilder extends ASTVisitor {
             } else if (childLoc.getSourceFile().equals(file)) {
                 itt.remove();
             }
+          }
         }
         // -- add and traverse
         addToNode.addChild(cuNode);     
@@ -193,14 +180,16 @@ public class AsmHierarchyBuilder extends ASTVisitor {
                        }
                    
                        IProgramElement pkgNode = null;
-                       for (Iterator it = structureModel.getRoot().getChildren().iterator(); 
-                           it.hasNext(); ) {
-                           IProgramElement currNode = (IProgramElement)it.next();
-                           if (pkgName.equals(currNode.getName())) {
-                               pkgNode = currNode;
-                               break; 
-                           } 
-                       }
+                       if (structureModel!=null && structureModel.getRoot()!=null && structureModel.getRoot().getChildren()!=null) {
+                               for (Iterator it = structureModel.getRoot().getChildren().iterator(); 
+                               it.hasNext(); ) {
+                               IProgramElement currNode = (IProgramElement)it.next();
+                               if (pkgName.equals(currNode.getName())) {
+                                       pkgNode = currNode;
+                                       break; 
+                               } 
+                               }
+                               }
                        if (pkgNode == null) {
                            // note packages themselves have no source location
                            pkgNode = new ProgramElement(
@@ -318,19 +307,40 @@ public class AsmHierarchyBuilder extends ASTVisitor {
                return (IProgramElement)stack.peek();
        }       
        
-       public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {                           
-               IProgramElement peNode = new ProgramElement(
-                       "",
-                       IProgramElement.Kind.ERROR,
-                       makeLocation(methodDeclaration),
-                       methodDeclaration.modifiers, 
-                       "",
-                       new ArrayList());  
+       public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {                   
+               IProgramElement peNode = null;
+               
+               // For intertype decls, use the modifiers from the original signature, not the generated method
 
+               if (methodDeclaration instanceof InterTypeDeclaration) {
+                       InterTypeDeclaration itd = (InterTypeDeclaration) methodDeclaration;
+                       ResolvedMember sig = itd.getSignature();
+                       peNode = new ProgramElement(
+                                               "",
+                                               IProgramElement.Kind.ERROR,
+                                               makeLocation(methodDeclaration),
+                                               (sig!=null?sig.getModifiers():0),
+                                               "",
+                                               new ArrayList());  
+               
+               } else {
+               
+                       peNode = new ProgramElement(
+                               "",
+                               IProgramElement.Kind.ERROR,
+                               makeLocation(methodDeclaration),
+                               methodDeclaration.modifiers, 
+                               "",
+                               new ArrayList());  
+               }
                formatter.genLabelAndKind(methodDeclaration, peNode);
                genBytecodeInfo(methodDeclaration, peNode);
-               peNode.setModifiers(methodDeclaration.modifiers);
-               peNode.setCorrespondingType(methodDeclaration.returnType.toString());
+
+               if (methodDeclaration.returnType!=null) {
+                 peNode.setCorrespondingType(methodDeclaration.returnType.toString());
+               } else {
+                 peNode.setCorrespondingType(null);    
+               }
                peNode.setSourceSignature(genSourceSignature(methodDeclaration));
                peNode.setFormalComment(generateJavadocComment(methodDeclaration));
                
@@ -349,7 +359,7 @@ public class AsmHierarchyBuilder extends ASTVisitor {
 
        private String genSourceSignature(MethodDeclaration methodDeclaration) {
                StringBuffer output = new StringBuffer();
-               methodDeclaration.printModifiers(methodDeclaration.modifiers, output);
+               ASTNode.printModifiers(methodDeclaration.modifiers, output);
                methodDeclaration.printReturnType(0, output).append(methodDeclaration.selector).append('(');
                if (methodDeclaration.arguments != null) {
                        for (int i = 0; i < methodDeclaration.arguments.length; i++) {
@@ -485,7 +495,7 @@ public class AsmHierarchyBuilder extends ASTVisitor {
         */
        private String genSourceSignature(FieldDeclaration fieldDeclaration) {
                StringBuffer output = new StringBuffer();
-               fieldDeclaration.printModifiers(fieldDeclaration.modifiers, output);
+               FieldDeclaration.printModifiers(fieldDeclaration.modifiers, output);
                fieldDeclaration.type.print(0, output).append(' ').append(fieldDeclaration.name); 
                
                if (fieldDeclaration.initialization != null
@@ -524,8 +534,17 @@ public class AsmHierarchyBuilder extends ASTVisitor {
                        stack.push(null); // a little wierd but does the job
                        return true;    
                }
+               StringBuffer argumentsSignature = new StringBuffer();
+               argumentsSignature.append("(");
+               if (constructorDeclaration.arguments!=null) {
+                 for (int i = 0;i<constructorDeclaration.arguments.length;i++) {
+                       argumentsSignature.append(constructorDeclaration.arguments[i]);
+                       if (i+1<constructorDeclaration.arguments.length) argumentsSignature.append(",");
+                 }
+               }
+               argumentsSignature.append(")");
                IProgramElement peNode = new ProgramElement(
-                       new String(constructorDeclaration.selector),
+                       new String(constructorDeclaration.selector)+argumentsSignature,
                        IProgramElement.Kind.CONSTRUCTOR,       
                        makeLocation(constructorDeclaration),
                        constructorDeclaration.modifiers,
@@ -535,6 +554,22 @@ public class AsmHierarchyBuilder extends ASTVisitor {
                peNode.setModifiers(constructorDeclaration.modifiers);
                peNode.setSourceSignature(genSourceSignature(constructorDeclaration));
                
+               // Fix to enable us to anchor things from ctor nodes
+               if (constructorDeclaration.binding != null) {
+                       String memberName = "";
+                       String memberBytecodeSignature = "";
+                       try {
+                               Member member = EclipseFactory.makeResolvedMember(constructorDeclaration.binding);
+                               memberName = member.getName();
+                               memberBytecodeSignature = member.getSignature();
+                       } catch (NullPointerException npe) {
+                               memberName = "<undefined>";
+                       } 
+                       peNode.setBytecodeName(memberName);
+                       peNode.setBytecodeSignature(memberBytecodeSignature);
+               }
+               
+               
                ((IProgramElement)stack.peek()).addChild(peNode);
                stack.push(peNode);
                return true;    
@@ -544,7 +579,7 @@ public class AsmHierarchyBuilder extends ASTVisitor {
        }
        private String genSourceSignature(ConstructorDeclaration constructorDeclaration) {
                StringBuffer output = new StringBuffer();
-               constructorDeclaration.printModifiers(constructorDeclaration.modifiers, output);
+               ASTNode.printModifiers(constructorDeclaration.modifiers, output);
                output.append(constructorDeclaration.selector).append('(');  
                if (constructorDeclaration.arguments != null) {
                        for (int i = 0; i < constructorDeclaration.arguments.length; i++) {
index b2b4d9c668586eb82cc6c787942ce74e81dfad31..fa79a83601a94288b9769b5c02a64071a94a1741 100644 (file)
@@ -135,12 +135,23 @@ public class EclipseAdapterUtils {
                                                                                                 seeAlso[i].getSourceLineNumber());
                                                                                                         
                }
+               // We transform messages from AJ types to eclipse IProblems
+               // and back to AJ types.  During their time as eclipse problems,
+               // we remember whether the message originated from a declare
+               // in the extraDetails.
+               String extraDetails = problem.getSupplementaryMessageInfo();
+               boolean declared = false;
+               if (extraDetails!=null && extraDetails.endsWith("[deow=true]")) {
+                       declared = true;
+                       extraDetails = extraDetails.substring(0,extraDetails.length()-"[deow=true]".length());
+               }
+               
         IMessage msg = new Message(problem.getMessage(), 
-                                                          problem.getSupplementaryMessageInfo(),
+                                                          extraDetails,
                                                                   problem.isError() ? IMessage.ERROR : IMessage.WARNING,
                                                                   sourceLocation, 
                                                                   null,
-                                                                  seeAlsoLocations);
+                                                                  seeAlsoLocations,declared);
         return msg;
     }               
 
index de8395967d7893bc79d9d3e04b23a1d9f926aa39..1ec80de037c4bf7339e08f265823254862eadec3 100644 (file)
@@ -188,6 +188,10 @@ public class Main {
         ourHandler = new MessageHandler(true);
     }    
     
+    public MessageHandler getMessageHandler() {
+       return ourHandler;
+    }
+    
     /**
      * Run without throwing exceptions but optionally using System.exit(..).
      * This sets up a message handler which emits messages immediately,
@@ -525,13 +529,15 @@ public class Main {
                }
         
         /** @return System.err for FAIL, ABORT, ERROR, and WARNING, 
-         *           System.out for INFO if verbose.
+         *           System.out for INFO if -verbose and WEAVEINFO if -showWeaveInfo.
          */
         protected PrintStream getStreamFor(IMessage.Kind kind) {
             if (IMessage.WARNING.isSameOrLessThan(kind)) {
                 return System.err;
             } else if (verbose && IMessage.INFO.equals(kind)) {
                 return System.out;
+            } else if (IMessage.WEAVEINFO.equals(kind)) {
+               return System.out;
             } else {
                 return null;
             }
index 96a5021ae384d5efd14e3a1744c687b6681a8ee3..4205b733c875312ce78121ad7436d370d28b7dc5 100644 (file)
@@ -191,7 +191,9 @@ public class BcweaverJarMaker {
                args.add("../tests/bugs/StringToString/helloworld.jar");                
                args.add("../tests/bugs/StringToString/HW.java");               
                CommandTestCase.runCompiler(args, CommandTestCase.NO_ERRORS);
-       }       
+
+               buildShowWeaveInfoTestingJars();                
+       }
        
        public static void makeURLWeavingClassLoaderJars() throws IOException {
                List args = new ArrayList();
@@ -296,7 +298,37 @@ public class BcweaverJarMaker {
                args.add(AjdtAjcTests.TESTDATA_PATH + "/src1/LTWPerthis.aj");
                CommandTestCase.runCompiler(args, CommandTestCase.NO_ERRORS);
        }       
-
+       
+       private static void buildJarWithClasspath(String outjar,String input,String deps,boolean nodebug) {
+               System.out.println("  Building "+outjar);
+               List args = new ArrayList();
+               if (nodebug) args.add("-g:none");               
+               args.add("-classpath"); 
+               args.add("../lib/test/aspectjrt.jar;../lib/test/testing-client.jar"  +
+                                File.pathSeparator + System.getProperty("aspectjrt.path") +
+                                (deps!=null?File.pathSeparator + "../ajde/testdata/WeaveInfoMessagesTest/"+deps:""));
+               args.add("-outjar");
+               args.add("../ajde/testdata/WeaveInfoMessagesTest/"+outjar);             
+               args.add("../ajde/testdata/WeaveInfoMessagesTest/"+input);
+               
+               System.err.println(args);
+               CommandTestCase.runCompiler(args, CommandTestCase.NO_ERRORS);   
+       }
+       
+       private static void buildShowWeaveInfoTestingJars() {
+               System.out.println("For binary weave info message testing (ShowWeaveMessagesTestCase.java)");
+               buildJarWithClasspath("Simple.jar","Simple.java",null,false);
+               // Build with javac and jar
+               // buildJarWithClasspath("Simple_nodebug.jar","Simple.java",null,true);
+               buildJarWithClasspath("AspectAdvice.jar","AspectAdvice.aj",null,false);
+               buildJarWithClasspath("AspectAdvice_nodebug.jar","AspectAdvice.aj","Simple.jar",true);
+               buildJarWithClasspath("AspectDeclare.jar","AspectDeclare.aj","Simple.jar",false);
+               buildJarWithClasspath("AspectDeclare_nodebug.jar","AspectDeclare.aj","Simple.jar",true);
+               buildJarWithClasspath("AspectITD.jar","AspectITD.aj","Simple.jar",false);
+               buildJarWithClasspath("AspectITD_nodebug.jar","AspectITD.aj","Simple.jar",true);
+               buildJarWithClasspath("AspectDeclareSoft.jar","AspectDeclareSoft.aj","Simple.jar",false);
+               buildJarWithClasspath("AspectDeclareSoft_nodebug.jar","AspectDeclareSoft.aj","Simple.jar",true);
+       }       
        
        public static void makeDuplicateManifestTestJars() throws IOException {
                List args = new ArrayList();
index f226d00d934d3646f354e874ee2addbdc8543877..485dfe3d4cb33411cbf9495a455a9bbf5d3bb4d2 100644 (file)
@@ -23,6 +23,8 @@ import java.util.List;
 //import java.util.Collections;
 //import java.util.List;
 
+import org.aspectj.ajde.ui.StructureModelUtil;
+import org.aspectj.ajde.ui.StructureModelUtil.ModelIncorrectException;
 import org.aspectj.bridge.ICommand;
 //import org.aspectj.bridge.IMessage;
 import org.aspectj.bridge.MessageUtil;
@@ -241,6 +243,9 @@ public class IncCompilerRun implements IAjcRun {
             }
 //            final long startTime = System.currentTimeMillis();
             commandResult = compiler.repeatCommand(handler);
+            if (!spec.checkModel.equals("")) {
+                                       StructureModelUtil.checkModel(spec.checkModel);
+            }
             // XXX disabled LangUtil.throwIaxIfNotAllAssignable(actualRecompiled, File.class, "recompiled");
             report = true;
             // handler does not verify sandbox...
@@ -258,6 +263,8 @@ public class IncCompilerRun implements IAjcRun {
                     result = dirChanges.end(status, sandbox.testBaseDir);
                 }
             }
+        } catch (ModelIncorrectException e) {
+               MessageUtil.fail(status,e.getMessage());
         } finally {
             if (!result || spec.runtime.isVerbose()) { // more debugging context in case of failure
                 MessageUtil.info(handler, "spec: " + spec.toLongString());
@@ -293,6 +300,8 @@ public class IncCompilerRun implements IAjcRun {
         protected ArrayList classesAdded;
         protected ArrayList classesRemoved;
         protected ArrayList classesUpdated;
+        
+        protected String checkModel;
 
         /**
          * skip description, skip sourceLocation, 
@@ -312,6 +321,7 @@ public class IncCompilerRun implements IAjcRun {
             classesAdded = new ArrayList();
             classesRemoved = new ArrayList();
             classesUpdated = new ArrayList();
+            checkModel="";
                }
         
         protected void initClone(Spec spec) 
@@ -341,8 +351,13 @@ public class IncCompilerRun implements IAjcRun {
                public void setTag(String input) {
                        tag = input;
                }
+               
+               public void setCheckModel(String thingsToCheck) {
+                       this.checkModel=thingsToCheck;
+               }
+               
         public String toString() {
-            return "IncCompile.Spec(" + tag + ", " + super.toString() + ")";
+            return "IncCompile.Spec(" + tag + ", " + super.toString() + ",["+checkModel+"])";
         }
         
         /** override to set dirToken to Sandbox.CLASSES and default suffix to ".class" */
index 9c8ca57e16ba1cb137236b16326803904bf82083..88869e757224eec1344316a5a5b80cd00efd5406 100644 (file)
@@ -222,6 +222,8 @@ public class SoftMessage implements IMessage {
        public boolean isFailed() {
                return kind == IMessage.FAIL;
        }
+       
+       public boolean getDeclared() { return false; }
 
        /** @return non-null String with simple message */
        final public String getMessage() {
index 45c00f0c0f18d9057316fe6c84fad1637442a3d7..c324963d7a51c146760677dfe0b547e4ff3b686b 100644 (file)
@@ -30,6 +30,7 @@
    <!ELEMENT inc-compile (dir-changes*,message*)>\r
    <!ATTLIST inc-compile tag CDATA #REQUIRED >\r
    <!ATTLIST inc-compile fresh CDATA #IMPLIED >\r
+   <!ATTLIST inc-compile checkModel CDATA #IMPLIED >\r
 \r
    <!ELEMENT run (dir-changes*,message*)>\r
    <!ATTLIST run class CDATA #REQUIRED >\r
diff --git a/tests/incModelTests.xml b/tests/incModelTests.xml
new file mode 100644 (file)
index 0000000..e810479
--- /dev/null
@@ -0,0 +1,102 @@
+
+<!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd">
+
+<suite>
+<!-- 
+     In order for these tests to pass you have to flip this flag to true:
+       AsmManager.attemptIncrementalModelRepairs
+       
+     If you want to debug the output from the tests, you might want uncomment
+     the static initializer in AsmManager which will enable you to collect
+     detailed information on model processing.
+-->
+
+<!-- 
+     These tests utilise the inc-compile test harness option but I've extended it
+     with a checkModel option which enables me to check information about the model
+     after a incremental compilation step.
+-->
+
+<!--
+       asm relationships for inter type declarations are tricky things.  
+       Today, because type mungers don't remember where they came from in attribute form, 
+       the relationships for ITDs are created during source compilation.  When building incrementally,
+       we are really doing a binary weave of 'everything else' with the source for the file that
+       has changed.  In this case the relationships for ITDs are not added.  This makes managing
+       them incrementally in the model rather tough!
+       
+       The solution is to make them remember where they came from.  This would mean we can create
+       the relationships during weave time and so they will be created when either doing a 
+       source compilation or a binary weave.  The support is in ResolvedTypeMunger to remember
+       where they came from (you just have to flick a switch) but I haven't switched it on
+       because we need to version *all* aspectj attributes properly so that we don't end up with 
+       a migration nightmare.  If ITD attributes remembered their location in a particular version
+       of AspectJ then everyone would need to recompile their code from source with that version.
+       If we keep changing the attributes, we keep having this problem.  If we include a *version*
+       number in every attribute we can make the compiler more robust to coping with 'old' attributes
+       that might be missing certain options or values.
+       
+       Hence the first test here is not complete...
+       
+-->
+    <ajc-test dir="incremental/model/introduction" 
+       title="Testing incremental structure model: Intertype declarations (and a declare parents)" 
+       keywords="incremental-test,model-test" >
+        <compile staging="true" options="-incremental,-emacssym" sourceroots="."/>
+        <inc-compile tag="20"/> <!-- Just 'touched' one file -->
+        <inc-compile tag="30"/> <!-- Just 'touched another aspect -->
+     </ajc-test>
+     
+        <ajc-test dir="incremental/model/intertype" 
+       title="Testing incremental structure model: Intertype field declarations" 
+       keywords="incremental-test,model-test" >
+        <compile staging="true" options="-incremental,-emacssym" sourceroots="."/>
+        <inc-compile tag="20" checkModel="inter-type field=2,RelationshipMapSize=3"/> <!-- BetaA intertypes int i and String s -->
+        <inc-compile tag="30" checkModel="inter-type field=1,RelationshipMapSize=2"/> <!-- BetaA takes the String intertype away -->
+     </ajc-test>
+     
+       <ajc-test dir="incremental/model/weaving2" 
+       title="Testing incremental structure model: Weaving handlers" 
+       keywords="incremental-test,model-test" >
+        <compile staging="true" options="-incremental,-emacssym" sourceroots="."/>
+        <inc-compile tag="20" checkModel="code=1,advice=1,RelationshipMapSize=2"/> <!-- BetaA has a new piece of handler advice added -->
+        <inc-compile tag="30" checkModel="code=1,advice=2,RelationshipMapSize=3"/> <!-- secondary.GammaA added, also advises the same handler -->
+        <inc-compile tag="40" checkModel="code=1,advice=1,RelationshipMapSize=2"/> <!-- primary.BetaA deleted -->
+    </ajc-test>
+    
+       <ajc-test dir="incremental/model/weaving" 
+       title="Testing incremental structure model: Weaving" 
+       keywords="incremental-test,model-test" >
+        <compile staging="true" options="-incremental,-emacssym" sourceroots="."/>
+        <inc-compile tag="20" checkModel="code=2,advice=2,java source file=3,RelationshipMapSize=4"/> <!-- BetaA has a new piece of advice added -->
+        <inc-compile tag="30" checkModel="code=1,advice=1,RelationshipMapSize=2"/> <!-- BetaA has a piece of advice removed -->
+        <inc-compile tag="40" checkModel="code=0,RelationshipMapSize=0,advice=0"/> <!-- BetaA other piece of advice removed (now empty) -->
+    </ajc-test>
+
+
+    <ajc-test dir="incremental/model/sourcefiles_updating" 
+       title="Testing incremental structure model: Updating files"
+       keywords="incremental-test,model-test" >
+        <compile staging="true" options="-incremental,-emacssym" sourceroots="."/>
+        <!-- On first compile, 5 source files in model, 'root','Alpha','Beta','Gamma','Delta' -->
+        <inc-compile tag="20" checkModel="java source file=5,method=4,class=3,FileMapSize=4"/> <!-- Beta changed, method added -->
+        <inc-compile tag="30" checkModel="java source file=5,method=4,class=4,advice=1"/> <!-- Delta changed, class added -->
+        <inc-compile tag="40" checkModel="advice=2"/> <!-- Gamma changed, advice added -->
+        <inc-compile tag="50" checkModel="advice=2,pointcut=1"/> <!-- Gamma changed, pointcut added -->
+        <inc-compile tag="60" checkModel="advice=0,pointcut=1"/> <!-- Gamma changed, both advice removed -->
+       </ajc-test>
+       
+       <ajc-test dir="incremental/model/sourcefiles_addremove" 
+       title="Testing incremental structure model: Adding and removing files" 
+       keywords="incremental-test,model-test" >
+        <compile staging="true" options="-incremental,-emacssym" sourceroots="."/>
+        <!-- On first compile, two source files in model, 'root' and 'Alpha' -->
+        <inc-compile tag="20" checkModel="java source file=3,FileMapSize=2"/> <!-- Adds primary.Beta class -->   
+        <inc-compile tag="30" checkModel="java source file=4"/> <!-- Adds secondary.Gamma aspect -->
+        <inc-compile tag="40" checkModel="java source file=5,package=2,FileMapSize=4"/> <!-- Adds seconday.Delta class -->
+        <inc-compile tag="50" checkModel="java source file=4,package=2"/> <!-- Deletes Gamma aspect -->
+        <inc-compile tag="60" checkModel="java source file=2,FileMapSize=1"/> <!-- Deletes Beta and Delta classes -->
+    </ajc-test>
+       
+       
+</suite>  
\ No newline at end of file
diff --git a/tests/incremental/model/intertype/primary/Alpha.java b/tests/incremental/model/intertype/primary/Alpha.java
new file mode 100644 (file)
index 0000000..4f77e13
--- /dev/null
@@ -0,0 +1,7 @@
+package primary;
+
+public class Alpha {
+  public static void main(String [] argv) {
+  }
+}
+
diff --git a/tests/incremental/model/intertype/secondary/BetaA.20.java b/tests/incremental/model/intertype/secondary/BetaA.20.java
new file mode 100644 (file)
index 0000000..abe370e
--- /dev/null
@@ -0,0 +1,8 @@
+package secondary;
+
+import primary.Alpha;
+
+public aspect BetaA {
+  int Alpha.i;
+  String Alpha.s;
+}
diff --git a/tests/incremental/model/intertype/secondary/BetaA.30.java b/tests/incremental/model/intertype/secondary/BetaA.30.java
new file mode 100644 (file)
index 0000000..394c7a9
--- /dev/null
@@ -0,0 +1,7 @@
+package secondary;
+
+import primary.Alpha;
+
+public aspect BetaA {
+  String Alpha.s;
+}
diff --git a/tests/incremental/model/introduction/introduction/CloneablePoint.20.java b/tests/incremental/model/introduction/introduction/CloneablePoint.20.java
new file mode 100644 (file)
index 0000000..c345098
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+*/
+package introduction;
+
+public aspect CloneablePoint {
+
+   declare parents: Point implements Cloneable;
+
+   public Object Point.clone() throws CloneNotSupportedException {
+      // we choose to bring all fields up to date before cloning.
+      makeRectangular();
+      makePolar();
+      return super.clone();
+   }
+
+   public static void main(String[] args){
+      Point p1 = new Point();
+      Point p2 = null;
+
+      p1.setPolar(Math.PI, 1.0);
+      try {
+         p2 = (Point)p1.clone();
+      } catch (CloneNotSupportedException e) {}
+      System.out.println("p1 =" + p1 );
+      System.out.println("p2 =" + p2 );
+
+      p1.rotate(Math.PI / -2);
+      System.out.println("p1 =" + p1 );
+      System.out.println("p2 =" + p2 );
+   }
+}
diff --git a/tests/incremental/model/introduction/introduction/CloneablePoint.java b/tests/incremental/model/introduction/introduction/CloneablePoint.java
new file mode 100644 (file)
index 0000000..c345098
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+*/
+package introduction;
+
+public aspect CloneablePoint {
+
+   declare parents: Point implements Cloneable;
+
+   public Object Point.clone() throws CloneNotSupportedException {
+      // we choose to bring all fields up to date before cloning.
+      makeRectangular();
+      makePolar();
+      return super.clone();
+   }
+
+   public static void main(String[] args){
+      Point p1 = new Point();
+      Point p2 = null;
+
+      p1.setPolar(Math.PI, 1.0);
+      try {
+         p2 = (Point)p1.clone();
+      } catch (CloneNotSupportedException e) {}
+      System.out.println("p1 =" + p1 );
+      System.out.println("p2 =" + p2 );
+
+      p1.rotate(Math.PI / -2);
+      System.out.println("p1 =" + p1 );
+      System.out.println("p2 =" + p2 );
+   }
+}
diff --git a/tests/incremental/model/introduction/introduction/ComparablePoint.java b/tests/incremental/model/introduction/introduction/ComparablePoint.java
new file mode 100644 (file)
index 0000000..a2893db
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+*/
+
+package introduction;
+
+public aspect ComparablePoint {
+
+   declare parents: Point implements Comparable;
+
+   public int Point.compareTo(Object o) {
+      return (int) (this.getRho() - ((Point)o).getRho());
+   }
+
+   public static void main(String[] args){
+      Point p1 = new Point();
+      Point p2 = new Point();
+
+      System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
+
+      p1.setRectangular(2,5);
+      p2.setRectangular(2,5);
+      System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
+
+      p2.setRectangular(3,6);
+      System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
+
+      p1.setPolar(Math.PI, 4);
+      p2.setPolar(Math.PI, 4);
+      System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
+
+      p1.rotate(Math.PI / 4.0);
+      System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
+
+      p1.offset(1,1);
+      System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
+   }
+}
diff --git a/tests/incremental/model/introduction/introduction/HashablePoint.30.java b/tests/incremental/model/introduction/introduction/HashablePoint.30.java
new file mode 100644 (file)
index 0000000..39eb33b
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+*/
+
+package introduction;
+
+import java.util.Hashtable;
+
+public aspect HashablePoint {
+
+   public int Point.hashCode() {
+      return (int) (getX() + getY() % Integer.MAX_VALUE);
+   }
+
+   public boolean Point.equals(Object o) {
+      if (o == this) { return true; }
+      if (!(o instanceof Point)) { return false; }
+      Point other = (Point)o;
+      return (getX() == other.getX()) && (getY() == other.getY());
+   }
+
+   public static void main(String[] args) {
+      Hashtable h = new Hashtable();
+      Point p1 = new Point();
+
+      p1.setRectangular(10, 10);
+      Point p2 = new Point();
+
+      p2.setRectangular(10, 10);
+
+      System.out.println("p1 = " + p1);
+      System.out.println("p2 = " + p2);
+      System.out.println("p1.hashCode() = " + p1.hashCode());
+      System.out.println("p2.hashCode() = " + p2.hashCode());
+
+      h.put(p1, "P1");
+      System.out.println("Got: " + h.get(p2));
+   }
+}
diff --git a/tests/incremental/model/introduction/introduction/HashablePoint.java b/tests/incremental/model/introduction/introduction/HashablePoint.java
new file mode 100644 (file)
index 0000000..39eb33b
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+*/
+
+package introduction;
+
+import java.util.Hashtable;
+
+public aspect HashablePoint {
+
+   public int Point.hashCode() {
+      return (int) (getX() + getY() % Integer.MAX_VALUE);
+   }
+
+   public boolean Point.equals(Object o) {
+      if (o == this) { return true; }
+      if (!(o instanceof Point)) { return false; }
+      Point other = (Point)o;
+      return (getX() == other.getX()) && (getY() == other.getY());
+   }
+
+   public static void main(String[] args) {
+      Hashtable h = new Hashtable();
+      Point p1 = new Point();
+
+      p1.setRectangular(10, 10);
+      Point p2 = new Point();
+
+      p2.setRectangular(10, 10);
+
+      System.out.println("p1 = " + p1);
+      System.out.println("p2 = " + p2);
+      System.out.println("p1.hashCode() = " + p1.hashCode());
+      System.out.println("p2.hashCode() = " + p2.hashCode());
+
+      h.put(p1, "P1");
+      System.out.println("Got: " + h.get(p2));
+   }
+}
diff --git a/tests/incremental/model/introduction/introduction/Point.30.java b/tests/incremental/model/introduction/introduction/Point.30.java
new file mode 100644 (file)
index 0000000..609a048
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+  Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+  Use and copying of this software and preparation of derivative works based
+  upon this software are permitted.  Any distribution of this software or
+  derivative works must comply with all applicable United States export control
+  laws.
+
+  This software is made available AS IS, and Xerox Corporation makes no warranty
+  about the software, its performance or its conformity to any specification.
+*/
+
+package introduction;
+
+public class Point {
+
+   protected double x = 0;
+   protected double y = 0;
+   protected double theta = 0;
+   protected double rho = 0;
+
+   protected boolean polar = true;
+   protected boolean rectangular = true;
+
+   public double getX(){
+      makeRectangular();
+      return x;
+   }
+
+   public double getY(){
+      makeRectangular();
+      return y;
+   }
+
+   public double getTheta(){
+      makePolar();
+      return theta;
+   }
+
+   public double getRho(){
+      makePolar();
+      return rho;
+   }
+
+   public void setRectangular(double newX, double newY){
+      x = newX;
+      y = newY;
+      rectangular = true;
+      polar = false;
+   }
+
+   public void setPolar(double newTheta, double newRho){
+      theta = newTheta;
+      rho = newRho;
+      rectangular = false;
+      polar = true;
+   }
+
+   public void rotate(double angle){
+      setPolar(theta + angle, rho);
+   }
+
+   public void offset(double deltaX, double deltaY){
+      setRectangular(x + deltaX, y + deltaY);
+   }
+
+   protected void makePolar(){
+      if (!polar){
+        theta = Math.atan2(y,x);
+        rho = y / Math.sin(theta);
+        polar = true;
+      }
+   }
+
+   protected void makeRectangular(){
+      if (!rectangular) {
+        x = rho * Math.sin(theta);
+        y = rho * Math.cos(theta);
+        rectangular = true;
+      }
+   }
+
+   public String toString(){
+      return "(" + getX() + ", " + getY() + ")[" 
+        + getTheta() + " : " + getRho() + "]";
+   }
+
+   public static void main(String[] args){
+      Point p1 = new Point();
+      System.out.println("p1 =" + p1);
+      p1.setRectangular(5,2);
+      System.out.println("p1 =" + p1);
+      p1.setPolar( Math.PI / 4.0 , 1.0);
+      System.out.println("p1 =" + p1);
+      p1.setPolar( 0.3805 , 5.385);
+      System.out.println("p1 =" + p1);
+   }
+}
diff --git a/tests/incremental/model/introduction/introduction/Point.java b/tests/incremental/model/introduction/introduction/Point.java
new file mode 100644 (file)
index 0000000..609a048
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+  Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+  Use and copying of this software and preparation of derivative works based
+  upon this software are permitted.  Any distribution of this software or
+  derivative works must comply with all applicable United States export control
+  laws.
+
+  This software is made available AS IS, and Xerox Corporation makes no warranty
+  about the software, its performance or its conformity to any specification.
+*/
+
+package introduction;
+
+public class Point {
+
+   protected double x = 0;
+   protected double y = 0;
+   protected double theta = 0;
+   protected double rho = 0;
+
+   protected boolean polar = true;
+   protected boolean rectangular = true;
+
+   public double getX(){
+      makeRectangular();
+      return x;
+   }
+
+   public double getY(){
+      makeRectangular();
+      return y;
+   }
+
+   public double getTheta(){
+      makePolar();
+      return theta;
+   }
+
+   public double getRho(){
+      makePolar();
+      return rho;
+   }
+
+   public void setRectangular(double newX, double newY){
+      x = newX;
+      y = newY;
+      rectangular = true;
+      polar = false;
+   }
+
+   public void setPolar(double newTheta, double newRho){
+      theta = newTheta;
+      rho = newRho;
+      rectangular = false;
+      polar = true;
+   }
+
+   public void rotate(double angle){
+      setPolar(theta + angle, rho);
+   }
+
+   public void offset(double deltaX, double deltaY){
+      setRectangular(x + deltaX, y + deltaY);
+   }
+
+   protected void makePolar(){
+      if (!polar){
+        theta = Math.atan2(y,x);
+        rho = y / Math.sin(theta);
+        polar = true;
+      }
+   }
+
+   protected void makeRectangular(){
+      if (!rectangular) {
+        x = rho * Math.sin(theta);
+        y = rho * Math.cos(theta);
+        rectangular = true;
+      }
+   }
+
+   public String toString(){
+      return "(" + getX() + ", " + getY() + ")[" 
+        + getTheta() + " : " + getRho() + "]";
+   }
+
+   public static void main(String[] args){
+      Point p1 = new Point();
+      System.out.println("p1 =" + p1);
+      p1.setRectangular(5,2);
+      System.out.println("p1 =" + p1);
+      p1.setPolar( Math.PI / 4.0 , 1.0);
+      System.out.println("p1 =" + p1);
+      p1.setPolar( 0.3805 , 5.385);
+      System.out.println("p1 =" + p1);
+   }
+}
diff --git a/tests/incremental/model/sourcefiles_addremove/primary/Alpha.java b/tests/incremental/model/sourcefiles_addremove/primary/Alpha.java
new file mode 100644 (file)
index 0000000..5e60f4f
--- /dev/null
@@ -0,0 +1,7 @@
+
+package primary;
+
+public class Alpha {
+    public static void main (String[] args) {
+    }
+}
diff --git a/tests/incremental/model/sourcefiles_addremove/primary/Beta.20.java b/tests/incremental/model/sourcefiles_addremove/primary/Beta.20.java
new file mode 100644 (file)
index 0000000..1ef401c
--- /dev/null
@@ -0,0 +1,11 @@
+package primary;
+
+public class Beta {
+  public static void main(String[] argv) {
+    sayhi();
+  }
+
+  public static void sayhi() {
+    System.err.println("Hi");
+  }
+}
diff --git a/tests/incremental/model/sourcefiles_addremove/primary/Beta.delete.60.java b/tests/incremental/model/sourcefiles_addremove/primary/Beta.delete.60.java
new file mode 100644 (file)
index 0000000..1ef401c
--- /dev/null
@@ -0,0 +1,11 @@
+package primary;
+
+public class Beta {
+  public static void main(String[] argv) {
+    sayhi();
+  }
+
+  public static void sayhi() {
+    System.err.println("Hi");
+  }
+}
diff --git a/tests/incremental/model/sourcefiles_addremove/secondary/Delta.40.java b/tests/incremental/model/sourcefiles_addremove/secondary/Delta.40.java
new file mode 100644 (file)
index 0000000..ed410ed
--- /dev/null
@@ -0,0 +1,5 @@
+package secondary;
+
+public class Delta {
+  public static void foo() {  }
+}
diff --git a/tests/incremental/model/sourcefiles_addremove/secondary/Delta.delete.60.java b/tests/incremental/model/sourcefiles_addremove/secondary/Delta.delete.60.java
new file mode 100644 (file)
index 0000000..ed410ed
--- /dev/null
@@ -0,0 +1,5 @@
+package secondary;
+
+public class Delta {
+  public static void foo() {  }
+}
diff --git a/tests/incremental/model/sourcefiles_addremove/secondary/Gamma.30.java b/tests/incremental/model/sourcefiles_addremove/secondary/Gamma.30.java
new file mode 100644 (file)
index 0000000..edbe716
--- /dev/null
@@ -0,0 +1,7 @@
+package secondary;
+
+aspect Gamma {
+  before(): call(* *(..)) {
+  }
+}
+
diff --git a/tests/incremental/model/sourcefiles_addremove/secondary/Gamma.delete.50.java b/tests/incremental/model/sourcefiles_addremove/secondary/Gamma.delete.50.java
new file mode 100644 (file)
index 0000000..edbe716
--- /dev/null
@@ -0,0 +1,7 @@
+package secondary;
+
+aspect Gamma {
+  before(): call(* *(..)) {
+  }
+}
+
diff --git a/tests/incremental/model/sourcefiles_updating/primary/Alpha.java b/tests/incremental/model/sourcefiles_updating/primary/Alpha.java
new file mode 100644 (file)
index 0000000..5e60f4f
--- /dev/null
@@ -0,0 +1,7 @@
+
+package primary;
+
+public class Alpha {
+    public static void main (String[] args) {
+    }
+}
diff --git a/tests/incremental/model/sourcefiles_updating/primary/Beta.20.java b/tests/incremental/model/sourcefiles_updating/primary/Beta.20.java
new file mode 100644 (file)
index 0000000..4efd977
--- /dev/null
@@ -0,0 +1,13 @@
+package primary;
+
+// Method added beyond what was in Beta.java
+
+public class Beta {
+  public static void main(String[] argv) {
+    sayhi();
+  }
+
+  public static void sayhi() {
+    System.err.println("Hi");
+  }
+}
diff --git a/tests/incremental/model/sourcefiles_updating/primary/Beta.java b/tests/incremental/model/sourcefiles_updating/primary/Beta.java
new file mode 100644 (file)
index 0000000..86dc7df
--- /dev/null
@@ -0,0 +1,7 @@
+package primary;
+
+public class Beta {
+  public static void main(String[] argv) {
+  }
+
+}
diff --git a/tests/incremental/model/sourcefiles_updating/secondary/Delta.30.java b/tests/incremental/model/sourcefiles_updating/secondary/Delta.30.java
new file mode 100644 (file)
index 0000000..f54b3f7
--- /dev/null
@@ -0,0 +1,10 @@
+package secondary;
+
+// Extra class added over Delta.java
+
+public class Delta {
+  public static void foo() {  }
+}
+
+class DeltaExtra {
+}
diff --git a/tests/incremental/model/sourcefiles_updating/secondary/Delta.java b/tests/incremental/model/sourcefiles_updating/secondary/Delta.java
new file mode 100644 (file)
index 0000000..ed410ed
--- /dev/null
@@ -0,0 +1,5 @@
+package secondary;
+
+public class Delta {
+  public static void foo() {  }
+}
diff --git a/tests/incremental/model/sourcefiles_updating/secondary/Gamma.40.java b/tests/incremental/model/sourcefiles_updating/secondary/Gamma.40.java
new file mode 100644 (file)
index 0000000..7e508af
--- /dev/null
@@ -0,0 +1,10 @@
+package secondary;
+
+aspect Gamma {
+  before(): call(* *(..)) {
+  }
+
+  after(): call(* *(..)) {
+  }
+}
+
diff --git a/tests/incremental/model/sourcefiles_updating/secondary/Gamma.50.java b/tests/incremental/model/sourcefiles_updating/secondary/Gamma.50.java
new file mode 100644 (file)
index 0000000..a380f86
--- /dev/null
@@ -0,0 +1,13 @@
+package secondary;
+
+aspect Gamma {
+
+  pointcut calls(): call(* *(..));
+
+  before(): calls() {
+  }
+
+  after(): calls() {
+  }
+}
+
diff --git a/tests/incremental/model/sourcefiles_updating/secondary/Gamma.60.java b/tests/incremental/model/sourcefiles_updating/secondary/Gamma.60.java
new file mode 100644 (file)
index 0000000..de4cf6d
--- /dev/null
@@ -0,0 +1,8 @@
+package secondary;
+
+aspect Gamma {
+
+  pointcut calls(): call(* *(..));
+
+}
+
diff --git a/tests/incremental/model/sourcefiles_updating/secondary/Gamma.java b/tests/incremental/model/sourcefiles_updating/secondary/Gamma.java
new file mode 100644 (file)
index 0000000..edbe716
--- /dev/null
@@ -0,0 +1,7 @@
+package secondary;
+
+aspect Gamma {
+  before(): call(* *(..)) {
+  }
+}
+
diff --git a/tests/incremental/model/weaving/primary/Alpha.java b/tests/incremental/model/weaving/primary/Alpha.java
new file mode 100644 (file)
index 0000000..e51f9f9
--- /dev/null
@@ -0,0 +1,21 @@
+package primary;
+
+public class Alpha {
+  public static void main(String[] argv) {
+    Alpha instance = new Alpha();
+    instance.m1();
+    instance.m2();
+    instance.m3();
+  }
+
+  public void m1() {
+  }
+
+  public boolean m2() {
+    return false;
+  }
+
+  public String m3() {
+    return "";
+  }
+}
diff --git a/tests/incremental/model/weaving/primary/BetaA.20.java b/tests/incremental/model/weaving/primary/BetaA.20.java
new file mode 100644 (file)
index 0000000..74ff748
--- /dev/null
@@ -0,0 +1,16 @@
+package primary;
+
+public aspect BetaA {
+
+  pointcut m1call(): call(* m1(..));
+
+  before(): m1call() {
+    System.err.println("m1 got called");
+  }
+
+  pointcut m2call(): call(* m2(..));
+
+  before(): m2call() {
+    System.err.println("m2 got called");
+  }
+}
diff --git a/tests/incremental/model/weaving/primary/BetaA.30.java b/tests/incremental/model/weaving/primary/BetaA.30.java
new file mode 100644 (file)
index 0000000..eeba653
--- /dev/null
@@ -0,0 +1,10 @@
+package primary;
+
+public aspect BetaA {
+
+  pointcut m2call(): call(* m2(..));
+
+  before(): m2call() {
+    System.err.println("m2 got called");
+  }
+}
diff --git a/tests/incremental/model/weaving/primary/BetaA.40.java b/tests/incremental/model/weaving/primary/BetaA.40.java
new file mode 100644 (file)
index 0000000..706cebb
--- /dev/null
@@ -0,0 +1,5 @@
+package primary;
+
+public aspect BetaA {
+
+}
diff --git a/tests/incremental/model/weaving/primary/BetaA.java b/tests/incremental/model/weaving/primary/BetaA.java
new file mode 100644 (file)
index 0000000..333c5f1
--- /dev/null
@@ -0,0 +1,10 @@
+package primary;
+
+public aspect BetaA {
+
+  pointcut m1call(): call(* m1(..));
+
+  before(): m1call() {
+    System.err.println("m1 got called");
+  }
+}
diff --git a/tests/incremental/model/weaving2/primary/Alpha.java b/tests/incremental/model/weaving2/primary/Alpha.java
new file mode 100644 (file)
index 0000000..ab7e82c
--- /dev/null
@@ -0,0 +1,11 @@
+package primary;
+
+public class Alpha {
+  public static void main(String[]argv) {
+    try {
+      System.err.println("aaa");
+    } catch (Throwable t) {
+      System.err.println("Caught:"+t);
+    }
+  }
+}
diff --git a/tests/incremental/model/weaving2/primary/BetaA.20.java b/tests/incremental/model/weaving2/primary/BetaA.20.java
new file mode 100644 (file)
index 0000000..1c73c6b
--- /dev/null
@@ -0,0 +1,8 @@
+package primary;
+
+public aspect BetaA {
+  pointcut handlers(): handler(Throwable);
+  before(): handlers() {
+    System.err.println("xxx");
+  }
+}
diff --git a/tests/incremental/model/weaving2/primary/BetaA.delete.40.java b/tests/incremental/model/weaving2/primary/BetaA.delete.40.java
new file mode 100644 (file)
index 0000000..1c73c6b
--- /dev/null
@@ -0,0 +1,8 @@
+package primary;
+
+public aspect BetaA {
+  pointcut handlers(): handler(Throwable);
+  before(): handlers() {
+    System.err.println("xxx");
+  }
+}
diff --git a/tests/incremental/model/weaving2/primary/BetaA.java b/tests/incremental/model/weaving2/primary/BetaA.java
new file mode 100644 (file)
index 0000000..1b8b1d7
--- /dev/null
@@ -0,0 +1,4 @@
+package primary;
+
+public aspect BetaA {
+}
diff --git a/tests/incremental/model/weaving2/secondary/GammaA.30.java b/tests/incremental/model/weaving2/secondary/GammaA.30.java
new file mode 100644 (file)
index 0000000..be2bec7
--- /dev/null
@@ -0,0 +1,8 @@
+package primary;
+
+public aspect GammaA {
+  pointcut handlers(): handler(Throwable);
+  before(): handlers() {
+    System.err.println("xxx");
+  }
+}
index a1e1e4a065f48bc94a9d727876813b58800f6c60..b3adcba43e8c0edde4c246a665d1969fe1480ee7 100644 (file)
@@ -16,9 +16,11 @@ package org.aspectj.weaver;
 import java.util.ArrayList;
 import java.util.Iterator;
 import org.aspectj.asm.*;
+import org.aspectj.asm.internal.AspectJElementHierarchy;
 import org.aspectj.asm.internal.ProgramElement;
 import org.aspectj.bridge.ISourceLocation;
 import org.aspectj.bridge.SourceLocation;
+import org.aspectj.weaver.bcel.BcelAdvice;
 
 public class AsmRelationshipProvider {
        
@@ -28,6 +30,8 @@ public class AsmRelationshipProvider {
        public static final String DECLAREDY_BY = "declared by";
        public static final String MATCHED_BY = "matched by";
        public static final String MATCHES_DECLARE = "matches declare";
+       public static final String INTER_TYPE_DECLARES = "declared on";
+       public static final String INTER_TYPE_DECLARED_BY = "aspect declarations";
 
        public static void checkerMunger(IHierarchy model, Shadow shadow, Checker checker) {
                if (shadow.getSourceLocation() == null || checker.getSourceLocation() == null) return;
@@ -44,37 +48,116 @@ public class AsmRelationshipProvider {
 
                IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap();
                if (sourceHandle != null && targetHandle != null) {
-                       IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE, MATCHED_BY);
-                       foreward.getTargets().add(targetHandle);
+                       IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE, MATCHED_BY,false,true);
+                       foreward.addTarget(targetHandle);
+//                     foreward.getTargets().add(targetHandle);
                                
-                       IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE, MATCHES_DECLARE);
+                       IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE, MATCHES_DECLARE,false,true);
                        if (back != null && back.getTargets() != null) {
-                               back.getTargets().add(sourceHandle);   
+                               back.addTarget(sourceHandle);
+                               //back.getTargets().add(sourceHandle);   
                        }
                }
        }
+
+    // For ITDs
+       public static void addRelationship(
+               ResolvedTypeX onType,
+               ResolvedTypeMunger munger,
+               ResolvedTypeX originatingAspect) {
+
+               String sourceHandle = "";
+               if (munger.getSourceLocation()!=null) {
+                       sourceHandle = ProgramElement.createHandleIdentifier(
+                                                                               munger.getSourceLocation().getSourceFile(),
+                                                                               munger.getSourceLocation().getLine(),
+                                                                               munger.getSourceLocation().getColumn());
+               } else {
+                       sourceHandle = ProgramElement.createHandleIdentifier(
+                                                       originatingAspect.getSourceLocation().getSourceFile(),
+                                                       originatingAspect.getSourceLocation().getLine(),
+                                                       originatingAspect.getSourceLocation().getColumn());
+               }
+               if (originatingAspect.getSourceLocation() != null) {
+                               
+                       String targetHandle = ProgramElement.createHandleIdentifier(
+                               onType.getSourceLocation().getSourceFile(),
+                               onType.getSourceLocation().getLine(),
+                               onType.getSourceLocation().getColumn());
+                               
+                       IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap();
+                       if (sourceHandle != null && targetHandle != null) {
+                               IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARES,false,true);
+                               foreward.addTarget(targetHandle);
+//                             foreward.getTargets().add(targetHandle);
+                               
+                               IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARED_BY,false,true);
+                               back.addTarget(sourceHandle);
+//                             back.getTargets().add(sourceHandle);  
+                       }
+               }
+       }
+       
+       public static void addDeclareParentsRelationship(ISourceLocation decp,ResolvedTypeX targetType) {
+
+               String sourceHandle = ProgramElement.createHandleIdentifier(decp.getSourceFile(),decp.getLine(),decp.getColumn());
+               
+               IProgramElement ipe = AsmManager.getDefault().getHierarchy().findElementForHandle(sourceHandle);
+               
+       
+               String targetHandle = ProgramElement.createHandleIdentifier(
+                               targetType.getSourceLocation().getSourceFile(),
+                               targetType.getSourceLocation().getLine(),
+                               targetType.getSourceLocation().getColumn());
+                               
+               IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap();
+               if (sourceHandle != null && targetHandle != null) {
+                       IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARES,false,true);
+                       foreward.addTarget(targetHandle);
+                               
+                       IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARED_BY,false,true);
+                       back.addTarget(sourceHandle);
+               }
+               
+       }
        
        public static void adviceMunger(IHierarchy model, Shadow shadow, ShadowMunger munger) {
                if (munger instanceof Advice) {
                        Advice advice = (Advice)munger;
+                       
                        if (advice.getKind().isPerEntry() || advice.getKind().isCflow()) {
                                // TODO: might want to show these in the future
                                return;
                        }
                        
+
                        IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap();
-                       IProgramElement targetNode = getNode(AsmManager.getDefault().getHierarchy(), shadow);                   
+                       IProgramElement targetNode = getNode(AsmManager.getDefault().getHierarchy(), shadow);
+                       boolean runtimeTest = ((BcelAdvice)munger).hasDynamicTests();
+                       
+                       // Work out extra info to inform interested UIs !
+                       IProgramElement.ExtraInformation ai = new IProgramElement.ExtraInformation();
+
                        String adviceHandle = advice.getHandle(); 
+                       
+                       // What kind of advice is it?
+                       // TODO: Prob a better way to do this but I just want to
+                       // get it into CVS !!!
+                       AdviceKind ak = ((Advice)munger).getKind();
+                       ai.setExtraAdviceInformation(ak.getName());
+                       IProgramElement adviceElement = AsmManager.getDefault().getHierarchy().findElementForHandle(adviceHandle);
+                       adviceElement.setExtraInfo(ai);         
+                       
                        if (adviceHandle != null && targetNode != null) {
                
                                if (targetNode != null) {
                                        String targetHandle = targetNode.getHandleIdentifier(); 
                                
-                                       IRelationship foreward = mapper.get(adviceHandle, IRelationship.Kind.ADVICE, ADVISES);
-                                       if (foreward != null) foreward.getTargets().add(targetHandle);
+                                       IRelationship foreward = mapper.get(adviceHandle, IRelationship.Kind.ADVICE, ADVISES,runtimeTest,true);
+                                       if (foreward != null) foreward.addTarget(targetHandle);//foreward.getTargets().add(targetHandle);
                                        
-                                       IRelationship back = mapper.get(targetHandle, IRelationship.Kind.ADVICE, ADVISED_BY);
-                                       if (back != null) back.getTargets().add(adviceHandle);
+                                       IRelationship back = mapper.get(targetHandle, IRelationship.Kind.ADVICE, ADVISED_BY,runtimeTest,true);
+                                       if (back != null)     back.addTarget(adviceHandle);//back.getTargets().add(adviceHandle);
                                }
                        }
 
@@ -102,12 +185,19 @@ public class AsmRelationshipProvider {
                }
        }
        
+       private static boolean sourceLinesMatch(ISourceLocation loc1,ISourceLocation loc2) {
+               if (loc1.getLine()!=loc2.getLine()) return false;
+               return true;
+       }
+       
+       
        private static IProgramElement findOrCreateCodeNode(IProgramElement enclosingNode, Member shadowSig, Shadow shadow)
        {
                for (Iterator it = enclosingNode.getChildren().iterator(); it.hasNext(); ) {
                        IProgramElement node = (IProgramElement)it.next();
                        if (shadowSig.getName().equals(node.getBytecodeName()) &&
-                               shadowSig.getSignature().equals(node.getBytecodeSignature()))
+                               shadowSig.getSignature().equals(node.getBytecodeSignature()) &&
+                               sourceLinesMatch(node.getSourceLocation(),shadow.getSourceLocation()))
                        {
                                return node;
                        }
index c87221bfa179cdb2e674834b7176eab535912af4..e8f5266f7ed1fbb1c8091cdd4cc66c58fcc0a162 100644 (file)
@@ -52,11 +52,15 @@ public class Checker extends ShadowMunger {
                                isError ? IMessage.ERROR : IMessage.WARNING,
                                shadow.getSourceLocation(),
                 null,
-                new ISourceLocation[]{this.getSourceLocation()});
-                       world.getMessageHandler().handleMessage(message);
+                new ISourceLocation[]{this.getSourceLocation()},true);
+            
+            world.getMessageHandler().handleMessage(message);
                        
                        if (world.xrefHandler != null) {
-                               world.xrefHandler.addCrossReference(this.getSourceLocation(),shadow.getSourceLocation(),IRelationship.Kind.DECLARE);
+                               world.xrefHandler.addCrossReference(this.getSourceLocation(),
+                                 shadow.getSourceLocation(),
+                                 (this.isError?IRelationship.Kind.DECLARE_ERROR:IRelationship.Kind.DECLARE_WARNING),false);
+                       
                        }
                        
                        if (world.getModel() != null) {
index 0ce029a551945162fa19c6bc0efc5823cd01bab5..0f0ecf02230ed8df58c93c768287848013fe93bc 100644 (file)
@@ -44,7 +44,8 @@ public abstract class ConcreteTypeMunger implements PartialOrder.PartialComparab
        }
        
        public ISourceLocation getSourceLocation() {
-               return null; //XXX
+               if (munger == null) return null;
+               return munger.getSourceLocation(); //XXX
        }
 
        public boolean matches(ResolvedTypeX onType) {
index c0ffeae4026f191095f2acb78540c54df91507e5..cb2fe93c33f053d35f246e523baac44ab8288a42 100644 (file)
@@ -20,6 +20,10 @@ import org.aspectj.bridge.ISourceLocation;
  */
 public interface ICrossReferenceHandler {
 
-       void addCrossReference(ISourceLocation from, ISourceLocation to, IRelationship.Kind kind);
+       void addCrossReference(
+         ISourceLocation from, 
+         ISourceLocation to,
+         IRelationship.Kind kind,
+         boolean runtimeTest);
        
 }
index 0f4ac0fb735e66d95a2849e856be8bfa6f956182..699ed973659298022aab7f87a84ea602fbc16ad4 100644 (file)
@@ -49,14 +49,17 @@ public class NewConstructorTypeMunger extends ResolvedTypeMunger {
                syntheticConstructor.write(s);
                explicitConstructor.write(s);
                writeSuperMethodsCalled(s);
+               if (ResolvedTypeMunger.persistSourceLocation) writeSourceLocation(s);
        }
        
        public static ResolvedTypeMunger readConstructor(DataInputStream s, ISourceContext context) throws IOException {
-               return new NewConstructorTypeMunger(
+               ResolvedTypeMunger munger = new NewConstructorTypeMunger(
                                ResolvedMember.readResolvedMember(s, context),
                                ResolvedMember.readResolvedMember(s, context),
                                ResolvedMember.readResolvedMember(s, context),
                                readSuperMethodsCalled(s));
+               if (ResolvedTypeMunger.persistSourceLocation) munger.setSourceLocation(readSourceLocation(s));
+               return munger;
        }
 
        public ResolvedMember getExplicitConstructor() {
index 8733a3b8d00c56d3e82b7c215502dfe82f3cfb53..3ef81e57b5afa0463dc68686bcf00ea848f2ba0f 100644 (file)
@@ -32,12 +32,15 @@ public class NewFieldTypeMunger extends ResolvedTypeMunger {
                kind.write(s);
                signature.write(s);
                writeSuperMethodsCalled(s);
+               if (ResolvedTypeMunger.persistSourceLocation) writeSourceLocation(s);
        }
 
        public static ResolvedTypeMunger readField(DataInputStream s, ISourceContext context) throws IOException {
-               return new NewFieldTypeMunger(
+               ResolvedTypeMunger munger = new NewFieldTypeMunger(
                        ResolvedMember.readResolvedMember(s, context),
                        readSuperMethodsCalled(s));
+               if (ResolvedTypeMunger.persistSourceLocation) munger.setSourceLocation(readSourceLocation(s));
+               return munger;
        }
        
        public ResolvedMember getMatchingSyntheticMember(Member member, ResolvedTypeX aspectType) {
index 92fcb2c8e4700f4f4b17d0696132979379d21ac4..f42f744585a8bdcb2e002fac3cd74339a209e4e2 100644 (file)
@@ -37,12 +37,15 @@ public class NewMethodTypeMunger extends ResolvedTypeMunger {
                kind.write(s);
                signature.write(s);
                writeSuperMethodsCalled(s);
+               if (ResolvedTypeMunger.persistSourceLocation) writeSourceLocation(s);
        }
        
        public static ResolvedTypeMunger readMethod(DataInputStream s, ISourceContext context) throws IOException {
-               return new NewMethodTypeMunger(
+               ResolvedTypeMunger munger = new NewMethodTypeMunger(
                                ResolvedMember.readResolvedMember(s, context),
                                readSuperMethodsCalled(s));
+               if (ResolvedTypeMunger.persistSourceLocation) munger.setSourceLocation(readSourceLocation(s));
+               return munger;
        }
        
        public ResolvedMember getMatchingSyntheticMember(Member member, ResolvedTypeX aspectType) {     
index 55e0a4e3e58601ba1c85a1fc1bee55e41b7f1a31..aa1ff72232198474668eaac8e58c12be230e9653 100644 (file)
@@ -15,7 +15,10 @@ package org.aspectj.weaver;
 
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
+import java.io.File;
 import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -23,6 +26,8 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.SourceLocation;
 import org.aspectj.util.TypeSafeEnum;
 
 /** This is an abstraction over method/field introduction.  It might not have the chops
@@ -33,12 +38,24 @@ public abstract class ResolvedTypeMunger {
        protected Kind kind;
        protected ResolvedMember signature;
        
+       public static transient boolean persistSourceLocation = false;
+       
        private Set /* resolvedMembers */ superMethodsCalled = Collections.EMPTY_SET;
+       
+       private ISourceLocation location; // Lost during serialize/deserialize !
 
        public ResolvedTypeMunger(Kind kind, ResolvedMember signature) {
                this.kind = kind;
                this.signature = signature;
        }
+       
+       public void setSourceLocation(ISourceLocation isl) {
+               location = isl;
+       }
+       
+       public ISourceLocation getSourceLocation() {
+               return location;
+       }
 
        // ----
 
@@ -95,7 +112,10 @@ public abstract class ResolvedTypeMunger {
                }
        }
 
+
+       
        protected static Set readSuperMethodsCalled(DataInputStream s) throws IOException {
+               
                Set ret = new HashSet();
                int n = s.readInt();
                for (int i=0; i < n; i++) {
@@ -105,6 +125,7 @@ public abstract class ResolvedTypeMunger {
        }
        
        protected void writeSuperMethodsCalled(DataOutputStream s) throws IOException {
+               
                if (superMethodsCalled == null) {
                        s.writeInt(0);
                        return;
@@ -118,6 +139,40 @@ public abstract class ResolvedTypeMunger {
                        ResolvedMember m = (ResolvedMember)i.next();
                        m.write(s);
                }
+               
+       }
+
+       protected static ISourceLocation readSourceLocation(DataInputStream s) throws IOException {
+               if (!persistSourceLocation) return null;
+               ISourceLocation ret = null;
+               ObjectInputStream ois = new ObjectInputStream(s);
+               try {
+                       Boolean validLocation = (Boolean)ois.readObject();
+                       if (validLocation.booleanValue()) {
+                               File f     = (File) ois.readObject();
+                               Integer ii = (Integer)ois.readObject();
+                               ret = new SourceLocation(f,ii.intValue());
+                       }
+               } catch (IOException ioe) {
+                       // Something went wrong, maybe this is an 'old style' file that doesnt attach locations to mungers
+                       ioe.printStackTrace();
+                       return null;
+               } catch (ClassNotFoundException e) { }
+               ois.close();
+               return ret;
+       }
+       
+       protected void writeSourceLocation(DataOutputStream s) throws IOException {     
+               if (!persistSourceLocation) return;
+               ObjectOutputStream oos = new ObjectOutputStream(s);
+               // oos.writeObject(location);
+               oos.writeObject(new Boolean(location!=null));
+               if (location !=null) {
+                 oos.writeObject(location.getSourceFile());
+                 oos.writeObject(new Integer(location.getLine()));
+               }
+               oos.flush();
+               oos.close();
        }
 
        
index 42e2920e4cf0476ca5f00df45636df73e6946f53..b34f62e7ea1b08fe2aec801eabf0ddbbe7aa18b3 100644 (file)
@@ -26,6 +26,7 @@ import org.aspectj.lang.JoinPoint;
 import org.aspectj.util.PartialOrder;
 import org.aspectj.util.TypeSafeEnum;
 import org.aspectj.weaver.ast.Var;
+import org.aspectj.weaver.bcel.BcelAdvice;
 
 /*
  * The superclass of anything representing a the shadow of a join point.  A shadow represents
@@ -345,6 +346,89 @@ public abstract class Shadow {
        protected void prepareForMungers() {
                throw new RuntimeException("Generic shadows cannot be prepared");               
        }
+       
+       /*
+        * Ensure we report a nice source location - particular in the case
+        * where the source info is missing (binary weave).
+        */
+       private String beautifyLocation(ISourceLocation isl) {
+               StringBuffer nice = new StringBuffer();
+               if (isl==null || isl.getSourceFile()==null || isl.getSourceFile().getName().indexOf("no debug info available")!=-1) {
+                       nice.append("no debug info available");
+           } else {
+               nice.append(isl.getSourceFile().getName());
+               if (isl.getLine()!=0) nice.append(":").append(isl.getLine());
+               }
+               return nice.toString();
+       }
+       
+       /*
+        * Report a message about the advice weave that has occurred.  Some messing about
+        * to make it pretty !  This code is just asking for an NPE to occur ...
+        */
+       private void reportWeavingMessage(ShadowMunger munger) {
+               Advice advice = (Advice)munger;
+               AdviceKind aKind = advice.getKind();
+               // Only report on interesting advice kinds ...
+               if (aKind == null || advice.getConcreteAspect()==null) {
+                       // We suspect someone is programmatically driving the weaver 
+                       // (e.g. IdWeaveTestCase in the weaver testcases)
+                       return;
+               }
+               if (!( aKind.equals(AdviceKind.Before) ||
+                      aKind.equals(AdviceKind.After) ||
+                      aKind.equals(AdviceKind.AfterReturning) ||
+                      aKind.equals(AdviceKind.AfterThrowing) ||
+                      aKind.equals(AdviceKind.Around) ||
+                      aKind.equals(AdviceKind.Softener))) return;
+               
+               String description = advice.getKind().toString();
+               String advisedType = this.getEnclosingType().getName();
+               String advisingType= advice.getConcreteAspect().getName();
+               Message msg = null;
+               if (advice.getKind().equals(AdviceKind.Softener)) {
+                       msg = WeaveMessage.constructWeavingMessage(
+                         WeaveMessage.WEAVEMESSAGE_SOFTENS,
+                           new String[]{advisedType,beautifyLocation(getSourceLocation()),
+                                                advisingType,beautifyLocation(munger.getSourceLocation())});
+               } else {
+                       boolean runtimeTest = ((BcelAdvice)advice).hasDynamicTests();
+                   msg = WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ADVISES,
+                         new String[]{ advisedType, beautifyLocation(getSourceLocation()),
+                                           description,
+                                           advisingType,beautifyLocation(munger.getSourceLocation()),
+                                           (runtimeTest?" [with runtime test]":"")});
+                                        // Boolean.toString(runtimeTest)});
+               }
+               getIWorld().getMessageHandler().handleMessage(msg);
+       }
+
+
+       public IRelationship.Kind determineRelKind(ShadowMunger munger) {
+               AdviceKind ak = ((Advice)munger).getKind();
+               if (ak.getKey()==AdviceKind.Before.getKey()) 
+                               return IRelationship.Kind.ADVICE_BEFORE;
+               else if (ak.getKey()==AdviceKind.After.getKey())
+                               return IRelationship.Kind.ADVICE_AFTER;
+               else if (ak.getKey()==AdviceKind.AfterThrowing.getKey())
+                               return IRelationship.Kind.ADVICE_AFTERTHROWING;
+               else if (ak.getKey()==AdviceKind.AfterReturning.getKey())
+                               return IRelationship.Kind.ADVICE_AFTERRETURNING;
+               else if (ak.getKey()==AdviceKind.Around.getKey())
+                               return IRelationship.Kind.ADVICE_AROUND;
+               else if (ak.getKey()==AdviceKind.CflowEntry.getKey() ||
+               ak.getKey()==AdviceKind.CflowBelowEntry.getKey() ||
+               ak.getKey()==AdviceKind.InterInitializer.getKey() ||
+               ak.getKey()==AdviceKind.PerCflowEntry.getKey() ||
+               ak.getKey()==AdviceKind.PerCflowBelowEntry.getKey() ||
+               ak.getKey()==AdviceKind.PerThisEntry.getKey() ||
+               ak.getKey()==AdviceKind.PerTargetEntry.getKey() ||
+               ak.getKey()==AdviceKind.Softener.getKey()) {
+                         System.err.println("Dont want a message about this: "+ak);
+                         return null;
+               }
+               throw new RuntimeException("Shadow.determineRelKind: What the hell is it? "+ak);
+       }
 
        /** Actually implement the (non-empty) mungers associated with this shadow */
        private void implementMungers() {
@@ -354,9 +438,19 @@ public abstract class Shadow {
                        munger.implementOn(this);
                        
                        if (world.xrefHandler != null) {
-                               world.xrefHandler.addCrossReference(munger.getSourceLocation(),this.getSourceLocation(),IRelationship.Kind.ADVICE);
+                               world.xrefHandler.addCrossReference(
+                                 munger.getSourceLocation(), // What is being applied
+                                 this.getSourceLocation(),   // Where is it being applied
+                                 determineRelKind(munger),   // What kind of advice?
+                                 ((BcelAdvice)munger).hasDynamicTests() // Is a runtime test being stuffed in the code?
+                                 );
                        }
                        
+                       // TAG: WeavingMessage
+                       if (!getIWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) {
+                               reportWeavingMessage(munger);
+                       }                       
+                       
                        if (world.getModel() != null) {
                                //System.err.println("munger: " + munger + " on " + this);
                                AsmRelationshipProvider.adviceMunger(world.getModel(), this, munger);
diff --git a/weaver/src/org/aspectj/weaver/WeaverMetrics.java b/weaver/src/org/aspectj/weaver/WeaverMetrics.java
new file mode 100644 (file)
index 0000000..113be29
--- /dev/null
@@ -0,0 +1,85 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * 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 org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.patterns.FastMatchInfo;
+
+
+/**
+ * Records stats about the weaver.  Information like 'how many types are dismissed during fast match' that
+ * may be useful for trying to tune pointcuts.  Not publicised.
+ */
+public class WeaverMetrics {
+    
+       // Level 1 of matching is at the type level, which types can be dismissed?
+       public static int fastMatchOnTypeAttempted = 0;
+       public static int fastMatchOnTypeTrue = 0;
+       public static int fastMatchOnTypeFalse = 0;
+
+       // Level 2 of matching is fast matching on the shadows in the remaining types
+       public static int fastMatchOnShadowsAttempted = 0;
+       public static int fastMatchOnShadowsTrue = 0;
+       public static int fastMatchOnShadowsFalse = 0;
+       
+    // Level 3 of matching is slow matching on the shadows (more shadows than were fast matched on!)
+       public static int matchTrue = 0;
+       public static int matchAttempted = 0;
+
+
+       
+       public static void reset() {
+
+               fastMatchOnShadowsAttempted = 0;
+               fastMatchOnShadowsTrue = 0;
+               fastMatchOnShadowsFalse = 0;
+
+               fastMatchOnTypeAttempted = 0;
+               fastMatchOnTypeTrue = 0;
+               fastMatchOnTypeFalse = 0;
+       
+               matchTrue = 0;
+               matchAttempted = 0;
+       }       
+
+       
+       public static void dumpInfo() {
+               System.err.println("Match summary:");
+               int fastMatchOnTypeMaybe = (fastMatchOnTypeAttempted-fastMatchOnTypeTrue-fastMatchOnTypeFalse);
+               System.err.print("At the type level, we attempted #"+fastMatchOnTypeAttempted+" fast matches:");
+               System.err.println("   YES/NO/MAYBE = "+fastMatchOnTypeTrue+"/"+fastMatchOnTypeFalse+"/"+fastMatchOnTypeMaybe);
+               int fastMatchMaybe = (fastMatchOnShadowsAttempted-fastMatchOnShadowsFalse-fastMatchOnShadowsTrue);
+               System.err.print("Within those #"+(fastMatchOnTypeTrue+fastMatchOnTypeMaybe)+" possible types, ");
+               System.err.print("we fast matched on #"+fastMatchOnShadowsAttempted+" shadows:");
+               System.err.println("   YES/NO/MAYBE = "+fastMatchOnShadowsTrue+"/"+fastMatchOnShadowsFalse+"/"+fastMatchMaybe);
+               System.err.println("Shadow (non-fast) matches attempted #"+matchAttempted+" of which "+matchTrue+" successful");
+       }
+       
+
+       public static void recordFastMatchTypeResult(FuzzyBoolean fb) {
+               fastMatchOnTypeAttempted++;
+               if (fb.alwaysTrue()) fastMatchOnTypeTrue++;
+               if (fb.alwaysFalse()) fastMatchOnTypeFalse++;
+       }
+       
+       public static void recordFastMatchResult(FuzzyBoolean fb) {
+               fastMatchOnShadowsAttempted++;
+               if (fb.alwaysTrue())  fastMatchOnShadowsTrue++;
+               if (fb.alwaysFalse()) fastMatchOnShadowsFalse++;
+       }
+       
+       public static void recordMatchResult(boolean b) {
+               matchAttempted++;
+               if (b) matchTrue++;
+       }
+
+}
index ad561a98e378e4fc0970d3d71d082b08fc313029..92e83c8744bd11f3ac159cc9fe2c942bef5744c6 100644 (file)
@@ -48,6 +48,7 @@ import org.apache.bcel.generic.ReturnInstruction;
 import org.apache.bcel.generic.Select;
 import org.apache.bcel.generic.Type;
 import org.aspectj.bridge.IMessage;
+import org.aspectj.util.FuzzyBoolean;
 import org.aspectj.util.PartialOrder;
 import org.aspectj.weaver.AjAttribute;
 import org.aspectj.weaver.AjcMemberMaker;
@@ -56,6 +57,7 @@ import org.aspectj.weaver.ConcreteTypeMunger;
 import org.aspectj.weaver.IClassWeaver;
 import org.aspectj.weaver.IntMap;
 import org.aspectj.weaver.Member;
+import org.aspectj.weaver.WeaverMetrics;
 import org.aspectj.weaver.NameMangler;
 import org.aspectj.weaver.NewFieldTypeMunger;
 import org.aspectj.weaver.ResolvedMember;
@@ -172,7 +174,9 @@ class BcelClassWeaver implements IClassWeaver {
                FastMatchInfo info = new FastMatchInfo(clazz.getType(), kind);
                for (Iterator i = shadowMungers.iterator(); i.hasNext();) {
                        ShadowMunger munger = (ShadowMunger) i.next();
-                       if (munger.getPointcut().fastMatch(info).maybeTrue()) mungers.add(munger);
+                       FuzzyBoolean fb = munger.getPointcut().fastMatch(info);
+                       WeaverMetrics.recordFastMatchResult(fb);// Could pass: munger.getPointcut().toString()
+                       if (fb.maybeTrue()) mungers.add(munger);
                }
        }
 
@@ -1120,13 +1124,19 @@ class BcelClassWeaver implements IClassWeaver {
         for (Iterator i = shadowMungers.iterator(); i.hasNext(); ) {
             ShadowMunger munger = (ShadowMunger)i.next();
             if (munger.match(shadow, world)) {
+               
+                               WeaverMetrics.recordMatchResult(true);// Could pass: munger
                 shadow.addMunger(munger);
                 isMatched = true;
                            if (shadow.getKind() == Shadow.StaticInitialization) {
                                  clazz.warnOnAddedStaticInitializer(shadow,munger.getSourceLocation());
                            }
-            }
+                               
+            } else {
+               WeaverMetrics.recordMatchResult(false); // Could pass: munger
+               }
         }       
+
         if (isMatched) shadowAccumulator.add(shadow);
         return isMatched;
     }
index 2fef3a0c1a6f63e9609208aa6fb024ec8065f3e1..4d031bcb99a467c7dfc30ecb50236d975dc1180f 100644 (file)
@@ -23,7 +23,10 @@ import org.apache.bcel.generic.InstructionConstants;
 import org.apache.bcel.generic.InstructionFactory;
 import org.apache.bcel.generic.InstructionList;
 import org.apache.bcel.generic.Type;
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.WeaveMessage;
 import org.aspectj.weaver.AjcMemberMaker;
+import org.aspectj.weaver.AsmRelationshipProvider;
 import org.aspectj.weaver.ConcreteTypeMunger;
 import org.aspectj.weaver.Member;
 import org.aspectj.weaver.NameMangler;
@@ -54,6 +57,7 @@ public class BcelTypeMunger extends ConcreteTypeMunger {
 
        public boolean munge(BcelClassWeaver weaver) {
                boolean changed = false;
+               boolean worthReporting = true;
                
                if (munger.getKind() == ResolvedTypeMunger.Field) {
                        changed = mungeNewField(weaver, (NewFieldTypeMunger)munger);
@@ -61,8 +65,10 @@ public class BcelTypeMunger extends ConcreteTypeMunger {
                        changed = mungeNewMethod(weaver, (NewMethodTypeMunger)munger);
                } else if (munger.getKind() == ResolvedTypeMunger.PerObjectInterface) {
                        changed = mungePerObjectInterface(weaver, (PerObjectInterfaceTypeMunger)munger);
+                       worthReporting = false;
                } else if (munger.getKind() == ResolvedTypeMunger.PrivilegedAccess) {
                        changed = mungePrivilegedAccess(weaver, (PrivilegedAccessMunger)munger);
+                       worthReporting = false;
                } else if (munger.getKind() == ResolvedTypeMunger.Constructor) {
                        changed = mungeNewConstructor(weaver, (NewConstructorTypeMunger)munger);
                } else if (munger.getKind() == ResolvedTypeMunger.Parent) {
@@ -76,6 +82,43 @@ public class BcelTypeMunger extends ConcreteTypeMunger {
                                weaver.getLazyClassGen().getOrCreateWeaverStateInfo();
                        info.addConcreteMunger(this);
                }
+               // Whilst type mungers aren't persisting their source locations, we add this relationship during
+               // compilation time (see other reference to ResolvedTypeMunger.persist)
+               if (ResolvedTypeMunger.persistSourceLocation) {
+                       if (changed) {
+                               if (munger.getKind().equals(ResolvedTypeMunger.Parent)) {
+                                 AsmRelationshipProvider.addRelationship(weaver.getLazyClassGen().getType(), munger,getAspectType());
+                               } else {
+                                 AsmRelationshipProvider.addRelationship(weaver.getLazyClassGen().getType(), munger,getAspectType());  
+                               }
+                       }
+               }
+               
+               // TAG: WeavingMessage
+               if (worthReporting  && munger!=null && !weaver.getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) {
+                       String tName = weaver.getLazyClassGen().getType().getSourceLocation().getSourceFile().getName();
+                       if (tName.indexOf("no debug info available")!=-1) tName = "no debug info available";
+                       String fName = getAspectType().getSourceLocation().getSourceFile().getName();
+               if (munger.getKind().equals(ResolvedTypeMunger.Parent)) {
+                       // This message will come out of AjLookupEnvironment.addParent if doing a source
+                       // compilation.
+                       NewParentTypeMunger parentTM = (NewParentTypeMunger)munger;
+                       if (parentTM.getNewParent().isInterface()) {
+                                       weaver.getWorld().getMessageHandler().handleMessage(WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_DECLAREPARENTSIMPLEMENTS,
+                                       new String[]{weaver.getLazyClassGen().getType().getName(),
+                                       tName,parentTM.getNewParent().getName(),fName}));
+                       } else {
+                               System.err.println("BANG, you need to fix this.  BcelTypeMunger");
+                       }
+               } else {
+                       weaver.getWorld().getMessageHandler().handleMessage(WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ITD,
+                       new String[]{weaver.getLazyClassGen().getType().getName(),
+                                        tName,munger.getKind().toString().toLowerCase(),
+                                        getAspectType().getName(),
+                                                fName+":'"+munger.getSignature()+"'"}));
+                               // ??? If only type mungers knew their originating line numbers ...
+               }       
+               }
                
                return changed;
        }
index 19beb0f6237e42b5f6b9cd3b9b7ff63be77ce19e..653510ddd0c8a21eb02ab2e643b0e5956b41cc0e 100644 (file)
@@ -48,11 +48,13 @@ import org.aspectj.bridge.IProgressListener;
 import org.aspectj.bridge.Message;
 import org.aspectj.bridge.SourceLocation;
 import org.aspectj.util.FileUtil;
+import org.aspectj.util.FuzzyBoolean;
 import org.aspectj.weaver.ConcreteTypeMunger;
 import org.aspectj.weaver.CrosscuttingMembersSet;
 import org.aspectj.weaver.IClassFileProvider;
 import org.aspectj.weaver.IWeaveRequestor;
 import org.aspectj.weaver.IWeaver;
+import org.aspectj.weaver.WeaverMetrics;
 import org.aspectj.weaver.NewParentTypeMunger;
 import org.aspectj.weaver.ResolvedTypeMunger;
 import org.aspectj.weaver.ResolvedTypeX;
@@ -75,6 +77,7 @@ public class BcelWeaver implements IWeaver {
     
     public BcelWeaver(BcelWorld world) {
         super();
+        WeaverMetrics.reset();
         this.world = world;
         this.xcutSet = world.getCrosscuttingMembersSet();
     }
@@ -815,7 +818,9 @@ public class BcelWeaver implements IWeaver {
                Iterator iter = list.iterator();
                while (iter.hasNext()) {
                        ShadowMunger munger = (ShadowMunger)iter.next();
-                       if (munger.getPointcut().fastMatch(info).maybeTrue()) {
+                       FuzzyBoolean fb = munger.getPointcut().fastMatch(info);
+                       WeaverMetrics.recordFastMatchTypeResult(fb); // Could pass: munger.getPointcut().toString(),info
+                       if (fb.maybeTrue()) {
                                result.add(munger);
                        }
                }
index c2b6121d0add85afdbbf2fd9c72fb44cfd190fc5..8d5434f279cb5a480b2f0af799a701d7f9e76fbd 100644 (file)
@@ -39,5 +39,9 @@ public class FastMatchInfo {
        public ResolvedTypeX getType() {
                return type;
        }
+       
+       public String toString() {
+               return "FastMatchInfo [type="+type.getName()+"] ["+(kind==null?"AllKinds":"Kind="+kind)+"]";
+       }
 
 }