- Enhanced structure model support. - *Incremental* structure model support written and tested (currently switched off, see incModelTests.xml) - -showWeaveInfo compiler option - existence of a 'runtimetest' surfaced through relationships - UI can determine if errors/warnings came from DEOWs. - Code to enable type mungers to remember source locations written (currently switched off)tags/for_ajdt1_1_12
@@ -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 |
@@ -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. |
@@ -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(); ) { |
@@ -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; |
@@ -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"); |
@@ -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); | |||
// |
@@ -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) { |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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()); | |||
} | |||
} | |||
} | |||
@@ -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(); | |||
} |
@@ -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); |
@@ -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) { |
@@ -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(); | |||
} |
@@ -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(); | |||
} | |||
} | |||
@@ -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; | |||
} | |||
} | |||
@@ -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; | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
@@ -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 | |||
*/ |
@@ -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; |
@@ -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; } | |||
} | |||
} |
@@ -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()); |
@@ -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\ |
@@ -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; |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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); |
@@ -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; | |||
} | |||
} |
@@ -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); |
@@ -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; |
@@ -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); |
@@ -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++) { |
@@ -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; | |||
} | |||
@@ -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; | |||
} |
@@ -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(); |
@@ -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" */ |
@@ -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() { |
@@ -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 > |
@@ -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> |
@@ -0,0 +1,7 @@ | |||
package primary; | |||
public class Alpha { | |||
public static void main(String [] argv) { | |||
} | |||
} | |||
@@ -0,0 +1,8 @@ | |||
package secondary; | |||
import primary.Alpha; | |||
public aspect BetaA { | |||
int Alpha.i; | |||
String Alpha.s; | |||
} |
@@ -0,0 +1,7 @@ | |||
package secondary; | |||
import primary.Alpha; | |||
public aspect BetaA { | |||
String Alpha.s; | |||
} |
@@ -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 ); | |||
} | |||
} |
@@ -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 ); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -0,0 +1,7 @@ | |||
package primary; | |||
public class Alpha { | |||
public static void main (String[] args) { | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
package primary; | |||
public class Beta { | |||
public static void main(String[] argv) { | |||
sayhi(); | |||
} | |||
public static void sayhi() { | |||
System.err.println("Hi"); | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
package primary; | |||
public class Beta { | |||
public static void main(String[] argv) { | |||
sayhi(); | |||
} | |||
public static void sayhi() { | |||
System.err.println("Hi"); | |||
} | |||
} |
@@ -0,0 +1,5 @@ | |||
package secondary; | |||
public class Delta { | |||
public static void foo() { } | |||
} |
@@ -0,0 +1,5 @@ | |||
package secondary; | |||
public class Delta { | |||
public static void foo() { } | |||
} |
@@ -0,0 +1,7 @@ | |||
package secondary; | |||
aspect Gamma { | |||
before(): call(* *(..)) { | |||
} | |||
} | |||
@@ -0,0 +1,7 @@ | |||
package secondary; | |||
aspect Gamma { | |||
before(): call(* *(..)) { | |||
} | |||
} | |||
@@ -0,0 +1,7 @@ | |||
package primary; | |||
public class Alpha { | |||
public static void main (String[] args) { | |||
} | |||
} |
@@ -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"); | |||
} | |||
} |
@@ -0,0 +1,7 @@ | |||
package primary; | |||
public class Beta { | |||
public static void main(String[] argv) { | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
package secondary; | |||
// Extra class added over Delta.java | |||
public class Delta { | |||
public static void foo() { } | |||
} | |||
class DeltaExtra { | |||
} |
@@ -0,0 +1,5 @@ | |||
package secondary; | |||
public class Delta { | |||
public static void foo() { } | |||
} |
@@ -0,0 +1,10 @@ | |||
package secondary; | |||
aspect Gamma { | |||
before(): call(* *(..)) { | |||
} | |||
after(): call(* *(..)) { | |||
} | |||
} | |||
@@ -0,0 +1,13 @@ | |||
package secondary; | |||
aspect Gamma { | |||
pointcut calls(): call(* *(..)); | |||
before(): calls() { | |||
} | |||
after(): calls() { | |||
} | |||
} | |||
@@ -0,0 +1,8 @@ | |||
package secondary; | |||
aspect Gamma { | |||
pointcut calls(): call(* *(..)); | |||
} | |||
@@ -0,0 +1,7 @@ | |||
package secondary; | |||
aspect Gamma { | |||
before(): call(* *(..)) { | |||
} | |||
} | |||
@@ -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 ""; | |||
} | |||
} |
@@ -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"); | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
package primary; | |||
public aspect BetaA { | |||
pointcut m2call(): call(* m2(..)); | |||
before(): m2call() { | |||
System.err.println("m2 got called"); | |||
} | |||
} |
@@ -0,0 +1,5 @@ | |||
package primary; | |||
public aspect BetaA { | |||
} |
@@ -0,0 +1,10 @@ | |||
package primary; | |||
public aspect BetaA { | |||
pointcut m1call(): call(* m1(..)); | |||
before(): m1call() { | |||
System.err.println("m1 got called"); | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
package primary; | |||
public aspect BetaA { | |||
pointcut handlers(): handler(Throwable); | |||
before(): handlers() { | |||
System.err.println("xxx"); | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
package primary; | |||
public aspect BetaA { | |||
pointcut handlers(): handler(Throwable); | |||
before(): handlers() { | |||
System.err.println("xxx"); | |||
} | |||
} |
@@ -0,0 +1,4 @@ | |||
package primary; | |||
public aspect BetaA { | |||
} |
@@ -0,0 +1,8 @@ | |||
package primary; | |||
public aspect GammaA { | |||
pointcut handlers(): handler(Throwable); | |||
before(): handlers() { | |||
System.err.println("xxx"); | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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) { |
@@ -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) { |
@@ -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); | |||
} |
@@ -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() { |
@@ -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) { |
@@ -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) { |
@@ -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(); | |||
} | |||
@@ -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); |
@@ -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++; | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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)+"]"; | |||
} | |||
} |