From 2982b4cc622a2a95429b16f0aa3c55b7e20d798a Mon Sep 17 00:00:00 2001 From: aclement Date: Tue, 3 Aug 2004 12:31:29 +0000 Subject: [PATCH] The BIG commit. - 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) --- .../ajde/internal/CompilerAdapter.java | 34 +- .../aspectj/ajde/ui/StructureModelUtil.java | 58 ++- .../ajde/ui/StructureViewNodeFactory.java | 4 +- ajde/testsrc/org/aspectj/ajde/AjdeTests.java | 1 + .../org/aspectj/ajde/AsmDeclarationsTest.java | 10 +- .../aspectj/ajde/AsmRelationshipsTest.java | 7 +- .../org/aspectj/ajde/BuildCancellingTest.java | 78 +-- .../ajde/ShowWeaveMessagesTestCase.java | 376 ++++++++++++++ asm/src/org/aspectj/asm/AsmManager.java | 486 +++++++++++++++++- asm/src/org/aspectj/asm/IHierarchy.java | 5 + asm/src/org/aspectj/asm/IProgramElement.java | 17 + asm/src/org/aspectj/asm/IRelationship.java | 24 +- asm/src/org/aspectj/asm/IRelationshipMap.java | 21 +- .../asm/internal/AspectJElementHierarchy.java | 28 +- .../aspectj/asm/internal/ProgramElement.java | 48 +- .../aspectj/asm/internal/Relationship.java | 17 +- .../aspectj/asm/internal/RelationshipMap.java | 71 ++- bridge/src/org/aspectj/bridge/IMessage.java | 6 +- bridge/src/org/aspectj/bridge/Message.java | 34 +- .../org/aspectj/bridge/MessageHandler.java | 3 + .../src/org/aspectj/bridge/WeaveMessage.java | 75 +++ .../org/aspectj/ajdt/ajc/BuildArgParser.java | 16 + .../org/aspectj/ajdt/ajc/messages.properties | 1 + .../compiler/WeaverMessageHandler.java | 12 +- .../compiler/lookup/AjLookupEnvironment.java | 76 ++- .../AsmInterTypeRelationshipProvider.java | 8 +- .../compiler/lookup/EclipseTypeMunger.java | 3 + .../internal/core/builder/AjBuildConfig.java | 17 + .../internal/core/builder/AjBuildManager.java | 99 +++- .../core/builder/AjCompilerOptions.java | 1 + .../core/builder/AsmElementFormatter.java | 48 +- .../core/builder/AsmHierarchyBuilder.java | 137 +++-- .../core/builder/EclipseAdapterUtils.java | 15 +- .../src/org/aspectj/tools/ajc/Main.java | 8 +- .../compiler/batch/BcweaverJarMaker.java | 36 +- .../harness/bridge/IncCompilerRun.java | 17 +- .../org/aspectj/testing/xml/SoftMessage.java | 2 + tests/ajcTestSuite.dtd | 1 + tests/incModelTests.xml | 102 ++++ .../model/intertype/primary/Alpha.java | 7 + .../model/intertype/secondary/BetaA.20.java | 8 + .../model/intertype/secondary/BetaA.30.java | 7 + .../introduction/CloneablePoint.20.java | 42 ++ .../introduction/CloneablePoint.java | 42 ++ .../introduction/ComparablePoint.java | 46 ++ .../introduction/HashablePoint.30.java | 47 ++ .../introduction/HashablePoint.java | 47 ++ .../introduction/introduction/Point.30.java | 98 ++++ .../introduction/introduction/Point.java | 98 ++++ .../sourcefiles_addremove/primary/Alpha.java | 7 + .../primary/Beta.20.java | 11 + .../primary/Beta.delete.60.java | 11 + .../secondary/Delta.40.java | 5 + .../secondary/Delta.delete.60.java | 5 + .../secondary/Gamma.30.java | 7 + .../secondary/Gamma.delete.50.java | 7 + .../sourcefiles_updating/primary/Alpha.java | 7 + .../sourcefiles_updating/primary/Beta.20.java | 13 + .../sourcefiles_updating/primary/Beta.java | 7 + .../secondary/Delta.30.java | 10 + .../sourcefiles_updating/secondary/Delta.java | 5 + .../secondary/Gamma.40.java | 10 + .../secondary/Gamma.50.java | 13 + .../secondary/Gamma.60.java | 8 + .../sourcefiles_updating/secondary/Gamma.java | 7 + .../model/weaving/primary/Alpha.java | 21 + .../model/weaving/primary/BetaA.20.java | 16 + .../model/weaving/primary/BetaA.30.java | 10 + .../model/weaving/primary/BetaA.40.java | 5 + .../model/weaving/primary/BetaA.java | 10 + .../model/weaving2/primary/Alpha.java | 11 + .../model/weaving2/primary/BetaA.20.java | 8 + .../weaving2/primary/BetaA.delete.40.java | 8 + .../model/weaving2/primary/BetaA.java | 4 + .../model/weaving2/secondary/GammaA.30.java | 8 + .../weaver/AsmRelationshipProvider.java | 110 +++- weaver/src/org/aspectj/weaver/Checker.java | 10 +- .../aspectj/weaver/ConcreteTypeMunger.java | 3 +- .../weaver/ICrossReferenceHandler.java | 6 +- .../weaver/NewConstructorTypeMunger.java | 5 +- .../aspectj/weaver/NewFieldTypeMunger.java | 5 +- .../aspectj/weaver/NewMethodTypeMunger.java | 5 +- .../aspectj/weaver/ResolvedTypeMunger.java | 55 ++ weaver/src/org/aspectj/weaver/Shadow.java | 96 +++- .../src/org/aspectj/weaver/WeaverMetrics.java | 85 +++ .../aspectj/weaver/bcel/BcelClassWeaver.java | 14 +- .../aspectj/weaver/bcel/BcelTypeMunger.java | 43 ++ .../org/aspectj/weaver/bcel/BcelWeaver.java | 7 +- .../weaver/patterns/FastMatchInfo.java | 4 + 89 files changed, 2900 insertions(+), 226 deletions(-) create mode 100644 ajde/testsrc/org/aspectj/ajde/ShowWeaveMessagesTestCase.java create mode 100644 bridge/src/org/aspectj/bridge/WeaveMessage.java create mode 100644 tests/incModelTests.xml create mode 100644 tests/incremental/model/intertype/primary/Alpha.java create mode 100644 tests/incremental/model/intertype/secondary/BetaA.20.java create mode 100644 tests/incremental/model/intertype/secondary/BetaA.30.java create mode 100644 tests/incremental/model/introduction/introduction/CloneablePoint.20.java create mode 100644 tests/incremental/model/introduction/introduction/CloneablePoint.java create mode 100644 tests/incremental/model/introduction/introduction/ComparablePoint.java create mode 100644 tests/incremental/model/introduction/introduction/HashablePoint.30.java create mode 100644 tests/incremental/model/introduction/introduction/HashablePoint.java create mode 100644 tests/incremental/model/introduction/introduction/Point.30.java create mode 100644 tests/incremental/model/introduction/introduction/Point.java create mode 100644 tests/incremental/model/sourcefiles_addremove/primary/Alpha.java create mode 100644 tests/incremental/model/sourcefiles_addremove/primary/Beta.20.java create mode 100644 tests/incremental/model/sourcefiles_addremove/primary/Beta.delete.60.java create mode 100644 tests/incremental/model/sourcefiles_addremove/secondary/Delta.40.java create mode 100644 tests/incremental/model/sourcefiles_addremove/secondary/Delta.delete.60.java create mode 100644 tests/incremental/model/sourcefiles_addremove/secondary/Gamma.30.java create mode 100644 tests/incremental/model/sourcefiles_addremove/secondary/Gamma.delete.50.java create mode 100644 tests/incremental/model/sourcefiles_updating/primary/Alpha.java create mode 100644 tests/incremental/model/sourcefiles_updating/primary/Beta.20.java create mode 100644 tests/incremental/model/sourcefiles_updating/primary/Beta.java create mode 100644 tests/incremental/model/sourcefiles_updating/secondary/Delta.30.java create mode 100644 tests/incremental/model/sourcefiles_updating/secondary/Delta.java create mode 100644 tests/incremental/model/sourcefiles_updating/secondary/Gamma.40.java create mode 100644 tests/incremental/model/sourcefiles_updating/secondary/Gamma.50.java create mode 100644 tests/incremental/model/sourcefiles_updating/secondary/Gamma.60.java create mode 100644 tests/incremental/model/sourcefiles_updating/secondary/Gamma.java create mode 100644 tests/incremental/model/weaving/primary/Alpha.java create mode 100644 tests/incremental/model/weaving/primary/BetaA.20.java create mode 100644 tests/incremental/model/weaving/primary/BetaA.30.java create mode 100644 tests/incremental/model/weaving/primary/BetaA.40.java create mode 100644 tests/incremental/model/weaving/primary/BetaA.java create mode 100644 tests/incremental/model/weaving2/primary/Alpha.java create mode 100644 tests/incremental/model/weaving2/primary/BetaA.20.java create mode 100644 tests/incremental/model/weaving2/primary/BetaA.delete.40.java create mode 100644 tests/incremental/model/weaving2/primary/BetaA.java create mode 100644 tests/incremental/model/weaving2/secondary/GammaA.30.java create mode 100644 weaver/src/org/aspectj/weaver/WeaverMetrics.java diff --git a/ajde/src/org/aspectj/ajde/internal/CompilerAdapter.java b/ajde/src/org/aspectj/ajde/internal/CompilerAdapter.java index 34637e24f..f98e08c0e 100644 --- a/ajde/src/org/aspectj/ajde/internal/CompilerAdapter.java +++ b/ajde/src/org/aspectj/ajde/internal/CompilerAdapter.java @@ -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 diff --git a/ajde/src/org/aspectj/ajde/ui/StructureModelUtil.java b/ajde/src/org/aspectj/ajde/ui/StructureModelUtil.java index fcc039e21..d9b1e8c97 100644 --- a/ajde/src/org/aspectj/ajde/ui/StructureModelUtil.java +++ b/ajde/src/org/aspectj/ajde/ui/StructureModelUtil.java @@ -14,17 +14,69 @@ 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. diff --git a/ajde/src/org/aspectj/ajde/ui/StructureViewNodeFactory.java b/ajde/src/org/aspectj/ajde/ui/StructureViewNodeFactory.java index 4f32eedc7..2e6693d56 100644 --- a/ajde/src/org/aspectj/ajde/ui/StructureViewNodeFactory.java +++ b/ajde/src/org/aspectj/ajde/ui/StructureViewNodeFactory.java @@ -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(); ) { diff --git a/ajde/testsrc/org/aspectj/ajde/AjdeTests.java b/ajde/testsrc/org/aspectj/ajde/AjdeTests.java index e70619504..a2155fd9b 100644 --- a/ajde/testsrc/org/aspectj/ajde/AjdeTests.java +++ b/ajde/testsrc/org/aspectj/ajde/AjdeTests.java @@ -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; diff --git a/ajde/testsrc/org/aspectj/ajde/AsmDeclarationsTest.java b/ajde/testsrc/org/aspectj/ajde/AsmDeclarationsTest.java index d5902854b..bcf70db2e 100644 --- a/ajde/testsrc/org/aspectj/ajde/AsmDeclarationsTest.java +++ b/ajde/testsrc/org/aspectj/ajde/AsmDeclarationsTest.java @@ -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: "; - 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"); diff --git a/ajde/testsrc/org/aspectj/ajde/AsmRelationshipsTest.java b/ajde/testsrc/org/aspectj/ajde/AsmRelationshipsTest.java index 407ad1004..64b365276 100644 --- a/ajde/testsrc/org/aspectj/ajde/AsmRelationshipsTest.java +++ b/ajde/testsrc/org/aspectj/ajde/AsmRelationshipsTest.java @@ -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); // diff --git a/ajde/testsrc/org/aspectj/ajde/BuildCancellingTest.java b/ajde/testsrc/org/aspectj/ajde/BuildCancellingTest.java index 5d07718e1..007727ea1 100644 --- a/ajde/testsrc/org/aspectj/ajde/BuildCancellingTest.java +++ b/ajde/testsrc/org/aspectj/ajde/BuildCancellingTest.java @@ -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 index 000000000..8127ad3cb --- /dev/null +++ b/ajde/testsrc/org/aspectj/ajde/ShowWeaveMessagesTestCase.java @@ -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); + } + } + + + +} diff --git a/asm/src/org/aspectj/asm/AsmManager.java b/asm/src/org/aspectj/asm/AsmManager.java index 91a166af6..0177bb4c2 100644 --- a/asm/src/org/aspectj/asm/AsmManager.java +++ b/asm/src/org/aspectj/asm/AsmManager.java @@ -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 ;i0) { + // 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 ;iFirst: 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. + *

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 ;iinjar 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; + } + } diff --git a/asm/src/org/aspectj/asm/internal/Relationship.java b/asm/src/org/aspectj/asm/internal/Relationship.java index 68ee50e3f..c47fb159e 100644 --- a/asm/src/org/aspectj/asm/internal/Relationship.java +++ b/asm/src/org/aspectj/asm/internal/Relationship.java @@ -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; + } } diff --git a/asm/src/org/aspectj/asm/internal/RelationshipMap.java b/asm/src/org/aspectj/asm/internal/RelationshipMap.java index ce05fd5c6..b70887af6 100644 --- a/asm/src/org/aspectj/asm/internal/RelationshipMap.java +++ b/asm/src/org/aspectj/asm/internal/RelationshipMap.java @@ -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(); + } + + } diff --git a/bridge/src/org/aspectj/bridge/IMessage.java b/bridge/src/org/aspectj/bridge/IMessage.java index 2bafc7d7a..fcb807016 100644 --- a/bridge/src/org/aspectj/bridge/IMessage.java +++ b/bridge/src/org/aspectj/bridge/IMessage.java @@ -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(); diff --git a/bridge/src/org/aspectj/bridge/Message.java b/bridge/src/org/aspectj/bridge/Message.java index af032b6de..1ddb18d69 100644 --- a/bridge/src/org/aspectj/bridge/Message.java +++ b/bridge/src/org/aspectj/bridge/Message.java @@ -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 */ diff --git a/bridge/src/org/aspectj/bridge/MessageHandler.java b/bridge/src/org/aspectj/bridge/MessageHandler.java index 6882306e8..7187b2c46 100644 --- a/bridge/src/org/aspectj/bridge/MessageHandler.java +++ b/bridge/src/org/aspectj/bridge/MessageHandler.java @@ -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 index 000000000..e15abeae7 --- /dev/null +++ b/bridge/src/org/aspectj/bridge/WeaveMessage.java @@ -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; } + } +} diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java index 3d795f25f..3928ddc44 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java @@ -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()); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties index 306813e8d..0dd92150a 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties @@ -26,6 +26,7 @@ AspectJ-specific options:\n\ \t ( uses classpath delimiter)\n\ \t-outjar put output classes in zip file \n\ \t-argfile 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 compile all .aj and .java files in \n\ diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverMessageHandler.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverMessageHandler.java index 734fd8816..d7925cb8f 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverMessageHandler.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverMessageHandler.java @@ -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; diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java index 05465c469..6612e66ce 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java @@ -13,25 +13,42 @@ 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); + } } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AsmInterTypeRelationshipProvider.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AsmInterTypeRelationshipProvider.java index 9bb093190..bb97a6ddd 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AsmInterTypeRelationshipProvider.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AsmInterTypeRelationshipProvider.java @@ -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); } } } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseTypeMunger.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseTypeMunger.java index 33a4f2a78..f9300e7cc 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseTypeMunger.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseTypeMunger.java @@ -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); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java index 74f5c4767..34474602d 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java @@ -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; + } } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java index ab428758a..3ca85e0a6 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java @@ -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 = ""; + private void setupModel(AjBuildConfig config) { IHierarchy model = AsmManager.getDefault().getHierarchy(); - AsmManager.getDefault().getRelationshipMap().clear(); + String rootLabel = ""; + + 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")) { +// 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); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java index 3c7ae7c38..f65ad2b3e 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java @@ -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; diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmElementFormatter.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmElementFormatter.java index 1f8a81a7d..4a2620873 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmElementFormatter.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmElementFormatter.java @@ -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)1) { +// +// for (int i = 1;i + diff --git a/tests/incModelTests.xml b/tests/incModelTests.xml new file mode 100644 index 000000000..e8104794e --- /dev/null +++ b/tests/incModelTests.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 index 000000000..4f77e13d2 --- /dev/null +++ b/tests/incremental/model/intertype/primary/Alpha.java @@ -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 index 000000000..abe370ecd --- /dev/null +++ b/tests/incremental/model/intertype/secondary/BetaA.20.java @@ -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 index 000000000..394c7a925 --- /dev/null +++ b/tests/incremental/model/intertype/secondary/BetaA.30.java @@ -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 index 000000000..c34509850 --- /dev/null +++ b/tests/incremental/model/introduction/introduction/CloneablePoint.20.java @@ -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 index 000000000..c34509850 --- /dev/null +++ b/tests/incremental/model/introduction/introduction/CloneablePoint.java @@ -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 index 000000000..a2893dba0 --- /dev/null +++ b/tests/incremental/model/introduction/introduction/ComparablePoint.java @@ -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 index 000000000..39eb33ba4 --- /dev/null +++ b/tests/incremental/model/introduction/introduction/HashablePoint.30.java @@ -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 index 000000000..39eb33ba4 --- /dev/null +++ b/tests/incremental/model/introduction/introduction/HashablePoint.java @@ -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 index 000000000..609a0488c --- /dev/null +++ b/tests/incremental/model/introduction/introduction/Point.30.java @@ -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 index 000000000..609a0488c --- /dev/null +++ b/tests/incremental/model/introduction/introduction/Point.java @@ -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 index 000000000..5e60f4f34 --- /dev/null +++ b/tests/incremental/model/sourcefiles_addremove/primary/Alpha.java @@ -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 index 000000000..1ef401ca8 --- /dev/null +++ b/tests/incremental/model/sourcefiles_addremove/primary/Beta.20.java @@ -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 index 000000000..1ef401ca8 --- /dev/null +++ b/tests/incremental/model/sourcefiles_addremove/primary/Beta.delete.60.java @@ -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 index 000000000..ed410eda9 --- /dev/null +++ b/tests/incremental/model/sourcefiles_addremove/secondary/Delta.40.java @@ -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 index 000000000..ed410eda9 --- /dev/null +++ b/tests/incremental/model/sourcefiles_addremove/secondary/Delta.delete.60.java @@ -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 index 000000000..edbe7169f --- /dev/null +++ b/tests/incremental/model/sourcefiles_addremove/secondary/Gamma.30.java @@ -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 index 000000000..edbe7169f --- /dev/null +++ b/tests/incremental/model/sourcefiles_addremove/secondary/Gamma.delete.50.java @@ -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 index 000000000..5e60f4f34 --- /dev/null +++ b/tests/incremental/model/sourcefiles_updating/primary/Alpha.java @@ -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 index 000000000..4efd977e8 --- /dev/null +++ b/tests/incremental/model/sourcefiles_updating/primary/Beta.20.java @@ -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 index 000000000..86dc7dfd8 --- /dev/null +++ b/tests/incremental/model/sourcefiles_updating/primary/Beta.java @@ -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 index 000000000..f54b3f7f0 --- /dev/null +++ b/tests/incremental/model/sourcefiles_updating/secondary/Delta.30.java @@ -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 index 000000000..ed410eda9 --- /dev/null +++ b/tests/incremental/model/sourcefiles_updating/secondary/Delta.java @@ -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 index 000000000..7e508af0e --- /dev/null +++ b/tests/incremental/model/sourcefiles_updating/secondary/Gamma.40.java @@ -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 index 000000000..a380f8651 --- /dev/null +++ b/tests/incremental/model/sourcefiles_updating/secondary/Gamma.50.java @@ -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 index 000000000..de4cf6d81 --- /dev/null +++ b/tests/incremental/model/sourcefiles_updating/secondary/Gamma.60.java @@ -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 index 000000000..edbe7169f --- /dev/null +++ b/tests/incremental/model/sourcefiles_updating/secondary/Gamma.java @@ -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 index 000000000..e51f9f972 --- /dev/null +++ b/tests/incremental/model/weaving/primary/Alpha.java @@ -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 index 000000000..74ff7481f --- /dev/null +++ b/tests/incremental/model/weaving/primary/BetaA.20.java @@ -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 index 000000000..eeba653b7 --- /dev/null +++ b/tests/incremental/model/weaving/primary/BetaA.30.java @@ -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 index 000000000..706cebb17 --- /dev/null +++ b/tests/incremental/model/weaving/primary/BetaA.40.java @@ -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 index 000000000..333c5f187 --- /dev/null +++ b/tests/incremental/model/weaving/primary/BetaA.java @@ -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 index 000000000..ab7e82c16 --- /dev/null +++ b/tests/incremental/model/weaving2/primary/Alpha.java @@ -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 index 000000000..1c73c6b9d --- /dev/null +++ b/tests/incremental/model/weaving2/primary/BetaA.20.java @@ -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 index 000000000..1c73c6b9d --- /dev/null +++ b/tests/incremental/model/weaving2/primary/BetaA.delete.40.java @@ -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 index 000000000..1b8b1d7c8 --- /dev/null +++ b/tests/incremental/model/weaving2/primary/BetaA.java @@ -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 index 000000000..be2bec758 --- /dev/null +++ b/tests/incremental/model/weaving2/secondary/GammaA.30.java @@ -0,0 +1,8 @@ +package primary; + +public aspect GammaA { + pointcut handlers(): handler(Throwable); + before(): handlers() { + System.err.println("xxx"); + } +} diff --git a/weaver/src/org/aspectj/weaver/AsmRelationshipProvider.java b/weaver/src/org/aspectj/weaver/AsmRelationshipProvider.java index a1e1e4a06..b3adcba43 100644 --- a/weaver/src/org/aspectj/weaver/AsmRelationshipProvider.java +++ b/weaver/src/org/aspectj/weaver/AsmRelationshipProvider.java @@ -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; } diff --git a/weaver/src/org/aspectj/weaver/Checker.java b/weaver/src/org/aspectj/weaver/Checker.java index c87221bfa..e8f5266f7 100644 --- a/weaver/src/org/aspectj/weaver/Checker.java +++ b/weaver/src/org/aspectj/weaver/Checker.java @@ -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) { diff --git a/weaver/src/org/aspectj/weaver/ConcreteTypeMunger.java b/weaver/src/org/aspectj/weaver/ConcreteTypeMunger.java index 0ce029a55..0f0ecf022 100644 --- a/weaver/src/org/aspectj/weaver/ConcreteTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/ConcreteTypeMunger.java @@ -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) { diff --git a/weaver/src/org/aspectj/weaver/ICrossReferenceHandler.java b/weaver/src/org/aspectj/weaver/ICrossReferenceHandler.java index c0ffeae40..cb2fe93c3 100644 --- a/weaver/src/org/aspectj/weaver/ICrossReferenceHandler.java +++ b/weaver/src/org/aspectj/weaver/ICrossReferenceHandler.java @@ -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); } diff --git a/weaver/src/org/aspectj/weaver/NewConstructorTypeMunger.java b/weaver/src/org/aspectj/weaver/NewConstructorTypeMunger.java index 0f4ac0fb7..699ed9736 100644 --- a/weaver/src/org/aspectj/weaver/NewConstructorTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/NewConstructorTypeMunger.java @@ -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() { diff --git a/weaver/src/org/aspectj/weaver/NewFieldTypeMunger.java b/weaver/src/org/aspectj/weaver/NewFieldTypeMunger.java index 8733a3b8d..3ef81e57b 100644 --- a/weaver/src/org/aspectj/weaver/NewFieldTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/NewFieldTypeMunger.java @@ -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) { diff --git a/weaver/src/org/aspectj/weaver/NewMethodTypeMunger.java b/weaver/src/org/aspectj/weaver/NewMethodTypeMunger.java index 92fcb2c8e..f42f74458 100644 --- a/weaver/src/org/aspectj/weaver/NewMethodTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/NewMethodTypeMunger.java @@ -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) { diff --git a/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java b/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java index 55e0a4e3e..aa1ff7223 100644 --- a/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java @@ -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(); } diff --git a/weaver/src/org/aspectj/weaver/Shadow.java b/weaver/src/org/aspectj/weaver/Shadow.java index 42e2920e4..b34f62e7e 100644 --- a/weaver/src/org/aspectj/weaver/Shadow.java +++ b/weaver/src/org/aspectj/weaver/Shadow.java @@ -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 index 000000000..113be2943 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/WeaverMetrics.java @@ -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++; + } + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java index ad561a98e..92e83c874 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java @@ -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; } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java b/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java index 2fef3a0c1..4d031bcb9 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java @@ -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; } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java index 19beb0f62..653510ddd 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java @@ -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); } } diff --git a/weaver/src/org/aspectj/weaver/patterns/FastMatchInfo.java b/weaver/src/org/aspectj/weaver/patterns/FastMatchInfo.java index c2b6121d0..8d5434f27 100644 --- a/weaver/src/org/aspectj/weaver/patterns/FastMatchInfo.java +++ b/weaver/src/org/aspectj/weaver/patterns/FastMatchInfo.java @@ -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)+"]"; + } } -- 2.39.5