use our groovy stub generator by default, give an UI option to switch to groovyc...
[fedora-idea.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / compiler / generator / GroovyToJavaGenerator.java
blobd30851a9e1388637112a802f9d31c04942ed3fc4
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.
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;
64 import java.io.*;
65 import java.util.*;
67 /**
68 * @author: Dmitry.Krasilschikov
69 * @date: 03.05.2007
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");
75 static {
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[]{
88 PsiModifier.PUBLIC,
89 PsiModifier.PROTECTED,
90 PsiModifier.PRIVATE,
91 PsiModifier.PACKAGE_LOCAL,
92 PsiModifier.STATIC,
93 PsiModifier.ABSTRACT,
94 PsiModifier.FINAL,
95 PsiModifier.NATIVE,
96 PsiModifier.SYNCHRONIZED,
97 PsiModifier.STRICTFP,
98 PsiModifier.TRANSIENT,
99 PsiModifier.VOLATILE
102 private static final String[] JAVA_TYPE_DEFINITION_MODIFIERS = new String[]{
103 PsiModifier.PUBLIC,
104 PsiModifier.ABSTRACT,
105 PsiModifier.FINAL
108 private static final CharSequence PREFIX_SEPARATOR = "/";
109 private CompileContext myContext;
110 private final Project myProject;
112 public GroovyToJavaGenerator(Project project) {
113 myProject = project;
116 public GenerationItem[] getGenerationItems(CompileContext context) {
117 if (GroovyCompilerConfiguration.getInstance(myProject).isUseGroovycStubs()) {
118 return new GenerationItem[0];
121 myContext = context;
123 List<GenerationItem> generationItems = new ArrayList<GenerationItem>();
124 GenerationItem item;
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)) {
135 continue;
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);
145 String prefix = "";
146 if (statements.length > 0 && statements[0] instanceof GrPackageDefinition) {
147 prefix = getJavaClassPackage((GrPackageDefinition) statements[0]);
150 //top level class
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() {
176 public void run() {
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() {
215 public void run() {
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;
292 return prefix;
295 private String createJavaSourceFile(VirtualFile outputRootDirectory, GroovyFileBase file, @NotNull PsiClass typeDefinition, GrPackageDefinition packageDefinition) {
296 //prefix defines structure of directories tree
297 String prefix = "";
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;
330 break;
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");
361 text.append(" ");
363 text.append(typeDefinitionName);
365 if (typeDefinition != null) {
366 appendTypeParameters(text, typeDefinition);
369 text.append(" ");
371 if (isScript) {
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));
380 text.append(" ");
382 PsiClassType[] implementsTypes = typeDefinition.getImplementsListTypes();
384 if (implementsTypes.length > 0) {
385 text.append(isInterface ? "extends " : "implements ");
386 int i = 0;
387 while (i < implementsTypes.length) {
388 if (i > 0) text.append(", ");
389 text.append(computeTypeText(implementsTypes[i], false));
390 text.append(" ");
391 i++;
396 text.append("{");
398 if (isEnum) {
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()));
407 if (isClassDef) {
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) {
419 continue;
422 if (method instanceof GrConstructor) {
423 writeConstructor(text, (GrConstructor) method, isEnum);
424 continue;
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);
447 } else {
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);
461 text.append("}");
464 private static void appendTypeParameters(StringBuffer text, PsiTypeParameterListOwner typeParameterListOwner) {
465 if (typeParameterListOwner.hasTypeParameters()) {
466 text.append("<");
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));
481 text.append(">");
485 private void writeEnumConstants(StringBuffer text, GrEnumTypeDefinition enumDefinition) {
486 text.append("\n ");
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) {
494 text.append("(");
495 writeStubConstructorInvocation(text, constructor, PsiSubstitutor.EMPTY);
496 text.append(")");
499 GrTypeDefinitionBody block = enumConstant.getAnonymousBlock();
500 if (block != null) {
501 text.append("{\n");
502 for (PsiMethod method : block.getMethods()) {
503 writeMethod(text, method, method.getParameterList().getParameters());
505 text.append("}");
508 text.append(";");
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());
524 text.append(";");
525 text.append("\n");
526 text.append("\n");
530 private void writeConstructor(final StringBuffer text, final GrConstructor constructor, boolean isEnum) {
531 text.append("\n");
532 text.append(" ");
533 if (!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();
545 text.append("(");
546 String paramType;
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);
557 text.append(" ");
558 text.append(parameter.getName());
561 text.append(")");
562 text.append(" ");
564 /************* body **********/
566 final GrConstructorInvocation constructorInvocation = constructor.getChainingConstructorInvocation();
567 if (constructorInvocation != null) {
568 ApplicationManager.getApplication().runReadAction(new Runnable() {
569 public void run() {
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) {
576 int i = 0;
577 if (results[i].getElement() == constructor && results.length > 1) {
578 i = 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));
596 text.append("{\n");
598 text.append(" ");
599 if (constructorInvocation.isSuperCall()) {
600 text.append("super");
601 } else {
602 text.append("this");
604 text.append("(");
606 if (chainedConstructor != null) {
607 writeStubConstructorInvocation(text, chainedConstructor, substitutor);
610 text.append(")");
611 text.append(";");
615 } else {
616 text.append("{\n");
619 text.append("\n }");
620 text.append("\n");
623 private static String getDefaultValueText(String typeCanonicalText) {
624 final String result = typesToInitialValues.get(typeCanonicalText);
625 if (result == null) return "null";
626 return result;
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
641 text.append("\n ");
642 writeFieldModifiers(text, modifierList, JAVA_MODIFIERS, variable);
644 //type
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();
659 text.append("\n");
660 text.append(" ");
661 writeMethodModifiers(text, modifierList, JAVA_MODIFIERS);
662 if (method.hasTypeParameters()) {
663 appendTypeParameters(text, method);
664 text.append(" ");
667 //append return type
668 PsiType retType;
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));
675 text.append(" ");
677 //append method name
678 text.append(name);
680 /************* parameters **********/
682 text.append("(");
684 //writes myParameters
685 int i = 0;
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));
693 text.append(" ");
694 text.append(parameter.getName());
696 i++;
698 text.append(")");
699 text.append(" ");
701 if (!isAbstract) {
702 /************* body **********/
703 text.append("{\n");
704 text.append(" return ");
706 text.append(getDefaultValueText(getTypeText(retType, false)));
708 text.append(";");
710 text.append("\n }");
711 } else {
712 text.append(";");
714 text.append("\n");
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);
722 text.append(" ");
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());
731 if (isProperty) {
732 text.append("private ");
735 for (String modifierType : modifiers) {
736 if (isProperty && modifierType.equals(PsiModifier.PUBLIC)) {
737 continue;
740 if (modifierList.hasModifierProperty(modifierType)) {
741 text.append(modifierType);
742 text.append(" ");
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) {
752 continue;
754 text.append(modifierType);
755 text.append(" ");
756 wasAddedModifiers = true;
759 return wasAddedModifiers;
762 private static String getTypeText(GrTypeElement typeElement) {
763 if (typeElement == null) {
764 return "java.lang.Object";
765 } else {
766 return computeTypeText(typeElement.getType(), false);
770 private static String getTypeText(PsiType type, boolean allowVarargs) {
771 if (type == null) {
772 return "java.lang.Object";
773 } else {
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();
799 File myFile;
800 if (!"".equals(prefix))
801 myFile = new File(outputDir + File.separator + prefixWithoutSeparator, generatedItemPath);
802 else
803 myFile = new File(outputDir, generatedItemPath);
805 BufferedWriter writer = null;
806 try {
807 Writer fileWriter = new FileWriter(myFile);
808 writer = new BufferedWriter(fileWriter);
809 writer.write(text.toString());
810 } catch (IOException e) {
811 LOG.error(e);
812 } finally {
813 try {
814 assert writer != null;
815 writer.close();
816 } catch (IOException e) {
817 LOG.error(e);
822 @NotNull
823 public String getDescription() {
824 return "Groovy to java source code generator";
827 public boolean validateConfiguration(CompileScope scope) {
828 return true;
831 CharTrie myTrie = new CharTrie();
833 public void compilationFinished(boolean aborted, int errors, int warnings, final CompileContext compileContext) {
834 myTrie.clear();
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) {
849 myVFile = vFile;
850 myModule = module;
851 myState = state;
852 myInTestSources = isInTestSources;
853 myHashCode = myTrie.getHashCode(path);
856 public String getPath() {
857 return myTrie.getString(myHashCode);
860 public ValidityState getValidityState() {
861 return myState;
864 public Module getModule() {
865 return myModule;
868 public boolean isTestSource() {
869 return myInTestSources;
872 public VirtualFile getVFile() {
873 return myVFile;