diff options
author | Andy Clement <aclement@pivotal.io> | 2017-10-20 12:48:41 -0700 |
---|---|---|
committer | Andy Clement <aclement@pivotal.io> | 2017-10-20 12:48:41 -0700 |
commit | a24d15f5e7538985ca9718d9e78635bb53372736 (patch) | |
tree | ae5fec85a2442cc94a59127fc4c964723c69c6d0 | |
parent | e9c279bc3e974f57053b718c895ad69194cd1dc0 (diff) | |
download | aspectj-a24d15f5e7538985ca9718d9e78635bb53372736.tar.gz aspectj-a24d15f5e7538985ca9718d9e78635bb53372736.zip |
Adjust how classpath entries manipulated for Java9 support
Prior to this AspectJ would discard ignore the ClasspathEntry
objects built by JDT and just work with the classpath as a string,
driving the JDT FileSystem to rebuild classpath entries again at
a later date using the string. This is more complex in Java9 because
the string representation was losing whether some entries came in
via modulepath. ClasspathEntry construction for modulepath entries
is non trivial (since the module-info must be processed).
The new version will cache some of the ClasspathEntry objects (those
built for modulepaths) and do more work on the AspectJ side building
classpath entries in general. It now passes these entries to a
different FileSystem entry point rather than the entry point that
takes a string path.
11 files changed, 504 insertions, 80 deletions
diff --git a/ajde.core/src/org/aspectj/ajde/core/internal/AjdeCoreBuildManager.java b/ajde.core/src/org/aspectj/ajde/core/internal/AjdeCoreBuildManager.java index 4ab05c968..5577a01af 100644 --- a/ajde.core/src/org/aspectj/ajde/core/internal/AjdeCoreBuildManager.java +++ b/ajde.core/src/org/aspectj/ajde/core/internal/AjdeCoreBuildManager.java @@ -37,6 +37,7 @@ import org.aspectj.bridge.ISourceLocation; import org.aspectj.bridge.Message; import org.aspectj.bridge.SourceLocation; import org.aspectj.bridge.context.CompilationAndWeavingContext; +import org.aspectj.org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.aspectj.util.LangUtil; @@ -277,6 +278,14 @@ public class AjdeCoreBuildManager { both.addAll(configClasspath); both.addAll(toAdd); config.setClasspath(both); + Classpath[] checkedClasspaths = config.getCheckedClasspaths(); + ArrayList<Classpath> cps = parser.handleClasspath(toAdd, compilerConfig.getProjectEncoding()); + Classpath[] newCheckedClasspaths = new Classpath[checkedClasspaths.length+cps.size()]; + System.arraycopy(checkedClasspaths, 0, newCheckedClasspaths, 0, checkedClasspaths.length); + for (int i=0;i<cps.size();i++) { + newCheckedClasspaths[checkedClasspaths.length+i] = cps.get(i); + } + config.setCheckedClasspaths(newCheckedClasspaths); } } @@ -295,18 +304,18 @@ public class AjdeCoreBuildManager { } // Process the INPATH - mergeInto(config.getInpath(), compilerConfig.getInpath()); + config.addToInpath(compilerConfig.getInpath()); // bug 168840 - calling 'setInPath(..)' creates BinarySourceFiles which // are used to see if there have been changes in classes on the inpath if (config.getInpath() != null) { - config.setInPath(config.getInpath()); + config.processInPath(); } // Process the SOURCE PATH RESOURCES config.setSourcePathResources(compilerConfig.getSourcePathResources()); // Process the ASPECTPATH - mergeInto(config.getAspectpath(), compilerConfig.getAspectPath()); + config.addToAspectpath(compilerConfig.getAspectPath()); // Process the JAVA OPTIONS MAP Map<String,String> jom = compilerConfig.getJavaOptionsMap(); @@ -347,17 +356,6 @@ public class AjdeCoreBuildManager { return config; } - private <T> void mergeInto(Collection<T> target, Collection<T> source) { - if ((null == target) || (null == source)) { - return; - } - for (T next : source) { - if (!target.contains(next)) { - target.add(next); - } - } - } - /** * Helper method for configure build options. This reads all command-line options specified in the non-standard options text * entry and sets any corresponding unset values in config. diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java index fae1aadd3..c061208f0 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java @@ -17,8 +17,10 @@ import org.aspectj.ajdt.internal.core.builder.AjBuildConfig; import org.aspectj.bridge.*; import org.aspectj.org.eclipse.jdt.core.compiler.CategorizedProblem; import org.aspectj.org.eclipse.jdt.internal.compiler.apt.dispatch.AptProblem; +import org.aspectj.org.eclipse.jdt.internal.compiler.batch.FileSystem; import org.aspectj.org.eclipse.jdt.internal.compiler.batch.Main; import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.aspectj.org.eclipse.jdt.internal.compiler.env.IModule; import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.aspectj.util.FileUtil; import org.aspectj.util.LangUtil; @@ -162,6 +164,11 @@ public class BuildArgParser extends Main { javaArgList.addAll(parser.getUnparsedArgs()); super.configure(javaArgList.toArray(new String[javaArgList.size()])); + if (parser.getModuleInfoArgument() != null) { + IModule moduleDesc = super.getModuleDesc(parser.getModuleInfoArgument()); + buildConfig.setModuleDesc(moduleDesc); + } + if (!proceed) { buildConfig.doNotProceed(); return buildConfig; @@ -181,8 +188,14 @@ public class BuildArgParser extends Main { } if (setClasspath) { + // This computed classpaths will be missing aspectpaths, inpaths, add those first buildConfig.setClasspath(getClasspath(parser)); + buildConfig.setModulepath(getModulepath(parser)); + buildConfig.setModulepathClasspathEntries(handleModulepath(parser.modulepath)); + buildConfig.setModulesourcepath(getModulesourcepath(parser)); + buildConfig.setModulesourcepathClasspathEntries(handleModuleSourcepath(parser.modulesourcepath)); buildConfig.setBootclasspath(getBootclasspath(parser)); + // TODO other paths (module/module source) } if (incrementalMode && (0 == buildConfig.getSourceRoots().size())) { @@ -214,8 +227,7 @@ public class BuildArgParser extends Main { } /* Search aspectpath */ - for (Iterator i = buildConfig.getAspectpath().iterator(); i.hasNext();) { - File pathElement = (File) i.next(); + for (File pathElement: buildConfig.getAspectpath()) { if (!pathElement.isDirectory() && pathElement.equals(outjar)) { String message = WeaverMessages.format(WeaverMessages.OUTJAR_IN_INPUT_PATH); MessageUtil.error(handler, message); @@ -237,6 +249,28 @@ public class BuildArgParser extends Main { return buildConfig; } + private void augmentCheckedClasspaths(List<File> extraPathEntries, String encoding) { + if (extraPathEntries.size() == 0) { + return; + } + ArrayList<String> asList = toArrayList(extraPathEntries); + List<FileSystem.Classpath> newClasspathEntries = handleClasspath(asList, encoding); + FileSystem.Classpath[] newCheckedClasspaths = new FileSystem.Classpath[checkedClasspaths.length + newClasspathEntries.size()]; + System.arraycopy(checkedClasspaths, 0, newCheckedClasspaths, 0, checkedClasspaths.length); + for (int i = 0; i < newClasspathEntries.size();i++) { + newCheckedClasspaths[i + checkedClasspaths.length] = newClasspathEntries.get(i); + } + checkedClasspaths = newCheckedClasspaths; + } + + private ArrayList<String> toArrayList(java.util.List<File> files) { + ArrayList<String> arrayList = new ArrayList<String>(); + for (File file: files) { + arrayList.add(file.getAbsolutePath()); + } + return arrayList; + } + public void printVersion() { final String version = bind("misc.version", //$NON-NLS-1$ new String[] { bind("compiler.name"), //$NON-NLS-1$ @@ -325,7 +359,23 @@ public class BuildArgParser extends Main { } return ret; } + + public List<String> getModulepath(AjcConfigParser parser) { + List<String> ret = new ArrayList<String>(); + addClasspath(parser.modulepath, ret); + return ret; + } + public List<String> getModulesourcepath(AjcConfigParser parser) { + List<String> ret = new ArrayList<String>(); + addClasspath(parser.modulesourcepath, ret); + return ret; + } + + public ArrayList<FileSystem.Classpath> handleClasspath(ArrayList<String> classpaths, String customEncoding) { + return super.handleClasspath(classpaths, customEncoding); + } + /** * If the classpath is not set, we use the environment's java.class.path, but remove the aspectjtools.jar entry from that list * in order to prevent wierd bootstrap issues (refer to bug#39959). @@ -380,6 +430,9 @@ public class BuildArgParser extends Main { } private void addClasspath(String classpath, List<String> classpathCollector) { + if (classpath == null) { + return; + } StringTokenizer tokenizer = new StringTokenizer(classpath, File.pathSeparator); while (tokenizer.hasMoreTokens()) { classpathCollector.add(tokenizer.nextToken()); @@ -389,10 +442,13 @@ public class BuildArgParser extends Main { private class AjcConfigParser extends ConfigParser { private String bootclasspath = null; private String classpath = null; + private String modulepath = null; + private String modulesourcepath = null; private String extdirs = null; private List unparsedArgs = new ArrayList(); private AjBuildConfig buildConfig; private IMessageHandler handler; + private String moduleInfoArgument; public AjcConfigParser(AjBuildConfig buildConfig, IMessageHandler handler) { this.buildConfig = buildConfig; @@ -402,38 +458,48 @@ public class BuildArgParser extends Main { public List getUnparsedArgs() { return unparsedArgs; } + + public String getModuleInfoArgument() { + return this.moduleInfoArgument; + } /** * Extract AspectJ-specific options (except for argfiles). Caller should warn when sourceroots is empty but in incremental * mode. Signals warnings or errors through handler set in constructor. */ - public void parseOption(String arg, LinkedList args) { // XXX use ListIterator.remove() + public void parseOption(String arg, LinkedList<Arg> args) { // XXX use ListIterator.remove() int nextArgIndex = args.indexOf(arg) + 1; // XXX assumes unique // trim arg? buildConfig.setXlazyTjp(true); // now default - MINOR could be pushed down and made default at a lower level if (LangUtil.isEmpty(arg)) { showWarning("empty arg found"); + } else if (arg.endsWith("module-info.java")) { + moduleInfoArgument = arg; } else if (arg.equals("-inpath")) { if (args.size() > nextArgIndex) { // buildConfig.getAjOptions().put(AjCompilerOptions.OPTION_Inpath, CompilerOptions.PRESERVE); - List<File> inPath = buildConfig.getInpath(); StringTokenizer st = new StringTokenizer(((ConfigParser.Arg) args.get(nextArgIndex)).getValue(), File.pathSeparator); + boolean inpathChange = false; while (st.hasMoreTokens()) { String filename = st.nextToken(); File file = makeFile(filename); if (FileUtil.isZipFile(file)) { - inPath.add(file); + buildConfig.addToInpath(file); + inpathChange = true; } else { if (file.isDirectory()) { - inPath.add(file); + buildConfig.addToInpath(file); + inpathChange = true; } else { showWarning("skipping missing, empty or corrupt inpath entry: " + filename); } } } - buildConfig.setInPath(inPath); + if (inpathChange) { + buildConfig.processInPath(); + } args.remove(args.get(nextArgIndex)); } } else if (arg.equals("-injars")) { @@ -467,7 +533,8 @@ public class BuildArgParser extends Main { String filename = st.nextToken(); File jarFile = makeFile(filename); if (FileUtil.isZipFile(jarFile) || jarFile.isDirectory()) { - buildConfig.getAspectpath().add(jarFile); +// buildConfig.getAspectpath().add(jarFile); + buildConfig.addToAspectpath(jarFile); } else { showWarning("skipping missing, empty or corrupt aspectpath entry: " + filename); } @@ -659,10 +726,47 @@ public class BuildArgParser extends Main { } } classpath = cp.toString(); - args.remove(args.get(nextArgIndex)); + Arg pathArg = args.get(nextArgIndex); + unparsedArgs.add("-classpath"); + unparsedArgs.add(pathArg.getValue()); + args.remove(pathArg); } else { showError("-classpath requires classpath entries"); } + } else if (arg.equals("--module-path") || arg.equals("-p")) { + if (args.size() > nextArgIndex) { + String mpArg = ((ConfigParser.Arg) args.get(nextArgIndex)).getValue(); + modulepath = mpArg; +// StringBuffer mp = new StringBuffer(); +// StringTokenizer strTok = new StringTokenizer(mpArg, File.pathSeparator); +// while (strTok.hasMoreTokens()) { +// mp.append(makeFile(strTok.nextToken())); +// if (strTok.hasMoreTokens()) { +// mp.append(File.pathSeparator); +// } +// } +// modulepath = mp.toString(); + args.remove(args.get(nextArgIndex)); + } else { + showError("--module-path requires modulepath entries"); + } + } else if (arg.equals("--module-source-path") || arg.equals("-p")) { + if (args.size() > nextArgIndex) { + String mspArg = ((ConfigParser.Arg) args.get(nextArgIndex)).getValue(); + modulesourcepath = mspArg; +// StringBuffer mp = new StringBuffer(); +// StringTokenizer strTok = new StringTokenizer(mpArg, File.pathSeparator); +// while (strTok.hasMoreTokens()) { +// mp.append(makeFile(strTok.nextToken())); +// if (strTok.hasMoreTokens()) { +// mp.append(File.pathSeparator); +// } +// } +// modulepath = mp.toString(); + args.remove(args.get(nextArgIndex)); + } else { + showError("--module-source-path requires modulepath entries"); + } } else if (arg.equals("-extdirs")) { if (args.size() > nextArgIndex) { String extdirsArg = ((ConfigParser.Arg) args.get(nextArgIndex)).getValue(); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/ConfigParser.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/ConfigParser.java index afa936db3..b92a4b439 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/ConfigParser.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/ConfigParser.java @@ -176,7 +176,7 @@ public class ConfigParser { } } - protected void parseOption(String arg, LinkedList args) { + protected void parseOption(String arg, LinkedList<Arg> args) { showWarning("unrecognized option: " + arg); } @@ -191,22 +191,22 @@ public class ConfigParser { throw new ParseException(CONFIG_MSG + message, location); } - void parseArgs(LinkedList args) { + void parseArgs(LinkedList<Arg> args) { while (args.size() > 0) { parseOneArg(args); } } - protected Arg removeArg(LinkedList args) { + protected Arg removeArg(LinkedList<Arg> args) { if (args.size() == 0) { showError("value missing"); return null; } else { - return (Arg) args.removeFirst(); + return args.removeFirst(); } } - protected String removeStringArg(LinkedList args) { + protected String removeStringArg(LinkedList<Arg> args) { Arg arg = removeArg(args); if (arg == null) { return null; @@ -235,7 +235,7 @@ public class ConfigParser { return false; } - void parseOneArg(LinkedList args) { + void parseOneArg(LinkedList<Arg> args) { Arg arg = removeArg(args); String v = arg.getValue(); location = arg.getLocation(); @@ -245,6 +245,9 @@ public class ConfigParser { parseConfigFileHelper(makeFile(removeArg(args).getValue())); } else if (isSourceFileName(v)) { addFileOrPattern(makeFile(v)); + if (v.endsWith("module-info.java")) { + parseOption(arg.getValue(), args); + } } else if (isXml(v)) { addXmlFile(makeFile(v)); } else { @@ -284,6 +287,10 @@ public class ConfigParser { private Location location; private String value; + public String toString() { + return "Arg[location="+location+" value="+value+"]"; + } + public Arg(String value, Location location) { this.value = value; this.location = location; diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java index 52ad76f5b..935eb3cee 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java @@ -107,6 +107,10 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC INameEnvironment nameEnvironment) { super(typeRequestor, options, problemReporter, nameEnvironment); } + + public AjLookupEnvironment(LookupEnvironment env, ModuleBinding moduleBinding) { + super(env, moduleBinding); + } // ??? duplicates some of super's code public void completeTypeBindings() { @@ -1474,6 +1478,13 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC this.factory.cleanup(); super.reset(); } + + @Override + public LookupEnvironment wrapInModuleEnvironment(ModuleBinding moduleBinding) { + AjLookupEnvironment newAjLookupEnvironment = new AjLookupEnvironment(this, moduleBinding); + newAjLookupEnvironment.factory = this.factory; + return newAjLookupEnvironment; + } } // commented out, supplied as info on how to manipulate annotations in an diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java index 98bd0484e..0587c4462 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java @@ -20,14 +20,29 @@ import java.io.File; import java.io.FileFilter; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.StringTokenizer; import org.aspectj.ajdt.ajc.BuildArgParser; import org.aspectj.ajdt.internal.compiler.CompilationResultDestinationManager; +import org.aspectj.org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; +import org.aspectj.org.eclipse.jdt.internal.compiler.batch.ClasspathJar; +import org.aspectj.org.eclipse.jdt.internal.compiler.batch.ClasspathJrt; +import org.aspectj.org.eclipse.jdt.internal.compiler.batch.ClasspathLocation; +import org.aspectj.org.eclipse.jdt.internal.compiler.batch.FileSystem; +import org.aspectj.org.eclipse.jdt.internal.compiler.batch.Main; +import org.aspectj.org.eclipse.jdt.internal.compiler.batch.ModuleFinder; +import org.aspectj.org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; +import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.aspectj.org.eclipse.jdt.internal.compiler.env.IModule; +import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser; +import org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemReporter; import org.aspectj.util.FileUtil; /** @@ -35,7 +50,9 @@ import org.aspectj.util.FileUtil; * an AjCompilerOptions instance */ public class AjBuildConfig implements CompilerConfigurationChangeFlags { - + + public static final Classpath[] NO_CHECKED_CLASSPATHS = new Classpath[0]; + private boolean shouldProceed = true; public static final String AJLINT_IGNORE = "ignore"; @@ -59,8 +76,16 @@ public class AjBuildConfig implements CompilerConfigurationChangeFlags { private Map<String, File> sourcePathResources = new HashMap<String, File>(); private List<File> aspectpath = new ArrayList<File>(); private List<String> classpath = new ArrayList<String>(); + private List<String> modulepath = new ArrayList<String>(); + // Expensive to compute (searching modules, parsing module-info) + private ArrayList<Classpath> modulepathClasspathEntries = null; + private List<String> modulesourcepath = new ArrayList<String>(); + // Expensive to compute (searching modules, parsing module-info) + private ArrayList<Classpath> modulesourcepathClasspathEntries = null; + private Classpath[] checkedClasspaths = null; private List<String> bootclasspath = new ArrayList<String>(); private List<String> cpElementsWithModifiedContents = new ArrayList<String>(); + private IModule moduleDesc; private File configFile; private String lintMode = AJLINT_DEFAULT; @@ -205,6 +230,53 @@ public class AjBuildConfig implements CompilerConfigurationChangeFlags { public void setClasspath(List<String> classpath) { this.classpath = classpath; + checkedClasspaths = null; + } + + public List<String> getModulepath() { + return modulepath; + } + + public List<String> getModulesourcepath() { + return modulesourcepath; + } + + public void setModulepath(List<String> modulepath) { + this.modulepath = modulepath; + checkedClasspaths = null; + } + + public void setModulesourcepath(List<String> modulesourcepath) { + this.modulesourcepath = modulesourcepath; + checkedClasspaths = null; + } + + public void setCheckedClasspaths(Classpath[] checkedClasspaths) { + this.checkedClasspaths = checkedClasspaths; + checkedClasspaths = null; + } + + private List<Classpath> processFilePath(List<File> path, java.lang.String encoding) { + List<Classpath> entries = new ArrayList<Classpath>(); + for (File file: path) { + entries.add(FileSystem.getClasspath(file.getAbsolutePath(), encoding, null, ClasspathLocation.BINARY)); + } + return entries; + } + + private List<Classpath> processStringPath(List<String> path, java.lang.String encoding) { + List<Classpath> entries = new ArrayList<Classpath>(); + for (String file: path) { + entries.add(FileSystem.getClasspath(file, encoding, null, ClasspathLocation.BINARY)); + } + return entries; + } + + public Classpath[] getCheckedClasspaths() { + if (checkedClasspaths == null) { + computeCheckedClasspath(); + } + return checkedClasspaths; } public List<String> getBootclasspath() { @@ -225,7 +297,7 @@ public class AjBuildConfig implements CompilerConfigurationChangeFlags { public List<File> getInpath() { // Elements of the list are either archives (jars/zips) or directories - return inPath; + return Collections.unmodifiableList(inPath); } public List<File> getInJars() { @@ -246,11 +318,10 @@ public class AjBuildConfig implements CompilerConfigurationChangeFlags { public void setInJars(List<File> sourceJars) { this.inJars = sourceJars; + checkedClasspaths = null; } - public void setInPath(List<File> dirsOrJars) { - inPath = dirsOrJars; - + public void processInPath() { // remember all the class files in directories on the inpath binaryFiles = new ArrayList<BinarySourceFile>(); FileFilter filter = new FileFilter() { @@ -258,7 +329,7 @@ public class AjBuildConfig implements CompilerConfigurationChangeFlags { return pathname.getPath().endsWith(".class"); } }; - for (Iterator<File> iter = dirsOrJars.iterator(); iter.hasNext();) { + for (Iterator<File> iter = inPath.iterator(); iter.hasNext();) { File inpathElement = iter.next(); if (inpathElement.isDirectory()) { File[] files = FileUtil.listFiles(inpathElement, filter); @@ -269,6 +340,12 @@ public class AjBuildConfig implements CompilerConfigurationChangeFlags { } } + public void setInPath(List<File> dirsOrJars) { + inPath = dirsOrJars; + checkedClasspaths = null; + processInPath(); + } + public List<File> getSourceRoots() { return sourceRoots; } @@ -308,16 +385,18 @@ public class AjBuildConfig implements CompilerConfigurationChangeFlags { public List<String> getFullClasspath() { List<String> full = new ArrayList<String>(); full.addAll(getBootclasspath()); // XXX Is it OK that boot classpath overrides inpath/injars/aspectpath? - for (Iterator<File> i = inJars.iterator(); i.hasNext();) { - full.add((i.next()).getAbsolutePath()); + for (File file: inJars) { + full.add(file.getAbsolutePath()); } - for (Iterator<File> i = inPath.iterator(); i.hasNext();) { - full.add((i.next()).getAbsolutePath()); + for (File file: inPath) { + full.add(file.getAbsolutePath()); } - for (Iterator<File> i = aspectpath.iterator(); i.hasNext();) { - full.add((i.next()).getAbsolutePath()); + for (File file: aspectpath) { + full.add(file.getAbsolutePath()); } full.addAll(getClasspath()); + full.addAll(getModulepath()); + full.addAll(getModulesourcepath()); // if (null != outputDir) { // full.add(outputDir.getAbsolutePath()); // } else if (null != outputJar) { @@ -335,11 +414,22 @@ public class AjBuildConfig implements CompilerConfigurationChangeFlags { } public List<File> getAspectpath() { - return aspectpath; + return Collections.unmodifiableList(aspectpath); } public void setAspectpath(List<File> aspectpath) { this.aspectpath = aspectpath; + checkedClasspaths = null; + } + + public void addToAspectpath(File file) { + this.aspectpath.add(file); + checkedClasspaths = null; + } + + public void addToInjars(File file) { + this.inJars.add(file); + checkedClasspaths = null; } /** @return true if any config file, sourceroots, sourcefiles, injars or inpath */ @@ -765,4 +855,116 @@ public class AjBuildConfig implements CompilerConfigurationChangeFlags { public void setProjectEncoding(String projectEncoding) { options.defaultEncoding = projectEncoding; } + + public String getProjectEncoding() { + return options.defaultEncoding; + } + + public void setModuleDesc(IModule moduleDesc) { + this.moduleDesc = moduleDesc; + } + + public IModule getModuleDesc() { + return moduleDesc; + } + + public void addToInpath(Set<File> newInpathEntries) { + if (newInpathEntries != null && newInpathEntries.size() != 0) { + for (File newInpathEntry: newInpathEntries) { + if (!inPath.contains(newInpathEntry)) { + inPath.add(newInpathEntry); + } + } + checkedClasspaths = null; + } + } + + public void addToInpath(File newInpathEntry) { +// if (!inPath.contains(newInpathEntry)) { + inPath.add(newInpathEntry); +// } + checkedClasspaths = null; + } + + public void addToAspectpath(Set<File> newAspectpathEntries) { + if (newAspectpathEntries != null && newAspectpathEntries.size() != 0) { + for (File newAspectpathEntry: newAspectpathEntries) { + if (!aspectpath.contains(newAspectpathEntry)) { + aspectpath.add(newAspectpathEntry); + } + } + checkedClasspaths = null; + } + } + + public void setModulepathClasspathEntries(ArrayList<Classpath> modulepathClasspathEntries) { + this.modulepathClasspathEntries = modulepathClasspathEntries; + } + + public void setModulesourcepathClasspathEntries(ArrayList<Classpath> modulesourcepathClasspathEntries) { + this.modulesourcepathClasspathEntries = modulesourcepathClasspathEntries; + } + + public File removeAspectPathEntry(int i) { + checkedClasspaths = null; + return aspectpath.remove(i); + } + + public String removeClasspathEntry(int i) { + checkedClasspaths = null; + return classpath.remove(i); + } + + public File removeInpathEntry(int i) { + checkedClasspaths = null; + return inPath.remove(i); + } + + public File removeInjarsEntry(int i) { + checkedClasspaths = null; + return inJars.remove(0); + } + + + // This is similar to the calculation done in Main.setPaths() but it isn't as sophisticated + // as that one (doesn't need to be) and it also considers the additional paths for an + // AspectJ project (aspectpath/inpath/injars) + private void computeCheckedClasspath() { + // Follow what we do in getFullClasspath(): + // bootclasspath, injars, inpath, aspectpath, classpath, modulepath + + String encoding = getProjectEncoding(); + // What to do about bootclasspath on java 9? + + // ArrayList<Classpath> allPaths = handleBootclasspath(bootclasspaths, customEncoding); + ArrayList<FileSystem.Classpath> allPaths = new ArrayList<FileSystem.Classpath>(); + allPaths.addAll(processStringPath(bootclasspath, encoding)); + allPaths.addAll(processFilePath(inJars, encoding)); + allPaths.addAll(processFilePath(inPath, encoding)); + allPaths.addAll(processFilePath(aspectpath, encoding)); + if (modulepathClasspathEntries != null) { + allPaths.addAll(modulepathClasspathEntries); + } + if (modulesourcepathClasspathEntries != null) { + allPaths.addAll(modulesourcepathClasspathEntries); + } + // The classpath is done after modules to give precedence to modules that share the + // same paths as classpath elements (the upcoming normalize will remove later dups) + allPaths.addAll(processStringPath(classpath, encoding)); + for (Iterator<FileSystem.Classpath> iter = allPaths.iterator();iter.hasNext();) { + Classpath next = iter.next(); + if (next == null) { + iter.remove(); + } + } + allPaths = FileSystem.ClasspathNormalizer.normalize(allPaths); + this.checkedClasspaths = new FileSystem.Classpath[allPaths.size()]; + allPaths.toArray(this.checkedClasspaths); + for (int i=0;i<checkedClasspaths.length;i++) { + if (checkedClasspaths[i] == null) { + throw new IllegalStateException(); + } + } + } + } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java index 164af6629..85b665dcd 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java @@ -79,6 +79,7 @@ import org.aspectj.org.eclipse.jdt.internal.compiler.batch.ClasspathLocation; import org.aspectj.org.eclipse.jdt.internal.compiler.batch.CompilationUnit; import org.aspectj.org.eclipse.jdt.internal.compiler.batch.FileSystem; import org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit; +import org.aspectj.org.eclipse.jdt.internal.compiler.env.IModule; import org.aspectj.org.eclipse.jdt.internal.compiler.env.INameEnvironment; import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser; @@ -865,8 +866,7 @@ public class AjBuildManager implements IOutputClassFileNameProvider, IBinarySour bcelWorld.getLint().setFromProperties(buildConfig.getLintSpecFile()); } - for (Iterator i = buildConfig.getAspectpath().iterator(); i.hasNext();) { - File f = (File) i.next(); + for (File f: buildConfig.getAspectpath()) { if (!f.exists()) { IMessage message = new Message("invalid aspectpath entry: " + f.getName(), null, true); handler.handleMessage(message); @@ -943,7 +943,19 @@ public class AjBuildManager implements IOutputClassFileNameProvider, IBinarySour // a classpathDirectory object that will attempt to look for source when it can't find binary. // int[] classpathModes = new int[classpaths.length]; // for (int i =0 ;i<classpaths.length;i++) classpathModes[i]=ClasspathDirectory.BINARY; - return new FileSystem(classpaths, filenames, defaultEncoding, ClasspathLocation.BINARY); + + FileSystem nameEnvironment = null; + // TODO J9 The compiler likes to work in terms of checked classpath objects - these will be different + // depending on where the code came from (classpath, modulepath). If working with just the raw + // 'classpaths' object it isn't recording where the code came from. This will be an issue later for + // weaving, the distinction will need to be maintained for proper 'module aware/respecting' weaving. + if (buildConfig.getCheckedClasspaths() == null) { + nameEnvironment = new FileSystem(classpaths, filenames, defaultEncoding, ClasspathLocation.BINARY); + } else { + nameEnvironment = new FileSystem(buildConfig.getCheckedClasspaths(), filenames, false); + } + nameEnvironment.module = buildConfig.getModuleDesc(); + return nameEnvironment; } public IProblemFactory getProblemFactory() { @@ -962,9 +974,30 @@ public class AjBuildManager implements IOutputClassFileNameProvider, IBinarySour if ("".equals(defaultEncoding)) {//$NON-NLS-1$ defaultEncoding = null; } - + CompilationUnit moduleCU = null; + + // TODO building with multiple module-infos? + int moduleIndex = -1; + IModule moduleDesc = buildConfig.getModuleDesc(); + String moduleName = moduleDesc == null? null: new String(moduleDesc.name()); + for (int i=0;i<fileCount;i++) { + if (filenames[i].endsWith("module-info.java")) { + moduleIndex = i; + moduleCU = new CompilationUnit(null, filenames[i], defaultEncoding, null, false, moduleName); + } + } + for (int i = 0; i < fileCount; i++) { - units[i] = new CompilationUnit(null, filenames[i], defaultEncoding); +// units[i] = new CompilationUnit(null, filenames[i], defaultEncoding); + if (i == moduleIndex) { + units[i] = moduleCU; + } else { + units[i] = new CompilationUnit(null, filenames[i], defaultEncoding, null, false, moduleName); + units[i].setModule(moduleCU); + } +// new CompilationUnit(null, fileName, encoding, this.destinationPaths[i], +// shouldIgnoreOptionalProblems(this.ignoreOptionalProblemsFromFolders, fileName.toCharArray()), +// this.modNames[i]); } return units; } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/StatefulNameEnvironment.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/StatefulNameEnvironment.java index 71c3041e8..b3cb0e2d1 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/StatefulNameEnvironment.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/StatefulNameEnvironment.java @@ -26,18 +26,18 @@ import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryType; import org.aspectj.org.eclipse.jdt.internal.compiler.env.IModule; -import org.aspectj.org.eclipse.jdt.internal.compiler.env.INameEnvironment; +import org.aspectj.org.eclipse.jdt.internal.compiler.env.IModuleAwareNameEnvironment; import org.aspectj.org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; import org.aspectj.util.FileUtil; -public class StatefulNameEnvironment implements INameEnvironment { +public class StatefulNameEnvironment implements IModuleAwareNameEnvironment { private Map<String,File> classesFromName; private Map<String,NameEnvironmentAnswer> inflatedClassFilesCache; private Set<String> packageNames; private AjState state; - private INameEnvironment baseEnvironment; + private IModuleAwareNameEnvironment baseEnvironment; - public StatefulNameEnvironment(INameEnvironment baseEnvironment, Map<String,File> classesFromName, AjState state) { + public StatefulNameEnvironment(IModuleAwareNameEnvironment baseEnvironment, Map<String,File> classesFromName, AjState state) { this.classesFromName = classesFromName; this.inflatedClassFilesCache = new HashMap<String,NameEnvironmentAnswer>(); this.baseEnvironment = baseEnvironment; @@ -130,4 +130,34 @@ public class StatefulNameEnvironment implements INameEnvironment { this.classesFromName = classNameToFileMap; } + @Override + public NameEnvironmentAnswer findType(char[][] compoundName, char[] moduleName) { + return baseEnvironment.findType(compoundName, moduleName); + } + + @Override + public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName, char[] moduleName) { + return baseEnvironment.findType(typeName, packageName, moduleName); + } + + @Override + public char[][] getModulesDeclaringPackage(char[][] parentPackageName, char[] name, char[] moduleName) { + return baseEnvironment.getModulesDeclaringPackage(parentPackageName, name, moduleName); + } + + @Override + public boolean hasCompilationUnit(char[][] qualifiedPackageName, char[] moduleName, boolean checkCUs) { + return baseEnvironment.hasCompilationUnit(qualifiedPackageName, moduleName, checkCUs); + } + + @Override + public IModule getModule(char[] moduleName) { + return baseEnvironment.getModule(moduleName); + } + + @Override + public char[][] getAllAutomaticModules() { + return baseEnvironment.getAllAutomaticModules(); + } + } diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/core/builder/AjBuildManagerTest.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/core/builder/AjBuildManagerTest.java index 3799b4cda..c4be26936 100644 --- a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/core/builder/AjBuildManagerTest.java +++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/core/builder/AjBuildManagerTest.java @@ -57,10 +57,10 @@ public class AjBuildManagerTest extends TestCase { } public void testSimpleStructure() throws IOException /* , CoreException */{ - AjBuildManager manager = new AjBuildManager(messageWriter); BuildArgParser parser = new BuildArgParser(messageWriter); String javaClassPath = System.getProperty("java.class.path"); + System.out.println(javaClassPath); String sandboxName = Ajc.createEmptySandbox().getAbsolutePath(); AjBuildConfig buildConfig = parser.genBuildConfig(new String[] { "-d", sandboxName, "-classpath", javaClassPath, AjdtAjcTests.TESTDATA_PATH + "/src1/A.java", diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/core/builder/AjStateTest.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/core/builder/AjStateTest.java index 1693178e3..101fdade1 100644 --- a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/core/builder/AjStateTest.java +++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/core/builder/AjStateTest.java @@ -48,44 +48,48 @@ public class AjStateTest extends TestCase { } public void testAddEntryToAspectpath() { - newConfig.getAspectpath().add(new File("anotherEntry.jar")); + newConfig.addToAspectpath(new File("anotherEntry.jar")); +// newConfig.getAspectpath().add(new File("anotherEntry.jar")); assertFalse("Can do incremental", aRightState.prepareForNextBuild(newConfig)); } public void testRemoveEntryFromAspectpath() { - newConfig.getAspectpath().remove(0); + newConfig.removeAspectPathEntry(0); assertFalse("Can do incremental", aRightState.prepareForNextBuild(newConfig)); } public void testReorderAspectpath() { - String o = newConfig.getClasspath().remove(0); - newConfig.getAspectpath().add(new File(o)); + String o = newConfig.removeClasspathEntry(0); + newConfig.addToAspectpath(new File(o)); +// newConfig.getAspectpath().add(new File(o)); assertFalse("Can do incremental", aRightState.prepareForNextBuild(newConfig)); } public void testAddEntryToInpath() { - newConfig.getInpath().add(new File("anotherEntry")); + newConfig.addToInpath(new File("anotherEntry")); assertFalse("Can do incremental", aRightState.prepareForNextBuild(newConfig)); } public void testRemoveEntryFromInpath() { - newConfig.getInpath().remove(0); + newConfig.removeInpathEntry(0);//getInpath().remove(0); assertFalse("Can do incremental", aRightState.prepareForNextBuild(newConfig)); } public void testReorderInpath() { - String o = newConfig.getClasspath().remove(0); - newConfig.getInpath().add(new File(o)); + String o = newConfig.removeClasspathEntry(0);//getClasspath().remove(0); + newConfig.addToInpath(new File(o));//getInpath().add(new File(o)); assertFalse("Can do incremental", aRightState.prepareForNextBuild(newConfig)); } public void testAddEntryToInjars() { - newConfig.getInJars().add(new File("anotherEntry.jar")); + newConfig.addToInjars(new File("anotherEntry.jar")); +// newConfig.getInJars().add(new File("anotherEntry.jar")); assertFalse("Can do incremental", aRightState.prepareForNextBuild(newConfig)); } public void testRemoveEntryFromInjars() { - newConfig.getInJars().remove(0); + newConfig.removeInjarsEntry(0); +// newConfig.getInJars().remove(0); assertFalse("Can do incremental", aRightState.prepareForNextBuild(newConfig)); } diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/AjcTestCase.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/AjcTestCase.java index 12b1e3508..b665afeba 100644 --- a/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/AjcTestCase.java +++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/AjcTestCase.java @@ -581,7 +581,7 @@ public class AjcTestCase extends TestCase { } public RunResult run(String className, String[] args, String classpath) { - return run(className, args, "", null, false,false); + return run(className, null, args, "", "", null, false,false); } /** @@ -593,7 +593,7 @@ public class AjcTestCase extends TestCase { * be appended to the classpath, as will any jars in the sandbox. * @param runSpec */ - public RunResult run(String className, String[] args, String vmargs, final String classpath, boolean useLTW, boolean useFullLTW) { + public RunResult run(String className, String moduleName, String[] args, String vmargs, final String classpath, String modulepath, boolean useLTW, boolean useFullLTW) { if (args != null) { for (int i = 0; i < args.length; i++) { @@ -607,8 +607,16 @@ public class AjcTestCase extends TestCase { cp.append(substituteSandbox(classpath)); cp.append(File.pathSeparator); } - cp.append(ajc.getSandboxDirectory().getAbsolutePath()); - getAnyJars(ajc.getSandboxDirectory(), cp); + if (moduleName == null) { + // When running modules, we want more control so don't try to be helpful by adding all jars + cp.append(ajc.getSandboxDirectory().getAbsolutePath()); + getAnyJars(ajc.getSandboxDirectory(), cp); + } + StringBuffer mp = new StringBuffer(); + if (modulepath != null) { + mp.append(substituteSandbox(modulepath)); + mp.append(File.pathSeparator); + } URLClassLoader sandboxLoader; ClassLoader parentLoader = getClass().getClassLoader().getParent(); @@ -639,7 +647,6 @@ public class AjcTestCase extends TestCase { String absPath = directory.getAbsolutePath(); String javaagent= absPath+File.separator+".."+File.separator+"aj-build"+File.separator+"dist"+File.separator+"tools"+File.separator+"lib"+File.separator+"aspectjweaver.jar"; try { - String command ="java " +vmargs+ " -classpath " + cp +" -javaagent:"+javaagent + " " + className ; // Command is executed using ProcessBuilder to allow setting CWD for ajc sandbox compliance @@ -654,10 +661,35 @@ public class AjcTestCase extends TestCase { System.out.println("Error executing full LTW test: " + e); e.printStackTrace(); } - return lastRunResult; - - }else{ + } else if (moduleName != null) { + // CODE FOR RUNNING MODULES + if(vmargs == null){ + vmargs =""; + } + try { + if (mp.indexOf("$runtime") != -1) { + mp = mp.replace(mp.indexOf("$runtime"),"$runtime".length(),TestUtil.aspectjrtPath().toString()); + } + if (cp.indexOf("aspectjrt")==-1) { + cp.append(TestUtil.aspectjrtPath().getPath()).append(File.pathSeparator); + } + String command = LangUtil.getJavaExecutable().getAbsolutePath() + " " +vmargs+ (cp.length()==0?"":" -classpath " + cp) + " -p "+mp+" --module "+moduleName ; + System.out.println("Command is "+command); + // Command is executed using ProcessBuilder to allow setting CWD for ajc sandbox compliance + ProcessBuilder pb = new ProcessBuilder(tokenizeCommand(command)); + pb.directory( new File(ajc.getSandboxDirectory().getAbsolutePath())); + exec = pb.start(); + BufferedReader stdInput = new BufferedReader(new InputStreamReader(exec.getInputStream())); + BufferedReader stdError = new BufferedReader(new InputStreamReader(exec.getErrorStream())); + exec.waitFor(); + lastRunResult = createResultFromBufferReaders(command,stdInput, stdError); + } catch (Exception e) { + System.out.println("Error executing module test: " + e); + e.printStackTrace(); + } + return lastRunResult; + } else { cp.append(DEFAULT_CLASSPATH_ENTRIES); URL[] urls = getURLs(cp.toString()); sandboxLoader = new URLClassLoader(urls, parentLoader); @@ -666,7 +698,8 @@ public class AjcTestCase extends TestCase { ByteArrayOutputStream baosErr = new ByteArrayOutputStream(); - StringBuffer command = new StringBuffer("java -classpath "); + StringBuffer command = new StringBuffer(); + command.append("java -classpath "); command.append(cp.toString()); command.append(" "); command.append(className); @@ -834,15 +867,15 @@ public class AjcTestCase extends TestCase { return urls; } - private String substituteSandbox(String classpath) { - // the longhand form of the non 1.3 API: classpath.replace("$sandbox", ajc.getSandboxDirectory().getAbsolutePath()); - while (classpath.indexOf("$sandbox") != -1) { - int pos = classpath.indexOf("$sandbox"); - String firstbit = classpath.substring(0, pos); - String endbit = classpath.substring(pos + 8); - classpath = firstbit + ajc.getSandboxDirectory().getAbsolutePath() + endbit; + private String substituteSandbox(String path) { + // the longhand form of the non 1.3 API: path.replace("$sandbox", ajc.getSandboxDirectory().getAbsolutePath()); + while (path.indexOf("$sandbox") != -1) { + int pos = path.indexOf("$sandbox"); + String firstbit = path.substring(0, pos); + String endbit = path.substring(pos + 8); + path = firstbit + ajc.getSandboxDirectory().getAbsolutePath() + endbit; } - return classpath; + return path; } /** @@ -864,6 +897,8 @@ public class AjcTestCase extends TestCase { args[i + 1] = substituteSandbox(args[i + 1]); String next = args[i + 1]; hasruntime = ((null != next) && (-1 != next.indexOf("aspectjrt.jar"))); + } else if ("-p".equals(args[i]) || "--module-path".equals(args[i])) { + args[i + 1] = substituteSandbox(args[i + 1]); } } if (-1 == cpIndex) { diff --git a/util/src/org/aspectj/util/SoftHashMap.java b/util/src/org/aspectj/util/SoftHashMap.java index f7971bddb..94ae83441 100644 --- a/util/src/org/aspectj/util/SoftHashMap.java +++ b/util/src/org/aspectj/util/SoftHashMap.java @@ -12,7 +12,7 @@ import java.util.*; public class SoftHashMap<K,V> extends AbstractMap<K,V> { private Map<K, SpecialValue> map; - private ReferenceQueue<? super V> rq = new ReferenceQueue<>(); + private ReferenceQueue<? super V> rq = new ReferenceQueue(); public SoftHashMap() { this.map = new HashMap<K,SpecialValue>(); |