diff options
89 files changed, 2900 insertions, 226 deletions
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: <type pattern>"; - assertEquals(((IProgramElement)aspect.getChildren().get(declareIndex+2)).toLabelString(), decParentsTPMessage); + String decParentsPtnMessage = "declare parents: extends Observable"; + assertEquals(decParentsPtnMessage,((IProgramElement)aspect.getChildren().get(declareIndex+1)).toLabelString()); + String decParentsTPMessage = "declare parents: extends Observable"; + assertEquals(decParentsTPMessage,((IProgramElement)aspect.getChildren().get(declareIndex+2)).toLabelString()); String decSoftMessage = "declare soft: SizeException"; IProgramElement decSoftNode = model.findElementForSignature(aspect, IProgramElement.Kind.DECLARE_SOFT, "declare soft"); 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 ;i<indent;i++) w.write(" "); + w.write(node+" ["+(node==null?"null":node.getKind().toString())+"]\n"); + if (node!=null) + for (Iterator i = node.getChildren().iterator();i.hasNext();) { + dumptree(w,(IProgramElement)i.next(),indent+2); + } + } + + private void dumprels(Writer w) throws IOException { + IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap(); + int ctr = 1; + Set entries = irm.getEntries(); + for (Iterator iter = entries.iterator(); iter.hasNext();) { + String hid = (String) iter.next(); + List rels = irm.get(hid); + for (Iterator iterator = rels.iterator(); iterator.hasNext();) { + IRelationship ir = (IRelationship) iterator.next(); + List targets = ir.getTargets(); + for (Iterator iterator2 = targets.iterator(); + iterator2.hasNext(); + ) { + String thid = (String) iterator2.next(); + w.write("Hid:"+(ctr++)+":(targets="+targets.size()+") "+hid+" ("+ir.getName()+") "+thid+"\n"); + } + } + } + } + + //===================== DELTA PROCESSING CODE ============== start ==========// + + // This code is *SLOW* but it isnt worth fixing until we address the + // bugs in binary weaving. + public void fixupStructureModel(Writer fw,List filesToBeCompiled,Set files_added,Set files_deleted) throws IOException { + // Three kinds of things to worry about: + // 1. New files have been added since the last compile + // 2. Files have been deleted since the last compile + // 3. Files have 'changed' since the last compile (really just those in config.getFiles()) + + // List files = config.getFiles(); + IHierarchy model = AsmManager.getDefault().getHierarchy(); + + boolean modelModified = false; + // Files to delete are: those to be compiled + those that have been deleted + + Set filesToRemoveFromStructureModel = new HashSet(filesToBeCompiled); + filesToRemoveFromStructureModel.addAll(files_deleted); + + for (Iterator iter = filesToRemoveFromStructureModel.iterator(); iter.hasNext();) { + File fileForCompilation = (File) iter.next(); + String correctedPath = AsmManager.getDefault().getCanonicalFilePath(fileForCompilation); + IProgramElement progElem = (IProgramElement)model.findInFileMap(correctedPath); + if (progElem!=null) { + // Found it, let's remove it + if (dumpDeltaProcessing) { + fw.write("Deleting "+progElem+" node for file "+fileForCompilation+"\n"); + } + removeNode(progElem); + verifyAssumption( + model.removeFromFileMap(correctedPath.toString()), + "Whilst repairing model, couldn't remove entry for file: "+correctedPath.toString()+" from the filemap"); + modelModified = true; + } + } + if (modelModified) { + model.flushTypeMap(); + model.flushHandleMap(); + } + } + + public void processDelta(List filesToBeCompiled,Set files_added,Set files_deleted) { + + try { + Writer fw = null; + + // Are we recording this ? + if (dumpDeltaProcessing) { + FileWriter filew = new FileWriter(dumpFilename,true); + fw = new BufferedWriter(filew); + fw.write("=== Processing delta changes for the model ===\n"); + fw.write("Files for compilation:#"+filesToBeCompiled.size()+":"+filesToBeCompiled+"\n"); + fw.write("Files added :#"+files_added.size()+":"+files_added+"\n"); + fw.write("Files deleted :#"+files_deleted.size()+":"+files_deleted+"\n"); + } + + long stime = System.currentTimeMillis(); + + fixupStructureModel(fw,filesToBeCompiled,files_added,files_deleted); + + long etime1 = System.currentTimeMillis(); // etime1-stime = time to fix up the model + + IHierarchy model = AsmManager.getDefault().getHierarchy(); + + // Some of this code relies on the fact that relationships are always in pairs, so you know + // if you are the target of a relationship because you are also the source of a relationship + // This seems a valid assumption for now... + + //TODO Speed this code up by making this assumption: + // the only piece of the handle that is interesting is the file name. We are working at file granularity, if the + // file does not exist (i.e. its not in the filemap) then any handle inside that file cannot exist. + if (dumpDeltaProcessing) fw.write("Repairing relationships map:\n"); + + // Now sort out the relationships map + IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap(); + Set sourcesToRemove = new HashSet(); + Set nonExistingHandles = new HashSet(); // Cache of handles that we *know* are invalid + int srchandlecounter = 0; + int tgthandlecounter = 0; + + // Iterate over the source handles in the relationships map + Set keyset = irm.getEntries(); // These are source handles + for (Iterator keyiter = keyset.iterator(); keyiter.hasNext();) { + String hid = (String) keyiter.next(); + srchandlecounter++; + + // Do we already know this handle points to nowhere? + if (nonExistingHandles.contains(hid)) { + sourcesToRemove.add(hid); + } else { + // We better check if it actually exists + IProgramElement existingElement = model.getElement(hid); + if (dumpDeltaProcessing) fw.write("Looking for handle ["+hid+"] in model, found: "+existingElement+"\n"); + + // Did we find it? + if (existingElement == null) { + // No, so delete this relationship + sourcesToRemove.add(hid); + nonExistingHandles.add(hid); // Speed up a bit you swine + } else { + // Ok, so the source is valid, what about the targets? + List relationships = irm.get(hid); + List relationshipsToRemove = new ArrayList(); + // Iterate through the relationships against this source handle + for (Iterator reliter = relationships.iterator();reliter.hasNext();) { + IRelationship rel = (IRelationship) reliter.next(); + List targets = rel.getTargets(); + List targetsToRemove = new ArrayList(); + + // Iterate through the targets for this relationship + for (Iterator targetIter = targets.iterator();targetIter.hasNext();) { + String targethid = (String) targetIter.next(); + tgthandlecounter++; + // Do we already know it doesn't exist? + if (nonExistingHandles.contains(targethid)) { + if (dumpDeltaProcessing) fw.write("Target handle ["+targethid+"] for srchid["+hid+"]rel["+rel.getName()+"] does not exist\n"); + targetsToRemove.add(targethid); + } else { + // We better check + IProgramElement existingTarget = model.getElement(targethid); + if (existingTarget == null) { + if (dumpDeltaProcessing) fw.write("Target handle ["+targethid+"] for srchid["+hid+"]rel["+rel.getName()+"] does not exist\n"); + targetsToRemove.add(targethid); + nonExistingHandles.add(targethid); + } + } + } + + // Do we have some targets that need removing? + if (targetsToRemove.size()!=0) { + // Are we removing *all* of the targets for this relationship (i.e. removing the relationship) + if (targetsToRemove.size()==targets.size()) { + if (dumpDeltaProcessing) fw.write("No targets remain for srchid["+hid+"] rel["+rel.getName()+"]: removing it\n"); + relationshipsToRemove.add(rel); + } else { + // Remove all the targets that are no longer valid + for (Iterator targsIter = targetsToRemove.iterator();targsIter.hasNext();) { + String togo = (String) targsIter.next(); + targets.remove(togo); + } + // Should have already been caught above, but lets double check ... + if (targets.size()==0) { + if (dumpDeltaProcessing) fw.write("No targets remain for srchid["+hid+"] rel["+rel.getName()+"]: removing it\n"); + relationshipsToRemove.add(rel); // TODO Should only remove this relationship for the srchid? + } + } + } + } + // Now, were any relationships emptied during that processing and so need removing for this source handle + if (relationshipsToRemove.size()>0) { + // Are we removing *all* of the relationships for this source handle? + if (relationshipsToRemove.size() == relationships.size()) { + // We know they are all going to go, so just delete the source handle. + sourcesToRemove.add(hid); + } else { + for (int i = 0 ;i<relationshipsToRemove.size();i++) { + IRelationship irel = (IRelationship)relationshipsToRemove.get(i); + verifyAssumption(irm.remove(hid,irel),"Failed to remove relationship "+irel.getName()+" for shid "+hid); + } + List rels = irm.get(hid); + if (rels==null || rels.size()==0) sourcesToRemove.add(hid); + } + } + } + } + } + // Remove sources that have no valid relationships any more + for (Iterator srciter = sourcesToRemove.iterator(); srciter.hasNext();) { + String hid = (String) srciter.next(); + irm.removeAll(hid); + IProgramElement ipe = model.getElement(hid); + if (ipe!=null) { + // If the relationship was hanging off a 'code' node, delete it. + if (ipe.getKind().equals(IProgramElement.Kind.CODE)) { + removeSingleNode(ipe); + } + } + } + long etime2 = System.currentTimeMillis(); // etime2-stime = time to repair the relationship map + if (dumpDeltaProcessing) { + fw.write("===== Delta Processing timing ==========\n"); + fw.write("Hierarchy="+(etime1-stime)+"ms Relationshipmap="+(etime2-etime1)+"ms\n"); + fw.write("===== Traversal ========================\n"); + fw.write("Source handles processed="+srchandlecounter+"\n"); + fw.write("Target handles processed="+tgthandlecounter+"\n"); + fw.write("========================================\n"); + fw.flush();fw.close(); + } + reportModelInfo("After delta processing"); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + /** + * Removes a specified program element from the structure model. + * We go to the parent of the program element, ask for all its children + * and remove the node we want to delete from the list of children. + */ + private void removeSingleNode(IProgramElement progElem) { + verifyAssumption(progElem!=null); + boolean deleteOK = false; + IProgramElement parent = progElem.getParent(); + List kids = parent.getChildren(); + for (int i =0 ;i<kids.size();i++) { + if (kids.get(i).equals(progElem)) { + kids.remove(i); + deleteOK=true; + break; + } + } + verifyAssumption(deleteOK); + } + + + /** + * Removes a specified program element from the structure model. + * Two processing stages: + * <p>First: We go to the parent of the program element, ask for all its children + * and remove the node we want to delete from the list of children. + * <p>Second:We check if that parent has any other children. If it has no other + * children and it is either a CODE node or a PACKAGE node, we delete it too. + */ + private void removeNode(IProgramElement progElem) { + + StringBuffer flightrecorder = new StringBuffer(); + try { + flightrecorder.append("In removeNode, about to chuck away: "+progElem+"\n"); + + verifyAssumption(progElem!=null); + boolean deleteOK = false; + IProgramElement parent = progElem.getParent(); + flightrecorder.append("Parent of it is "+parent+"\n"); + List kids = parent.getChildren(); + flightrecorder.append("Which has "+kids.size()+" kids\n"); + for (int i =0 ;i<kids.size();i++) { + flightrecorder.append("Comparing with "+kids.get(i)+"\n"); + if (kids.get(i).equals(progElem)) { + kids.remove(i); + flightrecorder.append("Removing it\n"); + deleteOK=true; + break; + } + } + verifyAssumption(deleteOK,flightrecorder.toString()); + // Are there any kids left for this node? + if (parent.getChildren().size()==0 && parent.getParent()!=null && + (parent.getKind().equals(IProgramElement.Kind.CODE) || + parent.getKind().equals(IProgramElement.Kind.PACKAGE))) { + // This node is on its own, we should trim it too *as long as its not a structural node* which we currently check by making sure its a code node + // We should trim if it + // System.err.println("Deleting parent:"+parent); + removeNode(parent); + } + } catch (NullPointerException npe ){ + // Occurred when commenting out other 2 ras classes in wsif?? reproducable? + System.err.println(flightrecorder.toString()); + npe.printStackTrace(); + } + } + + + public static void verifyAssumption(boolean b,String info) { + if (!b) { + System.err.println("=========== ASSERTION IS NOT TRUE =========v"); + System.err.println(info); + Thread.dumpStack(); + System.err.println("=========== ASSERTION IS NOT TRUE =========^"); + throw new RuntimeException("Assertion is false"); + } + } + + public static void verifyAssumption(boolean b) { + if (!b) { + Thread.dumpStack(); + throw new RuntimeException("Assertion is false"); + } + } + + + //===================== DELTA PROCESSING CODE ============== end ==========// + + /** + * A ModelInfo object captures basic information about the structure model. + * It is used for testing and producing debug info. + */ + public static class ModelInfo { + private Hashtable nodeTypeCount = new Hashtable(); + private Properties extraProperties = new Properties(); + + private ModelInfo(IHierarchy hierarchy,IRelationshipMap relationshipMap) { + IProgramElement ipe = hierarchy.getRoot(); + walkModel(ipe); + recordStat("FileMapSize", + new Integer(hierarchy.getFileMapEntrySet().size()).toString()); + recordStat("RelationshipMapSize", + new Integer(relationshipMap.getEntries().size()).toString()); + } + + private void walkModel(IProgramElement ipe) { + countNode(ipe); + List kids = ipe.getChildren(); + for (Iterator iter = kids.iterator(); iter.hasNext();) { + IProgramElement nextElement = (IProgramElement) iter.next(); + walkModel(nextElement); + } + } + + private void countNode(IProgramElement ipe) { + String node = ipe.getKind().toString(); + Integer ctr = (Integer)nodeTypeCount.get(node); + if (ctr==null) { + nodeTypeCount.put(node,new Integer(1)); + } else { + ctr = new Integer(ctr.intValue()+1); + nodeTypeCount.put(node,ctr); + } + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("Model node summary:\n"); + Enumeration nodeKeys = nodeTypeCount.keys(); + while (nodeKeys.hasMoreElements()) { + String key = (String)nodeKeys.nextElement(); + Integer ct = (Integer)nodeTypeCount.get(key); + sb.append(key+"="+ct+"\n"); + } + sb.append("Model stats:\n"); + Enumeration ks = extraProperties.keys(); + while (ks.hasMoreElements()) { + String k = (String)ks.nextElement(); + String v = extraProperties.getProperty(k); + sb.append(k+"="+v+"\n"); + } + return sb.toString(); + } + + public Properties getProperties() { + Properties p = new Properties(); + Enumeration nodeKeys = nodeTypeCount.keys(); + while (nodeKeys.hasMoreElements()) { + String key = (String)nodeKeys.nextElement(); + Integer ct = (Integer)nodeTypeCount.get(key); + p.setProperty(key,ct.toString()); + } + p.putAll(extraProperties); + return p; + } + + public void recordStat(String string, String string2) { + extraProperties.setProperty(string,string2); + } + + public static ModelInfo summarizeModel() { + return new ModelInfo(AsmManager.getDefault().getHierarchy(), + AsmManager.getDefault().getRelationshipMap()); + } + } } diff --git a/asm/src/org/aspectj/asm/IHierarchy.java b/asm/src/org/aspectj/asm/IHierarchy.java index 793b01420..95b00996b 100644 --- a/asm/src/org/aspectj/asm/IHierarchy.java +++ b/asm/src/org/aspectj/asm/IHierarchy.java @@ -31,6 +31,7 @@ public interface IHierarchy extends Serializable { public IProgramElement getRoot(); public void setRoot(IProgramElement root); public void addToFileMap(Object key, Object value); + public boolean removeFromFileMap(Object key); public void setFileMap(HashMap fileMap); public Object findInFileMap(Object key); public Set getFileMapEntrySet(); @@ -94,4 +95,8 @@ public interface IHierarchy extends Serializable { public String getConfigFile(); public void setConfigFile(String configFile); + + public void flushTypeMap(); + + public void flushHandleMap(); }
\ No newline at end of file diff --git a/asm/src/org/aspectj/asm/IProgramElement.java b/asm/src/org/aspectj/asm/IProgramElement.java index 83374889a..476b6aaa0 100644 --- a/asm/src/org/aspectj/asm/IProgramElement.java +++ b/asm/src/org/aspectj/asm/IProgramElement.java @@ -28,6 +28,23 @@ public interface IProgramElement extends Serializable { public void setChildren(List children); public void addChild(IProgramElement child); + + // Extra stuff + // Could be just a string but may prove more useful as an object in the long run ... + public static class ExtraInformation implements Serializable { + private String extraInfo; + public ExtraInformation() { extraInfo = "";} + + public void setExtraAdviceInformation(String string) {extraInfo = string;} + public String getExtraAdviceInformation() {return extraInfo;} + + public String toString() { + return "ExtraInformation: ["+extraInfo+"]"; + } + } + + public void setExtraInfo(ExtraInformation info); + public ExtraInformation getExtraInfo(); public IProgramElement getParent(); public void setParent(IProgramElement parent); diff --git a/asm/src/org/aspectj/asm/IRelationship.java b/asm/src/org/aspectj/asm/IRelationship.java index 18a11da0e..53b118262 100644 --- a/asm/src/org/aspectj/asm/IRelationship.java +++ b/asm/src/org/aspectj/asm/IRelationship.java @@ -27,17 +27,33 @@ public interface IRelationship extends Serializable { public String getSourceHandle(); + public boolean addTarget(String handle); + public Kind getKind(); + + public boolean hasRuntimeTest(); /** * Uses "typesafe enum" pattern. */ public static class Kind implements Serializable { - public static final Kind ADVICE = new Kind("advice"); - public static final Kind DECLARE = new Kind("declare"); - public static final Kind DECLARE_INTER_TYPE = new Kind("inter-type declaration"); - public static final Kind[] ALL = { ADVICE, DECLARE, DECLARE_INTER_TYPE }; + public static final Kind DECLARE_WARNING = new Kind("declare warning"); + public static final Kind DECLARE_ERROR = new Kind("declare error"); + public static final Kind ADVICE_AROUND = new Kind("around advice"); + public static final Kind ADVICE_AFTERRETURNING = new Kind("after returning advice"); + public static final Kind ADVICE_AFTERTHROWING = new Kind("after throwing advice"); + public static final Kind ADVICE_AFTER = new Kind("after advice"); + public static final Kind ADVICE_BEFORE = new Kind("before advice"); + public static final Kind ADVICE = new Kind("advice"); + public static final Kind DECLARE = new Kind("declare"); + public static final Kind DECLARE_INTER_TYPE = new Kind("inter-type declaration"); + + public static final Kind[] ALL = { + DECLARE_WARNING, DECLARE_ERROR, + ADVICE_AROUND,ADVICE_AFTERRETURNING,ADVICE_AFTERTHROWING,ADVICE_AFTER,ADVICE_BEFORE, + ADVICE, DECLARE, DECLARE_INTER_TYPE }; + private final String name; private Kind(String name) { diff --git a/asm/src/org/aspectj/asm/IRelationshipMap.java b/asm/src/org/aspectj/asm/IRelationshipMap.java index 7eb31335f..ff88efbc5 100644 --- a/asm/src/org/aspectj/asm/IRelationshipMap.java +++ b/asm/src/org/aspectj/asm/IRelationshipMap.java @@ -14,6 +14,7 @@ package org.aspectj.asm; import java.io.Serializable; import java.util.List; +import java.util.Set; //import org.aspectj.asm.IRelationship.Kind; @@ -50,21 +51,33 @@ public interface IRelationshipMap extends Serializable { * * @return null if the relationship is not found. */ - public IRelationship get(IProgramElement source, IRelationship.Kind kind, String relationshipName); + public IRelationship get(IProgramElement source, IRelationship.Kind kind, + String relationshipName,boolean runtimeTest, + boolean createIfMissing); /** + * Return a relationship matching the kind and name for the given element. + * + * @return null if the relationship is not found. + */ + public IRelationship get(IProgramElement source, IRelationship.Kind kind, + String relationshipName); + + /** * Return a relationship matching the kind and name for the given element. * Creates the relationship if not found. * * @return null if the relationship is not found. */ - public IRelationship get(String source, IRelationship.Kind kind, String relationshipName); + public IRelationship get(String source, IRelationship.Kind kind, + String relationshipName, boolean runtimeTest, + boolean createIfMissing); public void put(IProgramElement source, IRelationship relationship); public void put(String handle, IRelationship relationship); - public void remove(String handle, IRelationship relationship); + public boolean remove(String handle, IRelationship relationship); public void removeAll(String source); @@ -72,5 +85,7 @@ public interface IRelationshipMap extends Serializable { * Clear all of the relationships in the map. */ public void clear(); + + public Set getEntries(); } diff --git a/asm/src/org/aspectj/asm/internal/AspectJElementHierarchy.java b/asm/src/org/aspectj/asm/internal/AspectJElementHierarchy.java index 0a36642ab..da1b09e38 100644 --- a/asm/src/org/aspectj/asm/internal/AspectJElementHierarchy.java +++ b/asm/src/org/aspectj/asm/internal/AspectJElementHierarchy.java @@ -8,6 +8,7 @@ * * Contributors: * Mik Kersten initial implementation + * Andy Clement Extensions for better IDE representation * ******************************************************************/ @@ -32,7 +33,19 @@ public class AspectJElementHierarchy implements IHierarchy { private Map typeMap = null; public IProgramElement getElement(String handle) { - throw new RuntimeException("unimplemented"); + IProgramElement cachedEntry = (IProgramElement)handleMap.get(handle); + if (cachedEntry!=null) return cachedEntry; + + StringTokenizer st = new StringTokenizer(handle, ProgramElement.ID_DELIM); + String file = st.nextToken(); + int line = new Integer(st.nextToken()).intValue(); + // int col = new Integer(st.nextToken()).intValue(); TODO: use column number when available + String canonicalSFP = AsmManager.getDefault().getCanonicalFilePath(new File(file)); + IProgramElement ret = findNodeForSourceLineHelper(root,canonicalSFP, line); + if (ret!=null) { + handleMap.put(handle,ret); + } + return ret; } public IProgramElement getRoot() { @@ -48,6 +61,10 @@ public class AspectJElementHierarchy implements IHierarchy { public void addToFileMap( Object key, Object value ){ fileMap.put( key, value ); } + + public boolean removeFromFileMap(Object key) { + return (fileMap.remove(key)!=null); + } public void setFileMap(HashMap fileMap) { this.fileMap = fileMap; @@ -336,5 +353,14 @@ public class AspectJElementHierarchy implements IHierarchy { protected void cache(String handle, ProgramElement pe) { handleMap.put(handle,pe); } + + public void flushTypeMap() { + typeMap.clear(); + + } + + public void flushHandleMap() { + handleMap.clear(); + } } diff --git a/asm/src/org/aspectj/asm/internal/ProgramElement.java b/asm/src/org/aspectj/asm/internal/ProgramElement.java index 3cff3287d..913a1cebc 100644 --- a/asm/src/org/aspectj/asm/internal/ProgramElement.java +++ b/asm/src/org/aspectj/asm/internal/ProgramElement.java @@ -8,16 +8,22 @@ * * Contributors: * Mik Kersten initial implementation + * Andy Clement Extensions for better IDE representation * ******************************************************************/ package org.aspectj.asm.internal; -import java.io.*; -import java.util.*; +import java.io.File; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; -import org.aspectj.asm.*; -import org.aspectj.bridge.*; +import org.aspectj.asm.AsmManager; +import org.aspectj.asm.HierarchyWalker; +import org.aspectj.asm.IProgramElement; +import org.aspectj.bridge.IMessage; +import org.aspectj.bridge.ISourceLocation; /** @@ -55,6 +61,8 @@ public class ProgramElement implements IProgramElement { private List parameterTypes = null; private String details = null; + + private ExtraInformation info; /** * Used during de-externalization. @@ -126,6 +134,10 @@ public class ProgramElement implements IProgramElement { public Accessibility getAccessibility() { return accessibility; } + + public void setAccessibility(Accessibility a) { + accessibility=a; + } public String getDeclaringType() { return declaringType; @@ -388,6 +400,9 @@ public class ProgramElement implements IProgramElement { return sb.toString(); } + + public static boolean shortITDNames = true; + /** * TODO: move the "parent != null"==>injar heuristic to more explicit */ @@ -396,13 +411,20 @@ public class ProgramElement implements IProgramElement { if (kind == Kind.CODE || kind == Kind.INITIALIZER) { label = parent.getParent().getName() + ": "; } else if (kind.isInterTypeMember()) { - int dotIndex = name.indexOf('.'); - if (dotIndex != -1) { - return parent.getName() + ": " + toLabelString().substring(dotIndex+1); + if (shortITDNames) { + // if (name.indexOf('.')!=-1) return toLabelString().substring(name.indexOf('.')+1); + label=""; } else { + int dotIndex = name.indexOf('.'); + if (dotIndex != -1) { + return parent.getName() + ": " + toLabelString().substring(dotIndex+1); + } else { label = parent.getName() + '.'; + } } - } else if (kind == Kind.CLASS || kind == Kind.ASPECT) { + } else if (kind == Kind.CLASS || kind == Kind.ASPECT || kind == Kind.INTERFACE) { + label = ""; + } else if (kind.equals(Kind.DECLARE_PARENTS)) { label = ""; } else { if (parent != null) { @@ -487,5 +509,15 @@ public class ProgramElement implements IProgramElement { hierarchy.cache(handle,this); } } + + public void setExtraInfo(ExtraInformation info) { + this.info = info; + + } + + public ExtraInformation getExtraInfo() { + return info; + } + } 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 (<list> uses classpath delimiter)\n\ \t-outjar <file> put output classes in zip file <file>\n\ \t-argfile <file> specify line-delimited list of source files\n\ +\t-showWeaveInfo display information about weaving\n\ \t-incremental continuously-running compiler, needs -sourceroots\n\ \t (reads stdin: enter to recompile and ''q'' to quit)\n\ \t-sourceroots <dirs> compile all .aj and .java files in <dirs>\n\ 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 = "<root>"; + private void setupModel(AjBuildConfig config) { IHierarchy model = AsmManager.getDefault().getHierarchy(); - AsmManager.getDefault().getRelationshipMap().clear(); + String rootLabel = "<root>"; + + AsmManager.getDefault().getRelationshipMap().clear(); - IProgramElement.Kind kind = IProgramElement.Kind.FILE_JAVA; - if (buildConfig.getConfigFile() != null) { - rootLabel = buildConfig.getConfigFile().getName(); - model.setConfigFile( - buildConfig.getConfigFile().getAbsolutePath() - ); - kind = IProgramElement.Kind.FILE_LST; - } - model.setRoot(new ProgramElement(rootLabel, kind, new ArrayList())); + IProgramElement.Kind kind = IProgramElement.Kind.FILE_JAVA; + if (buildConfig.getConfigFile() != null) { + rootLabel = buildConfig.getConfigFile().getName(); + model.setConfigFile( + buildConfig.getConfigFile().getAbsolutePath() + ); + kind = IProgramElement.Kind.FILE_LST; + } + model.setRoot(new ProgramElement(rootLabel, kind, new ArrayList())); - model.setFileMap(new HashMap()); - setStructureModel(model); + model.setFileMap(new HashMap()); + setStructureModel(model); } +// +// private void dumplist(List l) { +// System.err.println("---- "+l.size()); +// for (int i =0 ;i<l.size();i++) System.err.println(i+"\t "+l.get(i)); +// } +// private void accumulateFileNodes(IProgramElement ipe,List store) { +// if (ipe.getKind()==IProgramElement.Kind.FILE_JAVA || +// ipe.getKind()==IProgramElement.Kind.FILE_ASPECTJ) { +// if (!ipe.getName().equals("<root>")) { +// store.add(ipe); +// return; +// } +// } +// for (Iterator i = ipe.getChildren().iterator();i.hasNext();) { +// accumulateFileNodes((IProgramElement)i.next(),store); +// } +// } + /** init only on initial batch compile? no file-specific options */ private void initBcelWorld(IMessageHandler handler) throws IOException { bcelWorld = new BcelWorld(buildConfig.getClasspath(), handler, null); 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)<newParents.length) details.append(","); + } + node.setDetails(kindOfDP+details.toString()); + } else if (declare.declareDecl instanceof DeclareSoft) { node.setKind( IProgramElement.Kind.DECLARE_SOFT); DeclareSoft ds = (DeclareSoft)declare.declareDecl; @@ -125,17 +152,30 @@ public class AsmElementFormatter { InterTypeDeclaration itd = (InterTypeDeclaration)methodDeclaration; String name = itd.onType.toString() + "." + new String(itd.getDeclaredSelector()); if (methodDeclaration instanceof InterTypeFieldDeclaration) { - node.setKind(IProgramElement.Kind.INTER_TYPE_FIELD); + node.setKind(IProgramElement.Kind.INTER_TYPE_FIELD); + node.setName(name); } else if (methodDeclaration instanceof InterTypeMethodDeclaration) { node.setKind(IProgramElement.Kind.INTER_TYPE_METHOD); -// InterTypeMethodDeclaration itmd = (InterTypeMethodDeclaration)methodDeclaration; + node.setName(name); } else if (methodDeclaration instanceof InterTypeConstructorDeclaration) { node.setKind(IProgramElement.Kind.INTER_TYPE_CONSTRUCTOR); + + // StringBuffer argumentsSignature = new StringBuffer("fubar"); +// argumentsSignature.append("("); +// if (methodDeclaration.arguments!=null && methodDeclaration.arguments.length>1) { +// +// for (int i = 1;i<methodDeclaration.arguments.length;i++) { +// argumentsSignature.append(methodDeclaration.arguments[i]); +// if (i+1<methodDeclaration.arguments.length) argumentsSignature.append(","); +// } +// } +// argumentsSignature.append(")"); // InterTypeConstructorDeclaration itcd = (InterTypeConstructorDeclaration)methodDeclaration; + node.setName(itd.onType.toString() + "." + itd.onType.toString()/*+argumentsSignature.toString()*/); } else { node.setKind(IProgramElement.Kind.ERROR); + node.setName(name); } - node.setName(name); node.setCorrespondingType(itd.returnType.toString()); if (node.getKind() != IProgramElement.Kind.INTER_TYPE_FIELD) { setParameters(methodDeclaration, node); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmHierarchyBuilder.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmHierarchyBuilder.java index f4aa53488..ec4aa6c63 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmHierarchyBuilder.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmHierarchyBuilder.java @@ -13,40 +13,25 @@ package org.aspectj.ajdt.internal.core.builder; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.ListIterator; -import java.util.Stack; +import java.io.*; +import java.util.*; import org.aspectj.ajdt.internal.compiler.ast.AspectDeclaration; +import org.aspectj.ajdt.internal.compiler.ast.DeclareDeclaration; +import org.aspectj.ajdt.internal.compiler.ast.InterTypeDeclaration; +import org.aspectj.ajdt.internal.compiler.ast.InterTypeFieldDeclaration; +import org.aspectj.ajdt.internal.compiler.ast.InterTypeMethodDeclaration; +import org.aspectj.ajdt.internal.compiler.lookup.AjLookupEnvironment; import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory; -import org.aspectj.asm.IHierarchy; -import org.aspectj.asm.IProgramElement; +import org.aspectj.asm.*; import org.aspectj.asm.internal.ProgramElement; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.bridge.SourceLocation; +import org.aspectj.bridge.*; import org.aspectj.util.LangUtil; import org.aspectj.weaver.Member; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.ast.ASTNode; -import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; -import org.eclipse.jdt.internal.compiler.ast.ExtendedStringLiteral; -import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; -import org.eclipse.jdt.internal.compiler.ast.ImportReference; -import org.eclipse.jdt.internal.compiler.ast.Initializer; -import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; +import org.aspectj.weaver.ResolvedMember; +import org.eclipse.jdt.internal.compiler.*; +import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.lookup.*; import org.eclipse.jdt.internal.compiler.problem.ProblemHandler; /** @@ -140,7 +125,8 @@ public class AsmHierarchyBuilder extends ASTVisitor { final IProgramElement addToNode = genAddToNode(unit, structureModel); // -- remove duplicates before adding (XXX use them instead?) - for (ListIterator itt = addToNode.getChildren().listIterator(); itt.hasNext(); ) { + if (addToNode!=null && addToNode.getChildren()!=null) { + for (ListIterator itt = addToNode.getChildren().listIterator(); itt.hasNext(); ) { IProgramElement child = (IProgramElement)itt.next(); ISourceLocation childLoc = child.getSourceLocation(); if (null == childLoc) { @@ -149,6 +135,7 @@ public class AsmHierarchyBuilder extends ASTVisitor { } else if (childLoc.getSourceFile().equals(file)) { itt.remove(); } + } } // -- add and traverse addToNode.addChild(cuNode); @@ -193,14 +180,16 @@ public class AsmHierarchyBuilder extends ASTVisitor { } IProgramElement pkgNode = null; - for (Iterator it = structureModel.getRoot().getChildren().iterator(); - it.hasNext(); ) { - IProgramElement currNode = (IProgramElement)it.next(); - if (pkgName.equals(currNode.getName())) { - pkgNode = currNode; - break; - } - } + if (structureModel!=null && structureModel.getRoot()!=null && structureModel.getRoot().getChildren()!=null) { + for (Iterator it = structureModel.getRoot().getChildren().iterator(); + it.hasNext(); ) { + IProgramElement currNode = (IProgramElement)it.next(); + if (pkgName.equals(currNode.getName())) { + pkgNode = currNode; + break; + } + } + } if (pkgNode == null) { // note packages themselves have no source location pkgNode = new ProgramElement( @@ -318,19 +307,40 @@ public class AsmHierarchyBuilder extends ASTVisitor { return (IProgramElement)stack.peek(); } - public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) { - IProgramElement peNode = new ProgramElement( - "", - IProgramElement.Kind.ERROR, - makeLocation(methodDeclaration), - methodDeclaration.modifiers, - "", - new ArrayList()); + public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) { + IProgramElement peNode = null; + + // For intertype decls, use the modifiers from the original signature, not the generated method + if (methodDeclaration instanceof InterTypeDeclaration) { + InterTypeDeclaration itd = (InterTypeDeclaration) methodDeclaration; + ResolvedMember sig = itd.getSignature(); + peNode = new ProgramElement( + "", + IProgramElement.Kind.ERROR, + makeLocation(methodDeclaration), + (sig!=null?sig.getModifiers():0), + "", + new ArrayList()); + + } else { + + peNode = new ProgramElement( + "", + IProgramElement.Kind.ERROR, + makeLocation(methodDeclaration), + methodDeclaration.modifiers, + "", + new ArrayList()); + } formatter.genLabelAndKind(methodDeclaration, peNode); genBytecodeInfo(methodDeclaration, peNode); - peNode.setModifiers(methodDeclaration.modifiers); - peNode.setCorrespondingType(methodDeclaration.returnType.toString()); + + if (methodDeclaration.returnType!=null) { + peNode.setCorrespondingType(methodDeclaration.returnType.toString()); + } else { + peNode.setCorrespondingType(null); + } peNode.setSourceSignature(genSourceSignature(methodDeclaration)); peNode.setFormalComment(generateJavadocComment(methodDeclaration)); @@ -349,7 +359,7 @@ public class AsmHierarchyBuilder extends ASTVisitor { private String genSourceSignature(MethodDeclaration methodDeclaration) { StringBuffer output = new StringBuffer(); - methodDeclaration.printModifiers(methodDeclaration.modifiers, output); + ASTNode.printModifiers(methodDeclaration.modifiers, output); methodDeclaration.printReturnType(0, output).append(methodDeclaration.selector).append('('); if (methodDeclaration.arguments != null) { for (int i = 0; i < methodDeclaration.arguments.length; i++) { @@ -485,7 +495,7 @@ public class AsmHierarchyBuilder extends ASTVisitor { */ private String genSourceSignature(FieldDeclaration fieldDeclaration) { StringBuffer output = new StringBuffer(); - fieldDeclaration.printModifiers(fieldDeclaration.modifiers, output); + FieldDeclaration.printModifiers(fieldDeclaration.modifiers, output); fieldDeclaration.type.print(0, output).append(' ').append(fieldDeclaration.name); if (fieldDeclaration.initialization != null @@ -524,8 +534,17 @@ public class AsmHierarchyBuilder extends ASTVisitor { stack.push(null); // a little wierd but does the job return true; } + StringBuffer argumentsSignature = new StringBuffer(); + argumentsSignature.append("("); + if (constructorDeclaration.arguments!=null) { + for (int i = 0;i<constructorDeclaration.arguments.length;i++) { + argumentsSignature.append(constructorDeclaration.arguments[i]); + if (i+1<constructorDeclaration.arguments.length) argumentsSignature.append(","); + } + } + argumentsSignature.append(")"); IProgramElement peNode = new ProgramElement( - new String(constructorDeclaration.selector), + new String(constructorDeclaration.selector)+argumentsSignature, IProgramElement.Kind.CONSTRUCTOR, makeLocation(constructorDeclaration), constructorDeclaration.modifiers, @@ -535,6 +554,22 @@ public class AsmHierarchyBuilder extends ASTVisitor { peNode.setModifiers(constructorDeclaration.modifiers); peNode.setSourceSignature(genSourceSignature(constructorDeclaration)); + // Fix to enable us to anchor things from ctor nodes + if (constructorDeclaration.binding != null) { + String memberName = ""; + String memberBytecodeSignature = ""; + try { + Member member = EclipseFactory.makeResolvedMember(constructorDeclaration.binding); + memberName = member.getName(); + memberBytecodeSignature = member.getSignature(); + } catch (NullPointerException npe) { + memberName = "<undefined>"; + } + peNode.setBytecodeName(memberName); + peNode.setBytecodeSignature(memberBytecodeSignature); + } + + ((IProgramElement)stack.peek()).addChild(peNode); stack.push(peNode); return true; @@ -544,7 +579,7 @@ public class AsmHierarchyBuilder extends ASTVisitor { } private String genSourceSignature(ConstructorDeclaration constructorDeclaration) { StringBuffer output = new StringBuffer(); - constructorDeclaration.printModifiers(constructorDeclaration.modifiers, output); + ASTNode.printModifiers(constructorDeclaration.modifiers, output); output.append(constructorDeclaration.selector).append('('); if (constructorDeclaration.arguments != null) { for (int i = 0; i < constructorDeclaration.arguments.length; i++) { diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseAdapterUtils.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseAdapterUtils.java index b2b4d9c66..fa79a8360 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseAdapterUtils.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseAdapterUtils.java @@ -135,12 +135,23 @@ public class EclipseAdapterUtils { seeAlso[i].getSourceLineNumber()); } + // We transform messages from AJ types to eclipse IProblems + // and back to AJ types. During their time as eclipse problems, + // we remember whether the message originated from a declare + // in the extraDetails. + String extraDetails = problem.getSupplementaryMessageInfo(); + boolean declared = false; + if (extraDetails!=null && extraDetails.endsWith("[deow=true]")) { + declared = true; + extraDetails = extraDetails.substring(0,extraDetails.length()-"[deow=true]".length()); + } + IMessage msg = new Message(problem.getMessage(), - problem.getSupplementaryMessageInfo(), + extraDetails, problem.isError() ? IMessage.ERROR : IMessage.WARNING, sourceLocation, null, - seeAlsoLocations); + seeAlsoLocations,declared); return msg; } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java b/org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java index de8395967..1ec80de03 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java @@ -188,6 +188,10 @@ public class Main { ourHandler = new MessageHandler(true); } + public MessageHandler getMessageHandler() { + return ourHandler; + } + /** * Run without throwing exceptions but optionally using System.exit(..). * This sets up a message handler which emits messages immediately, @@ -525,13 +529,15 @@ public class Main { } /** @return System.err for FAIL, ABORT, ERROR, and WARNING, - * System.out for INFO if verbose. + * System.out for INFO if -verbose and WEAVEINFO if -showWeaveInfo. */ protected PrintStream getStreamFor(IMessage.Kind kind) { if (IMessage.WARNING.isSameOrLessThan(kind)) { return System.err; } else if (verbose && IMessage.INFO.equals(kind)) { return System.out; + } else if (IMessage.WEAVEINFO.equals(kind)) { + return System.out; } else { return null; } diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/BcweaverJarMaker.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/BcweaverJarMaker.java index 96a5021ae..4205b733c 100644 --- a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/BcweaverJarMaker.java +++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/BcweaverJarMaker.java @@ -191,7 +191,9 @@ public class BcweaverJarMaker { args.add("../tests/bugs/StringToString/helloworld.jar"); args.add("../tests/bugs/StringToString/HW.java"); CommandTestCase.runCompiler(args, CommandTestCase.NO_ERRORS); - } + + buildShowWeaveInfoTestingJars(); + } public static void makeURLWeavingClassLoaderJars() throws IOException { List args = new ArrayList(); @@ -296,7 +298,37 @@ public class BcweaverJarMaker { args.add(AjdtAjcTests.TESTDATA_PATH + "/src1/LTWPerthis.aj"); CommandTestCase.runCompiler(args, CommandTestCase.NO_ERRORS); } - + + private static void buildJarWithClasspath(String outjar,String input,String deps,boolean nodebug) { + System.out.println(" Building "+outjar); + List args = new ArrayList(); + if (nodebug) args.add("-g:none"); + args.add("-classpath"); + args.add("../lib/test/aspectjrt.jar;../lib/test/testing-client.jar" + + File.pathSeparator + System.getProperty("aspectjrt.path") + + (deps!=null?File.pathSeparator + "../ajde/testdata/WeaveInfoMessagesTest/"+deps:"")); + args.add("-outjar"); + args.add("../ajde/testdata/WeaveInfoMessagesTest/"+outjar); + args.add("../ajde/testdata/WeaveInfoMessagesTest/"+input); + + System.err.println(args); + CommandTestCase.runCompiler(args, CommandTestCase.NO_ERRORS); + } + + private static void buildShowWeaveInfoTestingJars() { + System.out.println("For binary weave info message testing (ShowWeaveMessagesTestCase.java)"); + buildJarWithClasspath("Simple.jar","Simple.java",null,false); + // Build with javac and jar + // buildJarWithClasspath("Simple_nodebug.jar","Simple.java",null,true); + buildJarWithClasspath("AspectAdvice.jar","AspectAdvice.aj",null,false); + buildJarWithClasspath("AspectAdvice_nodebug.jar","AspectAdvice.aj","Simple.jar",true); + buildJarWithClasspath("AspectDeclare.jar","AspectDeclare.aj","Simple.jar",false); + buildJarWithClasspath("AspectDeclare_nodebug.jar","AspectDeclare.aj","Simple.jar",true); + buildJarWithClasspath("AspectITD.jar","AspectITD.aj","Simple.jar",false); + buildJarWithClasspath("AspectITD_nodebug.jar","AspectITD.aj","Simple.jar",true); + buildJarWithClasspath("AspectDeclareSoft.jar","AspectDeclareSoft.aj","Simple.jar",false); + buildJarWithClasspath("AspectDeclareSoft_nodebug.jar","AspectDeclareSoft.aj","Simple.jar",true); + } public static void makeDuplicateManifestTestJars() throws IOException { List args = new ArrayList(); diff --git a/testing/src/org/aspectj/testing/harness/bridge/IncCompilerRun.java b/testing/src/org/aspectj/testing/harness/bridge/IncCompilerRun.java index f226d00d9..485dfe3d4 100644 --- a/testing/src/org/aspectj/testing/harness/bridge/IncCompilerRun.java +++ b/testing/src/org/aspectj/testing/harness/bridge/IncCompilerRun.java @@ -23,6 +23,8 @@ import java.util.List; //import java.util.Collections; //import java.util.List; +import org.aspectj.ajde.ui.StructureModelUtil; +import org.aspectj.ajde.ui.StructureModelUtil.ModelIncorrectException; import org.aspectj.bridge.ICommand; //import org.aspectj.bridge.IMessage; import org.aspectj.bridge.MessageUtil; @@ -241,6 +243,9 @@ public class IncCompilerRun implements IAjcRun { } // final long startTime = System.currentTimeMillis(); commandResult = compiler.repeatCommand(handler); + if (!spec.checkModel.equals("")) { + StructureModelUtil.checkModel(spec.checkModel); + } // XXX disabled LangUtil.throwIaxIfNotAllAssignable(actualRecompiled, File.class, "recompiled"); report = true; // handler does not verify sandbox... @@ -258,6 +263,8 @@ public class IncCompilerRun implements IAjcRun { result = dirChanges.end(status, sandbox.testBaseDir); } } + } catch (ModelIncorrectException e) { + MessageUtil.fail(status,e.getMessage()); } finally { if (!result || spec.runtime.isVerbose()) { // more debugging context in case of failure MessageUtil.info(handler, "spec: " + spec.toLongString()); @@ -293,6 +300,8 @@ public class IncCompilerRun implements IAjcRun { protected ArrayList classesAdded; protected ArrayList classesRemoved; protected ArrayList classesUpdated; + + protected String checkModel; /** * skip description, skip sourceLocation, @@ -312,6 +321,7 @@ public class IncCompilerRun implements IAjcRun { classesAdded = new ArrayList(); classesRemoved = new ArrayList(); classesUpdated = new ArrayList(); + checkModel=""; } protected void initClone(Spec spec) @@ -341,8 +351,13 @@ public class IncCompilerRun implements IAjcRun { public void setTag(String input) { tag = input; } + + public void setCheckModel(String thingsToCheck) { + this.checkModel=thingsToCheck; + } + public String toString() { - return "IncCompile.Spec(" + tag + ", " + super.toString() + ")"; + return "IncCompile.Spec(" + tag + ", " + super.toString() + ",["+checkModel+"])"; } /** override to set dirToken to Sandbox.CLASSES and default suffix to ".class" */ diff --git a/testing/src/org/aspectj/testing/xml/SoftMessage.java b/testing/src/org/aspectj/testing/xml/SoftMessage.java index 9c8ca57e1..88869e757 100644 --- a/testing/src/org/aspectj/testing/xml/SoftMessage.java +++ b/testing/src/org/aspectj/testing/xml/SoftMessage.java @@ -222,6 +222,8 @@ public class SoftMessage implements IMessage { public boolean isFailed() { return kind == IMessage.FAIL; } + + public boolean getDeclared() { return false; } /** @return non-null String with simple message */ final public String getMessage() { diff --git a/tests/ajcTestSuite.dtd b/tests/ajcTestSuite.dtd index 45c00f0c0..c324963d7 100644 --- a/tests/ajcTestSuite.dtd +++ b/tests/ajcTestSuite.dtd @@ -30,6 +30,7 @@ <!ELEMENT inc-compile (dir-changes*,message*)>
<!ATTLIST inc-compile tag CDATA #REQUIRED >
<!ATTLIST inc-compile fresh CDATA #IMPLIED >
+ <!ATTLIST inc-compile checkModel CDATA #IMPLIED >
<!ELEMENT run (dir-changes*,message*)>
<!ATTLIST run class CDATA #REQUIRED >
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 @@ + +<!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd"> + +<suite> +<!-- + In order for these tests to pass you have to flip this flag to true: + AsmManager.attemptIncrementalModelRepairs + + If you want to debug the output from the tests, you might want uncomment + the static initializer in AsmManager which will enable you to collect + detailed information on model processing. +--> + +<!-- + These tests utilise the inc-compile test harness option but I've extended it + with a checkModel option which enables me to check information about the model + after a incremental compilation step. +--> + +<!-- + asm relationships for inter type declarations are tricky things. + Today, because type mungers don't remember where they came from in attribute form, + the relationships for ITDs are created during source compilation. When building incrementally, + we are really doing a binary weave of 'everything else' with the source for the file that + has changed. In this case the relationships for ITDs are not added. This makes managing + them incrementally in the model rather tough! + + The solution is to make them remember where they came from. This would mean we can create + the relationships during weave time and so they will be created when either doing a + source compilation or a binary weave. The support is in ResolvedTypeMunger to remember + where they came from (you just have to flick a switch) but I haven't switched it on + because we need to version *all* aspectj attributes properly so that we don't end up with + a migration nightmare. If ITD attributes remembered their location in a particular version + of AspectJ then everyone would need to recompile their code from source with that version. + If we keep changing the attributes, we keep having this problem. If we include a *version* + number in every attribute we can make the compiler more robust to coping with 'old' attributes + that might be missing certain options or values. + + Hence the first test here is not complete... + +--> + <ajc-test dir="incremental/model/introduction" + title="Testing incremental structure model: Intertype declarations (and a declare parents)" + keywords="incremental-test,model-test" > + <compile staging="true" options="-incremental,-emacssym" sourceroots="."/> + <inc-compile tag="20"/> <!-- Just 'touched' one file --> + <inc-compile tag="30"/> <!-- Just 'touched another aspect --> + </ajc-test> + + <ajc-test dir="incremental/model/intertype" + title="Testing incremental structure model: Intertype field declarations" + keywords="incremental-test,model-test" > + <compile staging="true" options="-incremental,-emacssym" sourceroots="."/> + <inc-compile tag="20" checkModel="inter-type field=2,RelationshipMapSize=3"/> <!-- BetaA intertypes int i and String s --> + <inc-compile tag="30" checkModel="inter-type field=1,RelationshipMapSize=2"/> <!-- BetaA takes the String intertype away --> + </ajc-test> + + <ajc-test dir="incremental/model/weaving2" + title="Testing incremental structure model: Weaving handlers" + keywords="incremental-test,model-test" > + <compile staging="true" options="-incremental,-emacssym" sourceroots="."/> + <inc-compile tag="20" checkModel="code=1,advice=1,RelationshipMapSize=2"/> <!-- BetaA has a new piece of handler advice added --> + <inc-compile tag="30" checkModel="code=1,advice=2,RelationshipMapSize=3"/> <!-- secondary.GammaA added, also advises the same handler --> + <inc-compile tag="40" checkModel="code=1,advice=1,RelationshipMapSize=2"/> <!-- primary.BetaA deleted --> + </ajc-test> + + <ajc-test dir="incremental/model/weaving" + title="Testing incremental structure model: Weaving" + keywords="incremental-test,model-test" > + <compile staging="true" options="-incremental,-emacssym" sourceroots="."/> + <inc-compile tag="20" checkModel="code=2,advice=2,java source file=3,RelationshipMapSize=4"/> <!-- BetaA has a new piece of advice added --> + <inc-compile tag="30" checkModel="code=1,advice=1,RelationshipMapSize=2"/> <!-- BetaA has a piece of advice removed --> + <inc-compile tag="40" checkModel="code=0,RelationshipMapSize=0,advice=0"/> <!-- BetaA other piece of advice removed (now empty) --> + </ajc-test> + + + <ajc-test dir="incremental/model/sourcefiles_updating" + title="Testing incremental structure model: Updating files" + keywords="incremental-test,model-test" > + <compile staging="true" options="-incremental,-emacssym" sourceroots="."/> + <!-- On first compile, 5 source files in model, 'root','Alpha','Beta','Gamma','Delta' --> + <inc-compile tag="20" checkModel="java source file=5,method=4,class=3,FileMapSize=4"/> <!-- Beta changed, method added --> + <inc-compile tag="30" checkModel="java source file=5,method=4,class=4,advice=1"/> <!-- Delta changed, class added --> + <inc-compile tag="40" checkModel="advice=2"/> <!-- Gamma changed, advice added --> + <inc-compile tag="50" checkModel="advice=2,pointcut=1"/> <!-- Gamma changed, pointcut added --> + <inc-compile tag="60" checkModel="advice=0,pointcut=1"/> <!-- Gamma changed, both advice removed --> + </ajc-test> + + <ajc-test dir="incremental/model/sourcefiles_addremove" + title="Testing incremental structure model: Adding and removing files" + keywords="incremental-test,model-test" > + <compile staging="true" options="-incremental,-emacssym" sourceroots="."/> + <!-- On first compile, two source files in model, 'root' and 'Alpha' --> + <inc-compile tag="20" checkModel="java source file=3,FileMapSize=2"/> <!-- Adds primary.Beta class --> + <inc-compile tag="30" checkModel="java source file=4"/> <!-- Adds secondary.Gamma aspect --> + <inc-compile tag="40" checkModel="java source file=5,package=2,FileMapSize=4"/> <!-- Adds seconday.Delta class --> + <inc-compile tag="50" checkModel="java source file=4,package=2"/> <!-- Deletes Gamma aspect --> + <inc-compile tag="60" checkModel="java source file=2,FileMapSize=1"/> <!-- Deletes Beta and Delta classes --> + </ajc-test> + + +</suite>
\ No newline at end of file diff --git a/tests/incremental/model/intertype/primary/Alpha.java b/tests/incremental/model/intertype/primary/Alpha.java new file mode 100644 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)+"]"; + } } |