don't load AST transformations from the same module and (temporarily) on stub generation (IDEADEV-41244)

This commit is contained in:
peter
2009-11-08 21:07:14 +00:00
parent 4efe7cbe00
commit 98201a2644
5 changed files with 161 additions and 42 deletions
@@ -24,6 +24,7 @@ import org.codehaus.groovy.tools.javac.JavaAwareResolveVisitor;
import org.codehaus.groovy.tools.javac.JavaStubGenerator;
import java.io.*;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
@@ -39,6 +40,7 @@ public class GroovycRunner {
public static final String PATCHERS = "patchers";
public static final String ENCODING = "encoding";
public static final String OUTPUTPATH = "outputpath";
public static final String FINAL_OUTPUTPATH = "final_outputpath";
public static final String END = "end";
public static final String SRC_FILE = "src_file";
@@ -112,11 +114,12 @@ public class GroovycRunner {
final List srcFiles = new ArrayList();
final Map class2File = new HashMap();
fillFromArgsFile(argsFile, compilerConfiguration, patchers, compilerMessages, srcFiles, class2File);
final String[] finalOutput = new String[1];
fillFromArgsFile(argsFile, compilerConfiguration, patchers, compilerMessages, srcFiles, class2File, finalOutput);
if (srcFiles.isEmpty()) return;
System.out.println(PRESENTABLE_MESSAGE + "Groovy compiler: loading sources...");
final CompilationUnit unit = createCompilationUnit(forStubs, compilerConfiguration);
final CompilationUnit unit = createCompilationUnit(forStubs, compilerConfiguration, finalOutput[0]);
addSources(forStubs, srcFiles, unit);
runPatchers(patchers, compilerMessages, class2File, unit);
@@ -165,7 +168,7 @@ public class GroovycRunner {
}
private static String fillFromArgsFile(File argsFile, CompilerConfiguration compilerConfiguration, List patchers, List compilerMessages,
List srcFiles, Map class2File) {
List srcFiles, Map class2File, String[] finalOutput) {
String moduleClasspath = null;
BufferedReader reader = null;
@@ -207,14 +210,15 @@ public class GroovycRunner {
}
}
}
if (line.startsWith(ENCODING)) {
else if (line.startsWith(ENCODING)) {
compilerConfiguration.setSourceEncoding(reader.readLine());
}
if (line.startsWith(OUTPUTPATH)) {
else if (line.startsWith(OUTPUTPATH)) {
compilerConfiguration.setTargetDirectory(reader.readLine());
}
else if (line.startsWith(FINAL_OUTPUTPATH)) {
finalOutput[0] = reader.readLine();
}
line = reader.readLine();
}
@@ -324,11 +328,40 @@ public class GroovycRunner {
compilerMessages.add(new CompilerMessage(CompilerMessage.WARNING, message + ":\n" + writer, "<exception>", -1, -1));
}
private static CompilationUnit createCompilationUnit(final boolean forStubs, final CompilerConfiguration config) {
private static CompilationUnit createCompilationUnit(final boolean forStubs, final CompilerConfiguration config, String finalOutput) {
config.setClasspathList(Collections.EMPTY_LIST);
final GroovyClassLoader classLoader = buildClassLoaderFor(config);
final CompilationUnit unit = new CompilationUnit(config, null, classLoader) {
final String localGlobalTransforms = new File(finalOutput + File.separator +
"META-INF" + File.separator +
"services" + File.separator +
"org.codehaus.groovy.transform.ASTTransformation")
.getAbsolutePath();
final GroovyClassLoader transformLoader = new GroovyClassLoader(classLoader) {
public Enumeration getResources(String name) throws IOException {
if (name.endsWith("org.codehaus.groovy.transform.ASTTransformation")) {
if (forStubs) {
//commenting the next line (it shouldn't be there) will result in GroovyCompilerTest failure
//meaning that stub generation for some module (A) may require already compiled classes from another module (B)
//where A depends on B, of course
return Collections.enumeration(Collections.EMPTY_LIST);
}
final Enumeration resources = super.getResources(name);
final ArrayList list = Collections.list(resources);
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
if (localGlobalTransforms.equals(((URL)iterator.next()).getFile())) {
iterator.remove();
}
}
return Collections.enumeration(list);
}
return super.getResources(name);
}
};
final CompilationUnit unit = new CompilationUnit(config, null, classLoader, transformLoader) {
public void gotoPhase(int phase) throws CompilationFailedException {
super.gotoPhase(phase);
@@ -57,9 +57,8 @@ public class GroovyCompiler extends GroovyCompilerBase {
}
@Override
protected void compileFiles(CompileContext compileContext, Module module, List<VirtualFile> toCompile, VirtualFile outputDir, OutputSink sink,
boolean tests) {
runGroovycCompiler(compileContext, module, toCompile, false, outputDir, sink, tests);
protected void compileFiles(CompileContext compileContext, Module module, List<VirtualFile> toCompile, OutputSink sink, boolean tests) {
runGroovycCompiler(compileContext, module, toCompile, false, getMainOutput(compileContext, module, tests), sink, tests);
}
public boolean validateConfiguration(CompileScope compileScope) {
@@ -57,7 +57,6 @@ import com.intellij.util.PathUtil;
import com.intellij.util.PathsList;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.groovy.compiler.rt.CompilerMessage;
import org.jetbrains.groovy.compiler.rt.GroovycRunner;
import org.jetbrains.plugins.groovy.GroovyFileType;
@@ -67,7 +66,6 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import java.io.*;
import java.nio.charset.Charset;
import java.util.*;
import java.util.regex.Pattern;
/**
* @author peter
@@ -75,8 +73,6 @@ import java.util.regex.Pattern;
public abstract class GroovyCompilerBase implements TranslatingCompiler {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.compiler.GroovyCompilerBase");
protected final Project myProject;
@NonNls private static final String GROOVYC_RUNNER_REQUIRED = ".*(groovy|asm|antlr|junit|jline|ant|commons).*\\.jar";
private static final Pattern NONTRADITIONAL_GROOVYC_RUNNER_REQUIRED = Pattern.compile(".*(groovy|junit|jline|ant).*\\.jar");
public GroovyCompilerBase(Project project) {
myProject = project;
@@ -142,7 +138,7 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler {
try {
File fileWithParameters = File.createTempFile("toCompile", "");
fillFileWithGroovycParameters(toCompile, fileWithParameters, outputDir, patchers);
fillFileWithGroovycParameters(toCompile, fileWithParameters, outputDir, patchers, getMainOutput(compileContext, module, tests));
commandLine.addParameter(forStubs ? "stubs" : "groovyc");
commandLine.addParameter(fileWithParameters.getPath());
@@ -211,6 +207,10 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler {
}
}
protected static VirtualFile getMainOutput(CompileContext compileContext, Module module, boolean tests) {
return tests ? compileContext.getModuleOutputDirectoryForTests(module) : compileContext.getModuleOutputDirectory(module);
}
private static CompilerMessageCategory getMessageCategory(CompilerMessage compilerMessage) {
String category;
category = compilerMessage.getCategory();
@@ -223,7 +223,7 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler {
return CompilerMessageCategory.ERROR;
}
private void fillFileWithGroovycParameters(List<VirtualFile> virtualFiles, File f, VirtualFile outputDir, final List<String> patchers) {
private void fillFileWithGroovycParameters(List<VirtualFile> virtualFiles, File f, VirtualFile outputDir, final List<String> patchers, VirtualFile finalOutputDir) {
if (LOG.isDebugEnabled()) {
LOG.debug("Running groovyc on: " + virtualFiles.toString());
}
@@ -269,9 +269,13 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler {
printer.println(ideCharset.name());
}
//production output
printer.println(GroovycRunner.OUTPUTPATH);
printer.println(PathUtil.getLocalPath(outputDir));
printer.println(GroovycRunner.FINAL_OUTPUTPATH);
printer.println(PathUtil.getLocalPath(finalOutputDir));
printer.close();
}
@@ -314,10 +318,10 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler {
}
if (!toCompile.isEmpty()) {
compileFiles(compileContext, module, toCompile, compileContext.getModuleOutputDirectory(module), sink, false);
compileFiles(compileContext, module, toCompile, sink, false);
}
if (!toCompileTests.isEmpty()) {
compileFiles(compileContext, module, toCompileTests, compileContext.getModuleOutputDirectoryForTests(module), sink, true);
compileFiles(compileContext, module, toCompileTests, sink, true);
}
}
@@ -325,9 +329,7 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler {
}
protected abstract void compileFiles(CompileContext compileContext, Module module,
List<VirtualFile> toCompile,
VirtualFile outputDir,
OutputSink sink, boolean tests);
List<VirtualFile> toCompile, OutputSink sink, boolean tests);
public boolean isCompilableFile(VirtualFile file, CompileContext context) {
final boolean result = GroovyFileType.GROOVY_FILE_TYPE.equals(file.getFileType());
@@ -80,7 +80,7 @@ public class GroovycStubGenerator extends GroovyCompilerBase {
@Override
protected void compileFiles(CompileContext compileContext, Module module,
final List<VirtualFile> toCompile, VirtualFile outputDir, OutputSink sink, boolean tests) {
final List<VirtualFile> toCompile, OutputSink sink, boolean tests) {
boolean hasGroovy = false;
boolean hasJava = false;
for (final VirtualFile file : toCompile) {
@@ -16,6 +16,7 @@
package org.jetbrains.plugins.groovy.lang;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerManagerImpl;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
@@ -38,17 +39,18 @@ import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.compiler.*;
import com.intellij.openapi.roots.CompilerModuleExtension;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.module.ModifiableModuleModel;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.StdModuleTypes;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
import com.intellij.testFramework.fixtures.TempDirTestFixture;
import com.intellij.testFramework.fixtures.impl.TempDirTestFixtureImpl;
@@ -77,6 +79,17 @@ public class GroovyCompilerTest extends JavaCodeInsightFixtureTestCase {
super.setUp();
getProject().getComponent(GroovyCompilerLoader.class).projectOpened();
CompilerManagerImpl.testSetup();
CompilerProjectExtension.getInstance(getProject()).setCompilerOutputUrl(myMainOutput.findOrCreateDir("out").getUrl());
addGroovyLibrary(myModule);
}
private static void addGroovyLibrary(final Module to) {
final String root = PathManager.getHomePath() + "/community/lib/";
final File[] groovyJars = GroovyUtils.getFilesInDirectoryByPattern(root, GroovyConfigUtils.GROOVY_ALL_JAR_PATTERN);
assert groovyJars.length == 1;
PsiTestUtil.addLibrary(to, "groovy", root, groovyJars[0].getName());
}
@Override
@@ -86,17 +99,6 @@ public class GroovyCompilerTest extends JavaCodeInsightFixtureTestCase {
super.tearDown();
}
@Override
protected void tuneFixture(JavaModuleFixtureBuilder moduleBuilder) throws Exception {
super.tuneFixture(moduleBuilder);
moduleBuilder.setOutputPath(myMainOutput.getTempDirPath() + "/out/production");
moduleBuilder.setTestOutputPath(myMainOutput.getTempDirPath() + "/out/tests");
final File[] groovyJars = GroovyUtils.getFilesInDirectoryByPattern(PathManager.getHomePath() + "/community/lib", GroovyConfigUtils.GROOVY_ALL_JAR_PATTERN);
assert groovyJars.length == 1;
moduleBuilder.addLibrary("Groovy", groovyJars[0].getPath());
//moduleBuilder.addJdk(CompilerConfigurationImpl.getTestsExternalCompilerHome());
}
public void testPlainGroovy() throws Throwable {
myFixture.addFileToProject("A.groovy", "println '239'");
assertEmpty(make());
@@ -298,6 +300,85 @@ public class GroovyCompilerTest extends JavaCodeInsightFixtureTestCase {
assertEmpty(make());
}
public void testDontApplyTransformsFromSameModule() throws Exception {
addTransform();
myFixture.addClass("public class JavaClassToGenerateStubs {}");
assertEmpty(make());
}
private void addTransform() throws IOException {
myFixture.addFileToProject("Transf.groovy",
"import org.codehaus.groovy.ast.*\n" +
"import org.codehaus.groovy.control.*\n" +
"import org.codehaus.groovy.transform.*\n" +
"@GroovyASTTransformation(phase = CompilePhase.CONVERSION)\n" +
"public class Transf implements ASTTransformation {\n" +
" void visit(ASTNode[] nodes, SourceUnit sourceUnit) {\n" +
" ModuleNode module = nodes[0]\n" +
" for (clazz in module.classes) {\n" +
" if (clazz.name.contains('Bar')) " +
" module.addStaticImportClass('Foo', ClassHelper.makeWithoutCaching(Foo.class));\n" +
" }\n" +
" }\n" +
"}");
myFixture.addFileToProject("Foo.groovy", "class Foo {\n" +
"static def autoImported() { 239 }\n" +
"}");
CompilerConfiguration.getInstance(getProject()).addResourceFilePattern("*.ASTTransformation");
myFixture.addFileToProject("META-INF/services/org.codehaus.groovy.transform.ASTTransformation", "Transf");
}
public void testApplyTransformsFromDependencies() throws Exception {
addTransform();
myFixture.addFileToProject("dependent/Bar.groovy", "class Bar {\n" +
" static Object zzz = autoImported()\n" +
" static void main(String[] args) {\n" +
" println zzz\n" +
" }\n" +
"}");
myFixture.addFileToProject("dependent/AJavaClass.java", "class AJavaClass {}");
Module dep = addDependentModule();
addGroovyLibrary(dep);
assertEmpty(make());
assertOutput("Bar", "239", dep);
}
private Module addDependentModule() {
Module dep = new WriteCommandAction<Module>(getProject()) {
@Override
protected void run(Result<Module> result) throws Throwable {
final ModifiableModuleModel moduleModel = ModuleManager.getInstance(getProject()).getModifiableModel();
moduleModel.newModule("dependent/dependent.iml", StdModuleTypes.JAVA);
moduleModel.commit();
final Module dep = ModuleManager.getInstance(getProject()).findModuleByName("dependent");
final ModifiableRootModel model = ModuleRootManager.getInstance(dep).getModifiableModel();
model.addModuleOrderEntry(myModule);
final VirtualFile depRoot = myFixture.getTempDirFixture().getFile("dependent");
final ContentEntry entry = model.addContentEntry(depRoot);
entry.addSourceFolder(depRoot, false);
model.setSdk(ModuleRootManager.getInstance(myModule).getSdk());
//model.getModuleExtension(CompilerModuleExtension.class).inheritCompilerOutputPath(true);
model.commit();
result.setResult(dep);
}
}.execute().getResultObject();
return dep;
}
private void deleteClassFile(final String className) throws IOException {
new WriteCommandAction(getProject()) {
protected void run(Result result) throws Throwable {
@@ -349,9 +430,13 @@ public class GroovyCompilerTest extends JavaCodeInsightFixtureTestCase {
*/
private void assertOutput(String className, String output) throws ExecutionException {
assertOutput(className, output, myModule);
}
private void assertOutput(String className, String output, final Module module) throws ExecutionException {
final ApplicationConfiguration configuration =
new ApplicationConfiguration("app", getProject(), ApplicationConfigurationType.getInstance());
configuration.setModule(myModule);
configuration.setModule(module);
configuration.setMainClassName(className);
final DefaultRunExecutor extension = Executor.EXECUTOR_EXTENSION_NAME.findExtension(DefaultRunExecutor.class);
final ExecutionEnvironment environment = new ExecutionEnvironment(configuration, new RunnerSettings<JDOMExternalizable>(null, null),null, DataManager.getInstance().getDataContext());