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.
16 package org
.jetbrains
.plugins
.groovy
.compiler
.generator
;
18 import com
.intellij
.compiler
.CompilerConfiguration
;
19 import com
.intellij
.openapi
.application
.ApplicationManager
;
20 import com
.intellij
.openapi
.compiler
.*;
21 import com
.intellij
.openapi
.compiler
.options
.ExcludedEntriesConfiguration
;
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
.progress
.ProgressIndicator
;
26 import com
.intellij
.openapi
.project
.Project
;
27 import com
.intellij
.openapi
.roots
.ModuleRootManager
;
28 import com
.intellij
.openapi
.util
.Computable
;
29 import com
.intellij
.openapi
.util
.text
.StringUtil
;
30 import com
.intellij
.openapi
.vfs
.VfsUtil
;
31 import com
.intellij
.openapi
.vfs
.VirtualFile
;
32 import com
.intellij
.psi
.*;
33 import com
.intellij
.psi
.util
.MethodSignature
;
34 import com
.intellij
.psi
.util
.MethodSignatureUtil
;
35 import com
.intellij
.util
.ArrayUtil
;
36 import com
.intellij
.util
.containers
.HashSet
;
37 import gnu
.trove
.THashSet
;
38 import org
.jetbrains
.annotations
.NotNull
;
39 import org
.jetbrains
.plugins
.groovy
.GroovyFileType
;
40 import org
.jetbrains
.plugins
.groovy
.compiler
.GroovyCompilerConfiguration
;
41 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.GroovyFile
;
42 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.GroovyFileBase
;
43 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.GroovyResolveResult
;
44 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.auxiliary
.modifiers
.GrModifierList
;
45 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.GrConstructorInvocation
;
46 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.GrField
;
47 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.GrVariable
;
48 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.GrVariableDeclaration
;
49 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.params
.GrParameter
;
50 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.typedef
.*;
51 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.typedef
.members
.GrConstructor
;
52 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.typedef
.members
.GrEnumConstant
;
53 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.typedef
.members
.GrMembersDeclaration
;
54 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.typedef
.members
.GrMethod
;
55 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.toplevel
.GrTopStatement
;
56 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.toplevel
.imports
.GrImportStatement
;
57 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.toplevel
.packaging
.GrPackageDefinition
;
58 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.types
.GrTypeElement
;
59 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.statements
.expressions
.TypesUtil
;
60 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.synthetic
.GrSyntheticMethodImplementation
;
61 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.synthetic
.GroovyScriptClass
;
62 import org
.jetbrains
.plugins
.groovy
.util
.containers
.CharTrie
;
68 * @author: Dmitry.Krasilschikov
71 public class GroovyToJavaGenerator
implements SourceGeneratingCompiler
, CompilationStatusListener
{
72 private static final Map
<String
, String
> typesToInitialValues
= new HashMap
<String
, String
>();
73 private static final Logger LOG
= Logger
.getInstance("org.jetbrains.plugins.groovy.compiler.generator.GroovyToJavaGenerator");
76 typesToInitialValues
.put("boolean", "false");
77 typesToInitialValues
.put("int", "0");
78 typesToInitialValues
.put("short", "0");
79 typesToInitialValues
.put("long", "0L");
80 typesToInitialValues
.put("byte", "0");
81 typesToInitialValues
.put("char", "'c'");
82 typesToInitialValues
.put("double", "0D");
83 typesToInitialValues
.put("float", "0F");
84 typesToInitialValues
.put("void", "");
87 private static final String
[] JAVA_MODIFIERS
= new String
[]{
89 PsiModifier
.PROTECTED
,
91 PsiModifier
.PACKAGE_LOCAL
,
96 PsiModifier
.SYNCHRONIZED
,
98 PsiModifier
.TRANSIENT
,
102 private static final String
[] JAVA_TYPE_DEFINITION_MODIFIERS
= new String
[]{
104 PsiModifier
.ABSTRACT
,
108 private static final CharSequence PREFIX_SEPARATOR
= "/";
109 private CompileContext myContext
;
110 private final Project myProject
;
112 public GroovyToJavaGenerator(Project project
) {
116 public GenerationItem
[] getGenerationItems(CompileContext context
) {
117 if (GroovyCompilerConfiguration
.getInstance(myProject
).isUseGroovycStubs()) {
118 return new GenerationItem
[0];
123 List
<GenerationItem
> generationItems
= new ArrayList
<GenerationItem
>();
125 final CompilerManager compilerManager
= CompilerManager
.getInstance(myProject
);
126 final CompilerConfiguration compilerConfiguration
= CompilerConfiguration
.getInstance(myProject
);
127 final ExcludedEntriesConfiguration excluded
= GroovyCompilerConfiguration
.getExcludeConfiguration(myProject
);
128 for (VirtualFile file
: getGroovyFilesToGenerate(context
)) {
129 if (compilerManager
.isExcludedFromCompilation(file
)) continue;
130 if (excluded
.isExcluded(file
)) continue;
131 if (compilerConfiguration
.isResourceFile(file
)) continue;
133 final Module module
= getModuleByFile(context
, file
);
134 if (module
== null || !(module
.getModuleType() instanceof JavaModuleType
)) {
138 boolean isInTestSources
= ModuleRootManager
.getInstance(module
).getFileIndex().isInTestSourceContent(file
);
140 final GroovyFileBase psiFile
= findPsiFile(file
);
141 GrTopStatement
[] statements
= getTopStatementsInReadAction(psiFile
);
143 boolean needCreateTopLevelClass
= !needsCreateClassFromFileName(statements
);
146 if (statements
.length
> 0 && statements
[0] instanceof GrPackageDefinition
) {
147 prefix
= getJavaClassPackage((GrPackageDefinition
) statements
[0]);
151 if (needCreateTopLevelClass
) {
152 generationItems
.add(new GenerationItemImpl(prefix
+ file
.getNameWithoutExtension() + "." + "java", module
, new TimestampValidityState(file
.getTimeStamp()), isInTestSources
, file
));
155 GrTypeDefinition
[] typeDefinitions
= ApplicationManager
.getApplication().runReadAction(new Computable
<GrTypeDefinition
[]>() {
156 public GrTypeDefinition
[] compute() {
157 return psiFile
.getTypeDefinitions();
161 for (GrTypeDefinition typeDefinition
: typeDefinitions
) {
162 item
= new GenerationItemImpl(prefix
+ typeDefinition
.getName() + "." + "java", module
, new TimestampValidityState(file
.getTimeStamp()), isInTestSources
, file
);
163 generationItems
.add(item
);
166 return generationItems
.toArray(new GenerationItem
[generationItems
.size()]);
169 protected Module
getModuleByFile(CompileContext context
, VirtualFile file
) {
170 return context
.getModuleByFile(file
);
173 protected VirtualFile
[] getGroovyFilesToGenerate(final CompileContext context
) {
174 final HashSet
<VirtualFile
> set
= new HashSet
<VirtualFile
>();
175 ApplicationManager
.getApplication().runReadAction(new Runnable() {
177 set
.addAll(Arrays
.asList(context
.getProjectCompileScope().getFiles(GroovyFileType
.GROOVY_FILE_TYPE
, true)));
181 return VfsUtil
.toVirtualFileArray(set
);
184 public GenerationItem
[] generate(CompileContext context
, GenerationItem
[] itemsToGenerate
, VirtualFile outputRootDirectory
) {
185 List
<GenerationItem
> generatedItems
= new ArrayList
<GenerationItem
>();
186 Map
<String
, GenerationItem
> pathsToItemsMap
= new HashMap
<String
, GenerationItem
>();
188 //puts items witch can be generated
189 for (GenerationItem item
: itemsToGenerate
) {
190 pathsToItemsMap
.put(item
.getPath(), item
);
193 Set
<VirtualFile
> vFiles
= new HashSet
<VirtualFile
>();
194 for (GenerationItem item
: itemsToGenerate
) {
195 vFiles
.add(((GenerationItemImpl
) item
).getVFile());
198 for (VirtualFile vFile
: vFiles
) {
199 //generate java classes form groovy source files
200 List
<String
> generatedJavaFilesRelPaths
= generateItems(vFile
, outputRootDirectory
);
201 for (String relPath
: generatedJavaFilesRelPaths
) {
202 GenerationItem generationItem
= pathsToItemsMap
.get(relPath
);
203 if (generationItem
!= null)
204 generatedItems
.add(generationItem
);
208 return generatedItems
.toArray(new GenerationItem
[generatedItems
.size()]);
211 private GroovyFile
findPsiFile(final VirtualFile virtualFile
) {
212 final GroovyFile
[] myFindPsiFile
= new GroovyFile
[1];
214 ApplicationManager
.getApplication().runReadAction(new Runnable() {
216 myFindPsiFile
[0] = (GroovyFile
) PsiManager
.getInstance(myProject
).findFile(virtualFile
);
220 assert myFindPsiFile
[0] != null;
221 return myFindPsiFile
[0];
224 //virtualFile -> PsiFile
225 private List
<String
> generateItems(final VirtualFile item
, final VirtualFile outputRootDirectory
) {
226 ProgressIndicator indicator
= getProcessIndicator();
227 if (indicator
!= null) indicator
.setText("Generating stubs for " + item
.getName() + "...");
229 if (LOG
.isDebugEnabled()) {
230 LOG
.debug("Generating stubs for " + item
.getName() + "...");
233 final GroovyFile file
= findPsiFile(item
);
235 List
<String
> generatedJavaFilesRelPaths
= ApplicationManager
.getApplication().runReadAction(new Computable
<List
<String
>>() {
236 public List
<String
> compute() {
237 return generate(file
, outputRootDirectory
);
241 assert generatedJavaFilesRelPaths
!= null;
243 return generatedJavaFilesRelPaths
;
246 protected ProgressIndicator
getProcessIndicator() {
247 return myContext
.getProgressIndicator();
250 private List
<String
> generate(final GroovyFile file
, VirtualFile outputRootDirectory
) {
251 List
<String
> generatedItemsRelativePaths
= new ArrayList
<String
>();
253 GrTopStatement
[] statements
= getTopStatementsInReadAction(file
);
255 GrPackageDefinition packageDefinition
= null;
256 if (statements
.length
> 0 && statements
[0] instanceof GrPackageDefinition
) {
257 packageDefinition
= (GrPackageDefinition
) statements
[0];
260 Set
<String
> classNames
= new THashSet
<String
>();
261 for (final GrTypeDefinition typeDefinition
: file
.getTypeDefinitions()) {
262 classNames
.add(typeDefinition
.getName());
265 if (file
.isScript()) {
266 VirtualFile virtualFile
= file
.getVirtualFile();
267 assert virtualFile
!= null;
268 String fileDefinitionName
= virtualFile
.getNameWithoutExtension();
269 if (!classNames
.contains(StringUtil
.capitalize(fileDefinitionName
)) &&
270 !classNames
.contains(StringUtil
.decapitalize(fileDefinitionName
))) {
271 final PsiClass scriptClass
= file
.getScriptClass();
272 if (scriptClass
!= null) {
273 generatedItemsRelativePaths
.add(createJavaSourceFile(outputRootDirectory
, file
, scriptClass
, packageDefinition
));
278 for (final GrTypeDefinition typeDefinition
: file
.getTypeDefinitions()) {
279 generatedItemsRelativePaths
.add(createJavaSourceFile(outputRootDirectory
, file
, typeDefinition
, packageDefinition
));
282 return generatedItemsRelativePaths
;
285 private static String
getJavaClassPackage(GrPackageDefinition packageDefinition
) {
286 if (packageDefinition
== null) return "";
288 String prefix
= packageDefinition
.getPackageName();
289 prefix
= prefix
.replace(".", PREFIX_SEPARATOR
);
290 prefix
+= PREFIX_SEPARATOR
;
295 private String
createJavaSourceFile(VirtualFile outputRootDirectory
, GroovyFileBase file
, @NotNull PsiClass typeDefinition
, GrPackageDefinition packageDefinition
) {
296 //prefix defines structure of directories tree
298 if (packageDefinition
!= null) {
299 prefix
= getJavaClassPackage(packageDefinition
);
302 StringBuffer text
= new StringBuffer();
304 final String typeDefinitionName
= typeDefinition
.getName();
305 writeTypeDefinition(text
, typeDefinitionName
, typeDefinition
, packageDefinition
);
307 VirtualFile virtualFile
= file
.getVirtualFile();
308 assert virtualFile
!= null;
309 // String generatedFileRelativePath = prefix + typeDefinitionName + "." + "java";
310 String fileShortName
= typeDefinitionName
+ "." + "java";
311 createGeneratedFile(text
, outputRootDirectory
.getPath(), prefix
, fileShortName
);
312 return prefix
+ typeDefinitionName
+ "." + "java";
315 private static GrTopStatement
[] getTopStatementsInReadAction(final GroovyFileBase myPsiFile
) {
316 if (myPsiFile
== null) return new GrTopStatement
[0];
318 return ApplicationManager
.getApplication().runReadAction(new Computable
<GrTopStatement
[]>() {
319 public GrTopStatement
[] compute() {
320 return myPsiFile
.getTopStatements();
325 private static boolean needsCreateClassFromFileName(GrTopStatement
[] statements
) {
326 boolean isOnlyInnerTypeDef
= true;
327 for (GrTopStatement statement
: statements
) {
328 if (!(statement
instanceof GrTypeDefinition
|| statement
instanceof GrImportStatement
|| statement
instanceof GrPackageDefinition
)) {
329 isOnlyInnerTypeDef
= false;
333 return isOnlyInnerTypeDef
;
336 private void writeTypeDefinition(StringBuffer text
, String typeDefinitionName
, @NotNull PsiClass typeDefinition
, GrPackageDefinition packageDefinition
) {
337 final boolean isScript
= typeDefinition
instanceof GroovyScriptClass
;
339 writePackageStatement(text
, packageDefinition
);
341 GrMembersDeclaration
[] membersDeclarations
= typeDefinition
instanceof GrTypeDefinition ?
((GrTypeDefinition
) typeDefinition
).getMemberDeclarations() : GrMembersDeclaration
.EMPTY_ARRAY
; //todo
343 boolean isClassDef
= typeDefinition
instanceof GrClassDefinition
;
344 boolean isInterface
= typeDefinition
instanceof GrInterfaceDefinition
;
345 boolean isEnum
= typeDefinition
instanceof GrEnumTypeDefinition
;
346 boolean isAtInterface
= typeDefinition
instanceof GrAnnotationTypeDefinition
;
349 PsiModifierList modifierList
= typeDefinition
.getModifierList();
351 boolean wasAddedModifiers
= modifierList
!= null && writeTypeDefinitionMethodModifiers(text
, modifierList
, JAVA_TYPE_DEFINITION_MODIFIERS
, typeDefinition
.isInterface());
352 if (!wasAddedModifiers
) {
353 text
.append("public ");
356 if (isInterface
) text
.append("interface");
357 else if (isEnum
) text
.append("enum");
358 else if (isAtInterface
) text
.append("@interface");
359 else text
.append("class");
363 text
.append(typeDefinitionName
);
365 if (typeDefinition
!= null) {
366 appendTypeParameters(text
, typeDefinition
);
372 text
.append("extends ");
373 text
.append("groovy.lang.Script ");
374 } else if (!isEnum
&& !isAtInterface
) {
375 final PsiClassType
[] extendsClassesTypes
= typeDefinition
.getExtendsListTypes();
377 if (extendsClassesTypes
.length
> 0) {
378 text
.append("extends ");
379 text
.append(computeTypeText(extendsClassesTypes
[0], false));
382 PsiClassType
[] implementsTypes
= typeDefinition
.getImplementsListTypes();
384 if (implementsTypes
.length
> 0) {
385 text
.append(isInterface ?
"extends " : "implements ");
387 while (i
< implementsTypes
.length
) {
388 if (i
> 0) text
.append(", ");
389 text
.append(computeTypeText(implementsTypes
[i
], false));
399 writeEnumConstants(text
, (GrEnumTypeDefinition
) typeDefinition
);
402 Set
<MethodSignature
> methodSignatures
= new HashSet
<MethodSignature
>();
405 List
<PsiMethod
> methods
= new ArrayList
<PsiMethod
>();
406 methods
.addAll(Arrays
.asList(typeDefinition
.getMethods()));
408 final PsiElementFactory factory
= JavaPsiFacade
.getInstance(myProject
).getElementFactory();
409 methods
.add(factory
.createMethodFromText("public groovy.lang.MetaClass getMetaClass() {}", null));
410 methods
.add(factory
.createMethodFromText("public void setMetaClass(groovy.lang.MetaClass mc) {}", null));
411 methods
.add(factory
.createMethodFromText("public Object invokeMethod(String name, Object args) {}", null));
412 methods
.add(factory
.createMethodFromText("public Object getProperty(String propertyName) {}", null));
413 methods
.add(factory
.createMethodFromText("public void setProperty(String propertyName, Object newValue) {}", null));
417 for (PsiMethod method
: methods
) {
418 if (method
instanceof GrSyntheticMethodImplementation
) {
422 if (method
instanceof GrConstructor
) {
423 writeConstructor(text
, (GrConstructor
) method
, isEnum
);
427 PsiParameter
[] parameters
= method
.getParameterList().getParameters();
428 if (parameters
.length
> 0) {
429 PsiParameter
[] parametersCopy
= new PsiParameter
[parameters
.length
];
430 PsiType
[] parameterTypes
= new PsiType
[parameters
.length
];
431 for (int i
= 0; i
< parameterTypes
.length
; i
++) {
432 parametersCopy
[i
] = parameters
[i
];
433 parameterTypes
[i
] = parameters
[i
].getType();
436 for (int i
= parameters
.length
- 1; i
>= 0; i
--) {
437 MethodSignature signature
= MethodSignatureUtil
.createMethodSignature(method
.getName(), parameterTypes
, method
.getTypeParameters(), PsiSubstitutor
.EMPTY
);
438 if (methodSignatures
.add(signature
)) {
439 writeMethod(text
, method
, parametersCopy
);
442 PsiParameter parameter
= parameters
[i
];
443 if (!(parameter
instanceof GrParameter
) || !((GrParameter
) parameter
).isOptional()) break;
444 parameterTypes
= ArrayUtil
.remove(parameterTypes
, parameterTypes
.length
- 1);
445 parametersCopy
= ArrayUtil
.remove(parametersCopy
, parametersCopy
.length
- 1);
448 MethodSignature signature
= method
.getSignature(PsiSubstitutor
.EMPTY
);
449 if (methodSignatures
.add(signature
)) {
450 writeMethod(text
, method
, parameters
);
455 for (GrMembersDeclaration declaration
: membersDeclarations
) {
456 if (declaration
instanceof GrVariableDeclaration
) {
457 writeVariableDeclarations(text
, (GrVariableDeclaration
) declaration
);
464 private static void appendTypeParameters(StringBuffer text
, PsiTypeParameterListOwner typeParameterListOwner
) {
465 if (typeParameterListOwner
.hasTypeParameters()) {
467 PsiTypeParameter
[] parameters
= typeParameterListOwner
.getTypeParameters();
468 for (int i
= 0; i
< parameters
.length
; i
++) {
469 if (i
> 0) text
.append(", ");
470 PsiTypeParameter parameter
= parameters
[i
];
471 text
.append(parameter
.getName());
472 PsiClassType
[] extendsListTypes
= parameter
.getExtendsListTypes();
473 if (extendsListTypes
.length
> 0) {
474 text
.append(" extends ");
475 for (int j
= 0; j
< extendsListTypes
.length
; j
++) {
476 if (j
> 0) text
.append(" & ");
477 text
.append(computeTypeText(extendsListTypes
[j
], false));
485 private void writeEnumConstants(StringBuffer text
, GrEnumTypeDefinition enumDefinition
) {
487 GrEnumConstant
[] enumConstants
= enumDefinition
.getEnumConstants();
488 for (int i
= 0; i
< enumConstants
.length
; i
++) {
489 if (i
> 0) text
.append(", ");
490 GrEnumConstant enumConstant
= enumConstants
[i
];
491 text
.append(enumConstant
.getName());
492 PsiMethod constructor
= enumConstant
.resolveConstructor();
493 if (constructor
!= null) {
495 writeStubConstructorInvocation(text
, constructor
, PsiSubstitutor
.EMPTY
);
499 GrTypeDefinitionBody block
= enumConstant
.getAnonymousBlock();
502 for (PsiMethod method
: block
.getMethods()) {
503 writeMethod(text
, method
, method
.getParameterList().getParameters());
511 private static void writeStubConstructorInvocation(StringBuffer text
, PsiMethod constructor
, PsiSubstitutor substitutor
) {
512 final PsiParameter
[] superParams
= constructor
.getParameterList().getParameters();
513 for (int j
= 0; j
< superParams
.length
; j
++) {
514 if (j
> 0) text
.append(", ");
515 String typeText
= getTypeText(substitutor
.substitute(superParams
[j
].getType()), false);
516 text
.append("(").append(typeText
).append(")").append(getDefaultValueText(typeText
));
520 private static void writePackageStatement(StringBuffer text
, GrPackageDefinition packageDefinition
) {
521 if (packageDefinition
!= null) {
522 text
.append("package ");
523 text
.append(packageDefinition
.getPackageName());
530 private void writeConstructor(final StringBuffer text
, final GrConstructor constructor
, boolean isEnum
) {
534 text
.append("public ");
535 //writeMethodModifiers(text, constructor.getModifierList(), JAVA_MODIFIERS);
538 /************* name **********/
539 //append constructor name
540 text
.append(constructor
.getName());
542 /************* parameters **********/
543 GrParameter
[] parameterList
= constructor
.getParameters();
547 GrTypeElement paramTypeElement
;
549 for (int i
= 0; i
< parameterList
.length
; i
++) {
550 if (i
> 0) text
.append(", ");
552 GrParameter parameter
= parameterList
[i
];
553 paramTypeElement
= parameter
.getTypeElementGroovy();
554 paramType
= getTypeText(paramTypeElement
);
556 text
.append(paramType
);
558 text
.append(parameter
.getName());
564 /************* body **********/
566 final GrConstructorInvocation constructorInvocation
= constructor
.getChainingConstructorInvocation();
567 if (constructorInvocation
!= null) {
568 ApplicationManager
.getApplication().runReadAction(new Runnable() {
570 GroovyResolveResult resolveResult
= constructorInvocation
.resolveConstructorGenerics();
571 PsiSubstitutor substitutor
= resolveResult
.getSubstitutor();
572 PsiMethod chainedConstructor
= (PsiMethod
) resolveResult
.getElement();
573 if (chainedConstructor
== null) {
574 final GroovyResolveResult
[] results
= constructorInvocation
.multiResolveConstructor();
575 if (results
.length
> 0) {
577 if (results
[i
].getElement() == constructor
&& results
.length
> 1) {
580 chainedConstructor
= (PsiMethod
) results
[i
].getElement();
581 substitutor
= results
[i
].getSubstitutor();
585 if (chainedConstructor
!= null) {
586 final PsiClassType
[] throwsTypes
= chainedConstructor
.getThrowsList().getReferencedTypes();
587 if (throwsTypes
.length
> 0) {
588 text
.append(" throws ");
589 for (int i
= 0; i
< throwsTypes
.length
; i
++) {
590 if (i
> 0) text
.append(", ");
591 text
.append(getTypeText(substitutor
.substitute(throwsTypes
[i
]), false));
599 if (constructorInvocation
.isSuperCall()) {
600 text
.append("super");
606 if (chainedConstructor
!= null) {
607 writeStubConstructorInvocation(text
, chainedConstructor
, substitutor
);
623 private static String
getDefaultValueText(String typeCanonicalText
) {
624 final String result
= typesToInitialValues
.get(typeCanonicalText
);
625 if (result
== null) return "null";
629 private static void writeVariableDeclarations(StringBuffer text
, GrVariableDeclaration variableDeclaration
) {
630 final String type
= getTypeText(variableDeclaration
.getTypeElementGroovy());
631 final String initializer
= getDefaultValueText(type
);
633 final GrModifierList modifierList
= variableDeclaration
.getModifierList();
634 final PsiNameHelper nameHelper
= JavaPsiFacade
.getInstance(variableDeclaration
.getProject()).getNameHelper();
635 for (final GrVariable variable
: variableDeclaration
.getVariables()) {
636 String name
= variable
.getName();
637 if (!nameHelper
.isIdentifier(name
)) {
638 continue; //does not have a java image
642 writeFieldModifiers(text
, modifierList
, JAVA_MODIFIERS
, variable
);
645 text
.append(type
).append(" ").append(name
).append(" = ").append(initializer
).append(";\n");
649 private static void writeMethod(StringBuffer text
, PsiMethod method
, final PsiParameter
[] parameters
) {
650 if (method
== null) return;
651 String name
= method
.getName();
652 if (!JavaPsiFacade
.getInstance(method
.getProject()).getNameHelper().isIdentifier(name
))
653 return; //does not have a java image
655 boolean isAbstract
= method
.hasModifierProperty(PsiModifier
.ABSTRACT
);
657 PsiModifierList modifierList
= method
.getModifierList();
661 writeMethodModifiers(text
, modifierList
, JAVA_MODIFIERS
);
662 if (method
.hasTypeParameters()) {
663 appendTypeParameters(text
, method
);
669 if (method
instanceof GrMethod
) {
670 retType
= ((GrMethod
) method
).getDeclaredReturnType();
671 if (retType
== null) retType
= TypesUtil
.getJavaLangObject((GrMethod
) method
);
672 } else retType
= method
.getReturnType();
674 text
.append(getTypeText(retType
, false));
680 /************* parameters **********/
684 //writes myParameters
686 while (i
< parameters
.length
) {
687 PsiParameter parameter
= parameters
[i
];
688 if (parameter
== null) continue;
690 if (i
> 0) text
.append(", "); //append ','
692 text
.append(getTypeText(parameter
.getType(), i
== parameters
.length
- 1));
694 text
.append(parameter
.getName());
702 /************* body **********/
704 text
.append(" return ");
706 text
.append(getDefaultValueText(getTypeText(retType
, false)));
717 private static boolean writeMethodModifiers(StringBuffer text
, PsiModifierList modifierList
, String
[] modifiers
) {
718 boolean wasAddedModifiers
= false;
719 for (String modifierType
: modifiers
) {
720 if (modifierList
.hasModifierProperty(modifierType
)) {
721 text
.append(modifierType
);
723 wasAddedModifiers
= true;
726 return wasAddedModifiers
;
729 private static void writeFieldModifiers(StringBuffer text
, GrModifierList modifierList
, String
[] modifiers
, GrVariable variable
) {
730 final boolean isProperty
= variable
instanceof GrField
&& !modifierList
.hasExplicitVisibilityModifiers() && !(((GrField
)variable
).getContainingClass().isInterface());
732 text
.append("private ");
735 for (String modifierType
: modifiers
) {
736 if (isProperty
&& modifierType
.equals(PsiModifier
.PUBLIC
)) {
740 if (modifierList
.hasModifierProperty(modifierType
)) {
741 text
.append(modifierType
);
747 private static boolean writeTypeDefinitionMethodModifiers(StringBuffer text
, PsiModifierList modifierList
, String
[] modifiers
, boolean isInterface
) {
748 boolean wasAddedModifiers
= false;
749 for (String modifierType
: modifiers
) {
750 if (modifierList
.hasModifierProperty(modifierType
)) {
751 if (PsiModifier
.ABSTRACT
.equals(modifierType
) && isInterface
) {
754 text
.append(modifierType
);
756 wasAddedModifiers
= true;
759 return wasAddedModifiers
;
762 private static String
getTypeText(GrTypeElement typeElement
) {
763 if (typeElement
== null) {
764 return "java.lang.Object";
766 return computeTypeText(typeElement
.getType(), false);
770 private static String
getTypeText(PsiType type
, boolean allowVarargs
) {
772 return "java.lang.Object";
774 return computeTypeText(type
, allowVarargs
);
778 private static String
computeTypeText(PsiType type
, boolean allowVarargs
) {
779 if (type
instanceof PsiArrayType
) {
780 String componentText
= computeTypeText(((PsiArrayType
) type
).getComponentType(), false);
781 if (allowVarargs
&& type
instanceof PsiEllipsisType
) return componentText
+ "...";
782 return componentText
+ "[]";
785 String canonicalText
= type
.getCanonicalText();
786 return canonicalText
!= null ? canonicalText
: type
.getPresentableText();
789 private static void createGeneratedFile(StringBuffer text
, String outputDir
, String prefix
, String generatedItemPath
) {
790 assert prefix
!= null;
792 String prefixWithoutSeparator
= prefix
;
794 if (!"".equals(prefix
)) {
795 prefixWithoutSeparator
= prefix
.substring(0, prefix
.length() - PREFIX_SEPARATOR
.length());
796 new File(outputDir
, prefixWithoutSeparator
).mkdirs();
800 if (!"".equals(prefix
))
801 myFile
= new File(outputDir
+ File
.separator
+ prefixWithoutSeparator
, generatedItemPath
);
803 myFile
= new File(outputDir
, generatedItemPath
);
805 BufferedWriter writer
= null;
807 Writer fileWriter
= new FileWriter(myFile
);
808 writer
= new BufferedWriter(fileWriter
);
809 writer
.write(text
.toString());
810 } catch (IOException e
) {
814 assert writer
!= null;
816 } catch (IOException e
) {
823 public String
getDescription() {
824 return "Groovy to java source code generator";
827 public boolean validateConfiguration(CompileScope scope
) {
831 CharTrie myTrie
= new CharTrie();
833 public void compilationFinished(boolean aborted
, int errors
, int warnings
, final CompileContext compileContext
) {
837 public ValidityState
createValidityState(DataInput in
) throws IOException
{
838 return TimestampValidityState
.load(in
);
841 class GenerationItemImpl
implements GenerationItem
{
842 ValidityState myState
;
843 private final boolean myInTestSources
;
844 final Module myModule
;
845 public int myHashCode
;
846 private final VirtualFile myVFile
;
848 public GenerationItemImpl(String path
, Module module
, ValidityState state
, boolean isInTestSources
, VirtualFile vFile
) {
852 myInTestSources
= isInTestSources
;
853 myHashCode
= myTrie
.getHashCode(path
);
856 public String
getPath() {
857 return myTrie
.getString(myHashCode
);
860 public ValidityState
getValidityState() {
864 public Module
getModule() {
868 public boolean isTestSource() {
869 return myInTestSources
;
872 public VirtualFile
getVFile() {