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
;
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
) {
64 public String
getDescription() {
65 return "groovy compiler";
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
>>() {
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
);
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() {
123 if (PsiManager
.getInstance(myProject
).findFile(vfile
) instanceof GroovyFile
) {
124 moduleClasses
.add(vfile
);
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
)) {
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() {
155 public void visitElement(PsiElement element
) {
156 if (element
instanceof GrCodeReferenceElement
) {
157 GrCodeReferenceElement referenceElement
= (GrCodeReferenceElement
)element
;
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
) {
169 //prevent our PSI errors from failing the entire compilation
173 element
.acceptChildren(this);
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())) {
191 ProjectRootManager rootManager
= ProjectRootManager
.getInstance(myProject
);
192 Module module
= rootManager
.getFileIndex().getModuleForFile(file
);
193 if (module
!= null) {
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
);
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);
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"));
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"));