don't resolve all groovy references to see which additional files need recompilation, we can do this in groovyc now

This commit is contained in:
peter
2011-11-10 16:07:35 +01:00
parent 1c130b6978
commit 87349eeab9
3 changed files with 70 additions and 136 deletions

View File

@@ -896,6 +896,30 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
}
}
public static List<String> getCompiledClassNames(VirtualFile srcFile, Project project) {
SourceFileInfo info = loadSourceInfo(srcFile);
if (info == null) {
return Collections.emptyList();
}
final ArrayList<String> result = new ArrayList<String>();
info.processOutputPaths(getProjectId(project), new Proc() {
@Override
public boolean execute(int projectId, String outputPath) {
VirtualFile clsFile = LocalFileSystem.getInstance().findFileByPath(outputPath);
if (clsFile != null) {
OutputFileInfo outputInfo = loadOutputInfo(clsFile);
if (outputInfo != null) {
ContainerUtil.addIfNotNull(result, outputInfo.getClassName());
}
}
return true;
}
});
return result;
}
private interface FileProcessor {
void execute(VirtualFile file);

View File

@@ -17,19 +17,15 @@
package org.jetbrains.plugins.groovy.compiler;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkType;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ContentIterator;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
@@ -37,30 +33,20 @@ import com.intellij.openapi.roots.ui.configuration.ClasspathEditor;
import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.FactoryMap;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.incremental.groovy.GroovycOSProcessHandler;
import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.GroovyFileTypeLoader;
import org.jetbrains.plugins.groovy.GroovyIcons;
import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.util.GroovyUtils;
import org.jetbrains.plugins.groovy.util.LibrariesUtil;
import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author Dmitry.Krasilschikov
@@ -81,124 +67,10 @@ public class GroovyCompiler extends GroovyCompilerBase {
@Override
protected void compileFiles(final CompileContext context, final Module module, List<VirtualFile> toCompile, OutputSink sink, boolean tests) {
final Set<VirtualFile> allToCompile = new LinkedHashSet<VirtualFile>(toCompile);
// groovyc may fail if we don't also recompile files like B such that A depends on B and B depends on C, where A & C \in toCompile
// see http://jira.codehaus.org/browse/GROOVY-4024
if (!"false".equals(System.getProperty("compile.groovy.dependencies", "true"))) {
context.getProgressIndicator().checkCanceled();
context.getProgressIndicator().setText("Enumerating Groovy classes...");
Set<VirtualFile> groovyFiles = enumerateGroovyFiles(module);
if (toCompile.size() < groovyFiles.size()) {
context.getProgressIndicator().checkCanceled();
context.getProgressIndicator().setText("Processing Groovy dependencies...");
addIntermediateGroovyClasses(allToCompile, groovyFiles);
}
}
context.getProgressIndicator().checkCanceled();
context.getProgressIndicator().setText(GroovycOSProcessHandler.GROOVY_COMPILER_IN_OPERATION);
context.getProgressIndicator().setText("Starting Groovy compiler...");
runGroovycCompiler(context, module, new ArrayList<VirtualFile>(allToCompile), false, getMainOutput(context, module, tests), sink, tests);
}
private void addIntermediateGroovyClasses(Set<VirtualFile> allToCompile, final Set<VirtualFile> groovyFiles) {
final Set<VirtualFile> initialFiles = new THashSet<VirtualFile>(allToCompile);
final THashSet<VirtualFile> visited = new THashSet<VirtualFile>();
for (VirtualFile aClass : initialFiles) {
if (visited.add(aClass)) {
goForIntermediateFiles(aClass, allToCompile, new FactoryMap<VirtualFile, Set<VirtualFile>>() {
@Override
protected Set<VirtualFile> create(final VirtualFile key) {
AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock();
try {
return calcCodeReferenceDependencies(key, groovyFiles);
}
finally {
accessToken.finish();
}
}
}, visited);
}
}
}
private Set<VirtualFile> enumerateGroovyFiles(final Module module) {
final Set<VirtualFile> moduleClasses = new THashSet<VirtualFile>();
ModuleRootManager.getInstance(module).getFileIndex().iterateContent(new ContentIterator() {
public boolean processFile(final VirtualFile vfile) {
if (!vfile.isDirectory() &&
GroovyFileType.GROOVY_FILE_TYPE.equals(vfile.getFileType())) {
AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock();
try {
if (PsiManager.getInstance(myProject).findFile(vfile) instanceof GroovyFile) {
moduleClasses.add(vfile);
}
}
finally {
accessToken.finish();
}
}
return true;
}
});
return moduleClasses;
}
private static void goForIntermediateFiles(VirtualFile from, Set<VirtualFile> dirty, FactoryMap<VirtualFile, Set<VirtualFile>> deps, Set<VirtualFile> visited) {
final Set<VirtualFile> set = deps.get(from);
for (VirtualFile psiClass : set) {
if (visited.add(psiClass)) {
goForIntermediateFiles(psiClass, dirty, deps, visited);
}
if (dirty.contains(psiClass)) {
dirty.add(from);
}
}
}
private Set<VirtualFile> calcCodeReferenceDependencies(VirtualFile vfile, final Set<VirtualFile> moduleFiles) {
final PsiFile psi = PsiManager.getInstance(myProject).findFile(vfile);
if (!(psi instanceof GroovyFile)) return Collections.emptySet();
final Set<VirtualFile> deps = new THashSet<VirtualFile>();
psi.acceptChildren(new PsiElementVisitor() {
@Override
public void visitElement(PsiElement element) {
if (element instanceof GrReferenceElement &&
(!(element instanceof GrReferenceExpression) || !((GrReferenceExpression)element).isQualified())) {
GrReferenceElement referenceElement = (GrReferenceElement)element;
try {
final PsiElement target = referenceElement.resolve();
if (target instanceof GrTypeDefinition || target instanceof GroovyScriptClass) {
final VirtualFile targetFile = target.getContainingFile().getViewProvider().getVirtualFile();
if (moduleFiles.contains(targetFile)) {
deps.add(targetFile);
}
}
}
catch (ProcessCanceledException ignored) {
}
catch (Exception e) {
LOG.error(e);
//prevent our PSI errors from failing the entire compilation
}
catch (AssertionError e) {
LOG.error(e);
//prevent our PSI errors from failing the entire compilation
}
}
element.acceptChildren(this);
}
});
return deps;
runGroovycCompiler(context, module, toCompile, false, getMainOutput(context, module, tests), sink, tests);
}
public boolean validateConfiguration(CompileScope compileScope) {

View File

@@ -19,6 +19,7 @@ package org.jetbrains.plugins.groovy.compiler;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.impl.CompilerUtil;
import com.intellij.compiler.impl.FileSetCompileScope;
import com.intellij.compiler.impl.TranslatingCompilerFilesMonitor;
import com.intellij.compiler.impl.javaCompiler.ModuleChunk;
import com.intellij.compiler.impl.javaCompiler.OutputItemImpl;
import com.intellij.compiler.make.CacheCorruptedException;
@@ -46,6 +47,7 @@ import com.intellij.openapi.projectRoots.JavaSdkType;
import com.intellij.openapi.projectRoots.JdkUtil;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkType;
import com.intellij.openapi.roots.ContentIterator;
import com.intellij.openapi.roots.ModuleFileIndex;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderRootType;
@@ -62,6 +64,7 @@ import com.intellij.psi.PsiManager;
import com.intellij.util.*;
import com.intellij.util.cls.ClsFormatException;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.groovy.compiler.rt.GroovycRunner;
import org.jetbrains.jps.incremental.groovy.GroovycOSProcessHandler;
@@ -167,14 +170,25 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler {
LOG.assertTrue(finalOutputDir != null, "No output directory for module " + module.getName() + (tests ? " tests" : " production"));
final Charset ideCharset = EncodingProjectManager.getInstance(myProject).getDefaultCharset();
String encoding = !Comparing.equal(CharsetToolkit.getDefaultSystemCharset(), ideCharset) ? ideCharset.name() : null;
List<String> paths2Compile = ContainerUtil.map2List(toCompile, new Function<VirtualFile, String>() {
Set<String> paths2Compile = ContainerUtil.map2Set(toCompile, new Function<VirtualFile, String>() {
@Override
public String fun(VirtualFile file) {
return file.getPath();
}
});
GroovycOSProcessHandler.fillFileWithGroovycParameters(fileWithParameters, outputDir.getPath(), paths2Compile, finalOutputDir.getPath(),
Collections.<String, String>emptyMap(), encoding, patchers);
Map<String, String> class2Src = new HashMap<String, String>();
for (VirtualFile file : enumerateGroovyFiles(module)) {
if (!paths2Compile.contains(file.getPath())) {
for (String name : TranslatingCompilerFilesMonitor.getCompiledClassNames(file, myProject)) {
class2Src.put(name.replace('$', '.'), file.getPath());
}
}
}
GroovycOSProcessHandler
.fillFileWithGroovycParameters(fileWithParameters, outputDir.getPath(), paths2Compile, finalOutputDir.getPath(),
class2Src, encoding, patchers);
parameters.getProgramParametersList().add(forStubs ? "stubs" : "groovyc");
parameters.getProgramParametersList().add(fileWithParameters.getPath());
@@ -283,6 +297,30 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler {
}
}
protected Set<VirtualFile> enumerateGroovyFiles(final Module module) {
final Set<VirtualFile> moduleClasses = new THashSet<VirtualFile>();
ModuleRootManager.getInstance(module).getFileIndex().iterateContent(new ContentIterator() {
public boolean processFile(final VirtualFile vfile) {
if (!vfile.isDirectory() &&
GroovyFileType.GROOVY_FILE_TYPE.equals(vfile.getFileType())) {
AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock();
try {
if (PsiManager.getInstance(myProject).findFile(vfile) instanceof GroovyFile) {
moduleClasses.add(vfile);
}
}
finally {
accessToken.finish();
}
}
return true;
}
});
return moduleClasses;
}
protected static void addStubsToCompileScope(List<String> outputPaths, CompileContext compileContext, Module module) {
List<VirtualFile> stubFiles = new ArrayList<VirtualFile>();
for (String outputPath : outputPaths) {