read action
[fedora-idea.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / compiler / GroovyCompiler.java
blob8a669b0ff836ed1a414cff76b1f7a5a1977e6b83
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.jetbrains.plugins.groovy.compiler;
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.compiler.CompileContext;
21 import com.intellij.openapi.compiler.CompileScope;
22 import com.intellij.openapi.diagnostic.Logger;
23 import com.intellij.openapi.module.JavaModuleType;
24 import com.intellij.openapi.module.Module;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.projectRoots.JavaSdkType;
27 import com.intellij.openapi.projectRoots.Sdk;
28 import com.intellij.openapi.roots.ContentIterator;
29 import com.intellij.openapi.roots.ModuleRootManager;
30 import com.intellij.openapi.roots.ProjectRootManager;
31 import com.intellij.openapi.roots.ui.configuration.ClasspathEditor;
32 import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator;
33 import com.intellij.openapi.ui.Messages;
34 import com.intellij.openapi.util.Computable;
35 import com.intellij.openapi.vfs.VirtualFile;
36 import com.intellij.psi.*;
37 import com.intellij.util.containers.FactoryMap;
38 import gnu.trove.THashSet;
39 import org.jetbrains.annotations.NotNull;
40 import org.jetbrains.plugins.groovy.GroovyBundle;
41 import org.jetbrains.plugins.groovy.GroovyFileType;
42 import org.jetbrains.plugins.groovy.GroovyFileTypeLoader;
43 import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
44 import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
45 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
46 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
47 import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
48 import org.jetbrains.plugins.groovy.util.LibrariesUtil;
50 import java.util.*;
52 /**
53 * @author Dmitry.Krasilschikov
56 public class GroovyCompiler extends GroovyCompilerBase {
57 private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.compiler.GroovyCompiler");
59 public GroovyCompiler(Project project) {
60 super(project);
63 @NotNull
64 public String getDescription() {
65 return "groovy compiler";
68 @Override
69 protected void compileFiles(final CompileContext context, final Module module, List<VirtualFile> toCompile, OutputSink sink, boolean tests) {
70 final Set<VirtualFile> allToCompile = new LinkedHashSet<VirtualFile>(toCompile);
72 // 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
73 // see http://jira.codehaus.org/browse/GROOVY-4024
74 // this is important only if >1 files have been changed
75 if (toCompile.size() > 1 && !"false".equals(System.getProperty("compile.groovy.dependencies", "true"))) {
76 context.getProgressIndicator().checkCanceled();
77 context.getProgressIndicator().setText("Enumerating Groovy classes...");
79 Set<VirtualFile> groovyFiles = enumerateGroovyFiles(module);
81 if (toCompile.size() < groovyFiles.size()) {
82 context.getProgressIndicator().checkCanceled();
83 context.getProgressIndicator().setText("Processing Groovy dependencies...");
85 addIntermediateGroovyClasses(allToCompile, groovyFiles);
89 context.getProgressIndicator().checkCanceled();
90 context.getProgressIndicator().setText(GroovycOSProcessHandler.GROOVY_COMPILER_IN_OPERATION);
92 runGroovycCompiler(context, module, new ArrayList<VirtualFile>(allToCompile), false, getMainOutput(context, module, tests), sink, tests);
95 private void addIntermediateGroovyClasses(Set<VirtualFile> allToCompile, final Set<VirtualFile> groovyFiles) {
96 final Set<VirtualFile> initialFiles = new THashSet<VirtualFile>(allToCompile);
98 final THashSet<VirtualFile> visited = new THashSet<VirtualFile>();
99 for (VirtualFile aClass : initialFiles) {
100 if (visited.add(aClass)) {
101 goForIntermediateFiles(aClass, allToCompile, new FactoryMap<VirtualFile, Set<VirtualFile>>() {
102 @Override
103 protected Set<VirtualFile> create(final VirtualFile key) {
104 return ApplicationManager.getApplication().runReadAction(new Computable<Set<VirtualFile>>() {
105 public Set<VirtualFile> compute() {
106 return calcCodeReferenceDependencies(key, groovyFiles);
110 }, visited);
115 private Set<VirtualFile> enumerateGroovyFiles(final Module module) {
116 final Set<VirtualFile> moduleClasses = new THashSet<VirtualFile>();
117 ModuleRootManager.getInstance(module).getFileIndex().iterateContent(new ContentIterator() {
118 public boolean processFile(final VirtualFile vfile) {
119 if (!vfile.isDirectory() &&
120 GroovyFileType.GROOVY_FILE_TYPE.equals(vfile.getFileType())) {
121 ApplicationManager.getApplication().runReadAction(new Runnable() {
122 public void run() {
123 if (PsiManager.getInstance(myProject).findFile(vfile) instanceof GroovyFile) {
124 moduleClasses.add(vfile);
130 return true;
133 return moduleClasses;
136 private static void goForIntermediateFiles(VirtualFile from, Set<VirtualFile> dirty, FactoryMap<VirtualFile, Set<VirtualFile>> deps, Set<VirtualFile> visited) {
137 final Set<VirtualFile> set = deps.get(from);
138 for (VirtualFile psiClass : set) {
139 if (visited.add(psiClass)) {
140 goForIntermediateFiles(psiClass, dirty, deps, visited);
142 if (dirty.contains(psiClass)) {
143 dirty.add(from);
148 private Set<VirtualFile> calcCodeReferenceDependencies(VirtualFile vfile, final Set<VirtualFile> moduleFiles) {
149 final PsiFile psi = PsiManager.getInstance(myProject).findFile(vfile);
150 if (!(psi instanceof GroovyFile)) return Collections.emptySet();
152 final Set<VirtualFile> deps = new THashSet<VirtualFile>();
153 psi.acceptChildren(new PsiElementVisitor() {
154 @Override
155 public void visitElement(PsiElement element) {
156 if (element instanceof GrCodeReferenceElement) {
157 GrCodeReferenceElement referenceElement = (GrCodeReferenceElement)element;
158 try {
159 final PsiElement target = referenceElement.resolve();
160 if (target instanceof GrTypeDefinition || target instanceof GroovyScriptClass) {
161 final VirtualFile targetFile = target.getContainingFile().getViewProvider().getVirtualFile();
162 if (moduleFiles.contains(targetFile)) {
163 deps.add(targetFile);
167 catch (Exception e) {
168 LOG.error(e);
169 //prevent our PSI errors from failing the entire compilation
173 element.acceptChildren(this);
176 return deps;
179 public boolean validateConfiguration(CompileScope compileScope) {
180 VirtualFile[] files = compileScope.getFiles(GroovyFileType.GROOVY_FILE_TYPE, true);
181 if (files.length == 0) return true;
183 final Set<String> scriptExtensions = GroovyFileTypeLoader.getCustomGroovyScriptExtensions();
185 Set<Module> modules = new HashSet<Module>();
186 for (VirtualFile file : files) {
187 if (scriptExtensions.contains(file.getExtension())) {
188 continue;
191 ProjectRootManager rootManager = ProjectRootManager.getInstance(myProject);
192 Module module = rootManager.getFileIndex().getModuleForFile(file);
193 if (module != null) {
194 modules.add(module);
198 Set<Module> nojdkModules = new HashSet<Module>();
199 for (Module module : modules) {
200 if(!(module.getModuleType() instanceof JavaModuleType)) return true;
201 final Sdk sdk = ModuleRootManager.getInstance(module).getSdk();
202 if (sdk == null || !(sdk.getSdkType() instanceof JavaSdkType)) {
203 nojdkModules.add(module);
204 continue;
207 if (!LibrariesUtil.hasGroovySdk(module)) {
208 if (!GroovyConfigUtils.getInstance().tryToSetUpGroovyFacetOntheFly(module)) {
209 Messages.showErrorDialog(myProject, GroovyBundle.message("cannot.compile.groovy.files.no.facet", module.getName()),
210 GroovyBundle.message("cannot.compile"));
211 ModulesConfigurator.showDialog(module.getProject(), module.getName(), ClasspathEditor.NAME, false);
212 return false;
217 if (!nojdkModules.isEmpty()) {
218 final Module[] noJdkArray = nojdkModules.toArray(new Module[nojdkModules.size()]);
219 if (noJdkArray.length == 1) {
220 Messages.showErrorDialog(myProject, GroovyBundle.message("cannot.compile.groovy.files.no.sdk", noJdkArray[0].getName()),
221 GroovyBundle.message("cannot.compile"));
223 else {
224 StringBuffer modulesList = new StringBuffer();
225 for (int i = 0; i < noJdkArray.length; i++) {
226 if (i > 0) modulesList.append(", ");
227 modulesList.append(noJdkArray[i].getName());
229 Messages.showErrorDialog(myProject, GroovyBundle.message("cannot.compile.groovy.files.no.sdk.mult", modulesList.toString()),
230 GroovyBundle.message("cannot.compile"));
232 return false;
235 return true;