From 85e6003f8224578e9c06111616a2d543dbf34f69 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 10 Oct 2012 19:15:26 +0200 Subject: [PATCH] navigation from externally-made groovy stubs to the source code --- .../compiler/impl/CompileContextImpl.java | 29 +++++++++++---- .../jps/incremental/IncProjectBuilder.java | 10 +---- .../jps/incremental/groovy/GroovyBuilder.java | 25 ++++++++----- .../generator/GroovycStubGenerator.java | 8 ++-- .../groovy/compiler/GroovyCompilerTest.groovy | 37 +++++++++++-------- .../compiler/GroovyCompilerTestCase.java | 22 +++++------ 6 files changed, 74 insertions(+), 57 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileContextImpl.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileContextImpl.java index fa9232f984ae..a06185b67d71 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileContextImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileContextImpl.java @@ -43,6 +43,7 @@ import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.pom.Navigatable; @@ -225,22 +226,21 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon } @Nullable - private VirtualFile findPresentableFileForMessage(final String url) { - if (url == null) { + private VirtualFile findPresentableFileForMessage(@Nullable final String url) { + final VirtualFile file = findFileByUrl(url); + if (file == null) { return null; } - final VirtualFileManager fileManager = VirtualFileManager.getInstance(); return ApplicationManager.getApplication().runReadAction(new Computable() { @Override public VirtualFile compute() { - final VirtualFile file = fileManager.findFileByUrl(url); - if (file != null) { + if (file.isValid()) { for (final Map.Entry> entry : myOutputRootToSourceGeneratorMap.entrySet()) { final VirtualFile root = entry.getKey(); - if (VfsUtil.isAncestor(root, file, false)) { + if (VfsUtilCore.isAncestor(root, file, false)) { final Pair pair = entry.getValue(); final VirtualFile presentableFile = pair.getFirst().getPresentableFile(CompileContextImpl.this, pair.getSecond(), root, file); - return presentableFile != null? presentableFile : file; + return presentableFile != null ? presentableFile : file; } } } @@ -248,7 +248,20 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon } }); } - + + @Nullable + private static VirtualFile findFileByUrl(@Nullable String url) { + if (url == null) { + return null; + } + VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(url); + if (file == null) { + // groovy stubs may be placed in completely random directories which aren't refreshed automatically + return VirtualFileManager.getInstance().refreshAndFindFileByUrl(url); + } + return file; + } + public void addMessage(CompilerMessage msg) { Collection messages = myMessages.get(msg.getCategory()); if (messages == null) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index adb6a8b674d8..4543ec49b29b 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -603,14 +603,8 @@ public class IncProjectBuilder { throw new ProjectBuildException(e); } finally { - final Collection tempRoots = context.getProjectDescriptor().getBuildRootIndex().clearTempRoots(context); - if (!tempRoots.isEmpty()) { - final Set rootFiles = new HashSet(); - for (BuildRootDescriptor rd : tempRoots) { - rootFiles.add(rd.getRootFile()); - context.getProjectDescriptor().fsState.clearRecompile(rd); - } - myAsyncTasks.add(FileUtil.asyncDelete(rootFiles)); + for (BuildRootDescriptor rd : context.getProjectDescriptor().getBuildRootIndex().clearTempRoots(context)) { + context.getProjectDescriptor().fsState.clearRecompile(rd); } try { diff --git a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java index 6eb82bcd3908..3c75cda92260 100644 --- a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java +++ b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java @@ -78,7 +78,7 @@ public class GroovyBuilder extends ModuleLevelBuilder { if (finalOutputs == null) { return ExitCode.ABORT; } - Map generationOutputs = getGenerationOutputs(chunk, finalOutputs); + Map generationOutputs = myForStubs ? getStubGenerationOutputs(chunk, context) : finalOutputs; final Set toCompilePaths = new LinkedHashSet(); for (File file : toCompile) { @@ -176,11 +176,18 @@ public class GroovyBuilder extends ModuleLevelBuilder { STUB_TO_SRC.set(context, null); } - private Map getGenerationOutputs(ModuleChunk chunk, Map finalOutputs) throws IOException { + private static Map getStubGenerationOutputs(ModuleChunk chunk, CompileContext context) throws IOException { Map generationOutputs = new HashMap(); + File commonRoot = new File(context.getProjectDescriptor().dataManager.getDataPaths().getDataStorageRoot(), "groovyStubs"); for (ModuleBuildTarget target : chunk.getTargets()) { - generationOutputs.put(target, myForStubs ? FileUtil.createTempDirectory("groovyStubs", "__" + target.getModuleName()).getPath() - : finalOutputs.get(target)); + File targetRoot = new File(commonRoot, target.getModuleName() + File.separator + target.getTargetType().getTypeId()); + if (!FileUtil.delete(targetRoot)) { + throw new IOException("External make cannot clean " + targetRoot.getPath()); + } + if (!targetRoot.mkdirs()) { + throw new IOException("External make cannot create " + targetRoot.getPath()); + } + generationOutputs.put(target, targetRoot.getPath()); } return generationOutputs; } @@ -254,11 +261,11 @@ public class GroovyBuilder extends ModuleLevelBuilder { return toCompile; } - private boolean updateDependencies(CompileContext context, - ModuleChunk chunk, - List toCompile, - Map generationOutputs, - List successfullyCompiled) throws IOException { + private static boolean updateDependencies(CompileContext context, + ModuleChunk chunk, + List toCompile, + Map generationOutputs, + List successfullyCompiled) throws IOException { final Mappings delta = context.getProjectDescriptor().dataManager.getMappings().createDelta(); final List successfullyCompiledFiles = new ArrayList(); if (!successfullyCompiled.isEmpty()) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovycStubGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovycStubGenerator.java index 2ca34e4780c2..51a13ab39751 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovycStubGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovycStubGenerator.java @@ -164,20 +164,20 @@ public class GroovycStubGenerator extends GroovyCompilerBase { private static File getStubOutput(Module module, boolean tests) { final Project project = module.getProject(); final String rootPath = CompilerPaths.getGeneratedDataDirectory(project).getPath() + "/" + GROOVY_STUBS + "/"; - return new File(rootPath + project.getLocationHash() + "/" + module.getName() + "/" + (tests ? "tests" : "production") + "/"); + return new File(rootPath + module.getName() + "/" + (tests ? "tests" : "production") + "/"); } @Nullable public static PsiClass findClassByStub(Project project, VirtualFile stubFile) { final String[] components = StringUtil.trimEnd(stubFile.getPath(), ".java").split("[\\\\/]"); final int stubs = Arrays.asList(components).indexOf(GROOVY_STUBS); - if (stubs < 0 || stubs >= components.length - 4) return null; + if (stubs < 0 || stubs >= components.length - 3) return null; - final String moduleName = components[stubs + 2]; + final String moduleName = components[stubs + 1]; final Module module = ModuleManager.getInstance(project).findModuleByName(moduleName); if (module == null) return null; - final String fqn = StringUtil.join(Arrays.asList(components).subList(stubs + 4, components.length), "."); + final String fqn = StringUtil.join(Arrays.asList(components).subList(stubs + 3, components.length), "."); return JavaPsiFacade.getInstance(project).findClass(fqn, GlobalSearchScope.moduleScope(module)); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy index 0ae751960b70..52c59b05028c 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy @@ -14,14 +14,14 @@ * limitations under the License. */ -package org.jetbrains.plugins.groovy.compiler; - - - +package org.jetbrains.plugins.groovy.compiler import com.intellij.compiler.CompilerConfiguration import com.intellij.compiler.CompilerConfigurationImpl import com.intellij.compiler.server.BuildManager +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.PathManager +import com.intellij.openapi.compiler.CompilerMessage +import com.intellij.openapi.compiler.CompilerMessageCategory import com.intellij.openapi.compiler.options.ExcludeEntryDescription import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration import com.intellij.openapi.module.Module @@ -30,8 +30,8 @@ import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiFile import com.intellij.testFramework.TestLoggerFactory -import junit.framework.AssertionFailedError - +import org.jetbrains.plugins.groovy.compiler.generator.GroovycStubGenerator +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile /** * @author peter */ @@ -82,15 +82,8 @@ public abstract class GroovyCompilerTest extends GroovyCompilerTestCase { } private void shouldFail(Closure action) { - try { - action() - fail("Make should fail"); - } - catch (RuntimeException e) { - if (!(e.getCause() instanceof AssertionFailedError)) { - throw e; - } - } + List messages = action() + assert messages.find { it.category == CompilerMessageCategory.ERROR } } public void testRenameToJava() throws Throwable { @@ -720,6 +713,20 @@ public class Main { assert findClassFile("Client") } + public void "test navigate from stub to source"() { + GroovyFile groovyFile = (GroovyFile) myFixture.addFileToProject("a.groovy", "class Groovy3 { InvalidType type }") + myFixture.addClass("class Java4 extends Groovy3 {}").containingFile + + def msg = make().find { it.message.contains('InvalidType') } + assert msg?.virtualFile + ApplicationManager.application.runWriteAction { msg.virtualFile.delete(this) } + + def error = make().find { it.message.contains('InvalidType') } + assert error?.virtualFile + assert groovyFile.classes[0] == GroovycStubGenerator.findClassByStub(project, error.virtualFile) + + } + public void "test ignore groovy internal non-existent interface helper inner class"() { myFixture.addFileToProject 'Foo.groovy', ''' interface Foo {} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java index 81ce946a69e8..9eb1cce65848 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java @@ -242,7 +242,7 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC }.execute(); } - protected List make() { + protected List make() { return runCompiler(new Consumer() { @Override public void consume(ErrorReportingCallback callback) { @@ -251,7 +251,7 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC }); } - protected List rebuild() { + protected List rebuild() { return runCompiler(new Consumer() { @Override public void consume(ErrorReportingCallback callback) { @@ -260,7 +260,7 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC }); } - protected List compileModule(final Module module) { + protected List compileModule(final Module module) { return runCompiler(new Consumer() { @Override public void consume(ErrorReportingCallback callback) { @@ -269,7 +269,7 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC }); } - protected List compileFiles(final VirtualFile... files) { + protected List compileFiles(final VirtualFile... files) { return runCompiler(new Consumer() { @Override public void consume(ErrorReportingCallback callback) { @@ -278,7 +278,7 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC }); } - private List runCompiler(final Consumer runnable) { + private List runCompiler(final Consumer runnable) { final Semaphore semaphore = new Semaphore(); semaphore.down(); final ErrorReportingCallback callback = new ErrorReportingCallback(semaphore); @@ -389,7 +389,7 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC private static class ErrorReportingCallback implements CompileStatusNotification { private final Semaphore mySemaphore; private Throwable myError; - private final List myMessages = new ArrayList(); + private final List myMessages = new ArrayList(); public ErrorReportingCallback(Semaphore semaphore) { mySemaphore = semaphore; @@ -400,15 +400,11 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC try { for (CompilerMessageCategory category : CompilerMessageCategory.values()) { for (CompilerMessage message : compileContext.getMessages(category)) { - final String msg = message.getMessage(); - if (category != CompilerMessageCategory.INFORMATION || !msg.startsWith("Compilation completed successfully")) { - myMessages.add(category + ": " + msg); + if (category != CompilerMessageCategory.INFORMATION || !message.getMessage().startsWith("Compilation completed successfully")) { + myMessages.add(message); } } } - if (errors > 0) { - fail("Compiler errors occurred! " + StringUtil.join(myMessages, "\n")); - } assertFalse("Code did not compile!", aborted); } catch (Throwable t) { @@ -425,7 +421,7 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC } } - public List getMessages() { + public List getMessages() { return myMessages; } }