update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInsight / generation / GenerateConstructorHandler.java
blob4bde9f7011e5bf02992beeb4627c1c22d1858a61
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 com.intellij.codeInsight.generation;
18 import com.intellij.CommonBundle;
19 import com.intellij.codeInsight.AnnotationUtil;
20 import com.intellij.codeInsight.CodeInsightBundle;
21 import com.intellij.codeInsight.daemon.ImplicitUsageProvider;
22 import com.intellij.ide.util.MemberChooser;
23 import com.intellij.openapi.diagnostic.Logger;
24 import com.intellij.openapi.project.Project;
25 import com.intellij.openapi.ui.Messages;
26 import com.intellij.openapi.extensions.Extensions;
27 import com.intellij.psi.*;
28 import com.intellij.psi.codeStyle.CodeStyleManager;
29 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
30 import com.intellij.psi.codeStyle.VariableKind;
31 import com.intellij.psi.javadoc.PsiDocComment;
32 import com.intellij.psi.util.TypeConversionUtil;
33 import com.intellij.psi.util.PsiUtil;
34 import com.intellij.util.Function;
35 import com.intellij.util.IncorrectOperationException;
36 import com.intellij.util.containers.ContainerUtil;
37 import org.jetbrains.annotations.NonNls;
38 import org.jetbrains.annotations.NotNull;
39 import org.jetbrains.annotations.Nullable;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Collections;
44 import java.util.List;
46 public class GenerateConstructorHandler extends GenerateMembersHandlerBase {
47 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.generation.GenerateConstructorHandler");
48 private boolean myCopyJavadoc;
50 public GenerateConstructorHandler() {
51 super(CodeInsightBundle.message("generate.constructor.fields.chooser.title"));
54 protected ClassMember[] getAllOriginalMembers(PsiClass aClass) {
55 PsiField[] fields = aClass.getFields();
56 ArrayList<ClassMember> array = new ArrayList<ClassMember>();
57 ImplicitUsageProvider[] implicitUsageProviders = Extensions.getExtensions(ImplicitUsageProvider.EP_NAME);
58 fieldLoop: for (PsiField field : fields) {
59 if (field.hasModifierProperty(PsiModifier.STATIC)) continue;
61 if (field.hasModifierProperty(PsiModifier.FINAL) && field.getInitializer() != null) continue;
63 for(ImplicitUsageProvider provider: implicitUsageProviders) {
64 if (provider.isImplicitWrite(field)) continue fieldLoop;
66 array.add(new PsiFieldMember(field));
68 return array.toArray(new ClassMember[array.size()]);
71 @Nullable
72 protected ClassMember[] chooseOriginalMembers(PsiClass aClass, Project project) {
73 if (aClass instanceof PsiAnonymousClass){
74 Messages.showMessageDialog(project,
75 CodeInsightBundle.message("error.attempt.to.generate.constructor.for.anonymous.class"),
76 CommonBundle.getErrorTitle(),
77 Messages.getErrorIcon());
78 return null;
81 myCopyJavadoc = false;
82 PsiMethod[] baseConstructors = null;
83 PsiClass baseClass = aClass.getSuperClass();
84 if (baseClass != null){
85 ArrayList<PsiMethod> array = new ArrayList<PsiMethod>();
86 PsiMethod[] methods = baseClass.getMethods();
87 for (PsiMethod method : methods) {
88 if (method.isConstructor()) {
89 if (JavaPsiFacade.getInstance(method.getProject()).getResolveHelper().isAccessible(method, aClass, aClass)) {
90 array.add(method);
94 if (array.size() > 0){
95 if (array.size() == 1){
96 baseConstructors = new PsiMethod[]{array.get(0)};
98 else{
99 final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, aClass, PsiSubstitutor.EMPTY);
100 PsiMethodMember[] constructors = ContainerUtil.map2Array(array, PsiMethodMember.class, new Function<PsiMethod, PsiMethodMember>() {
101 public PsiMethodMember fun(final PsiMethod s) {
102 return new PsiMethodMember(s, substitutor);
105 MemberChooser<PsiMethodMember> chooser = new MemberChooser<PsiMethodMember>(constructors, false, true, project);
106 chooser.setTitle(CodeInsightBundle.message("generate.constructor.super.constructor.chooser.title"));
107 chooser.show();
108 List<PsiMethodMember> elements = chooser.getSelectedElements();
109 if (elements == null || elements.size() == 0) return null;
110 baseConstructors = new PsiMethod[elements.size()];
111 for(int i = 0; i < elements.size(); i++){
112 final ClassMember member = elements.get(i);
113 baseConstructors[i] = ((PsiMethodMember)member).getElement();
115 myCopyJavadoc = chooser.isCopyJavadoc();
120 ClassMember[] allMembers = getAllOriginalMembers(aClass);
121 ClassMember[] members;
122 if (allMembers.length == 0) {
123 members = ClassMember.EMPTY_ARRAY;
125 else{
126 members = chooseMembers(allMembers, true, false, project);
127 if (members == null) return null;
129 if (baseConstructors != null){
130 ArrayList<ClassMember> array = new ArrayList<ClassMember>();
131 for (PsiMethod baseConstructor : baseConstructors) {
132 array.add(new PsiMethodMember(baseConstructor));
134 array.addAll(Arrays.asList(members));
135 members = array.toArray(new ClassMember[array.size()]);
138 return members;
141 @NotNull
142 protected List<? extends GenerationInfo> generateMemberPrototypes(PsiClass aClass, ClassMember[] members) throws IncorrectOperationException {
143 ArrayList<PsiMethod> baseConstructors = new ArrayList<PsiMethod>();
144 ArrayList<PsiElement> fieldsVector = new ArrayList<PsiElement>();
145 for (ClassMember member1 : members) {
146 PsiElement member = ((PsiElementClassMember)member1).getElement();
147 if (member instanceof PsiMethod) {
148 baseConstructors.add((PsiMethod)member);
150 else {
151 fieldsVector.add(member);
154 PsiField[] fields = fieldsVector.toArray(new PsiField[fieldsVector.size()]);
156 if (!baseConstructors.isEmpty()) {
157 List<GenerationInfo> constructors = new ArrayList<GenerationInfo>(baseConstructors.size());
158 final PsiClass superClass = aClass.getSuperClass();
159 assert superClass != null;
160 PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY);
161 for (PsiMethod baseConstructor : baseConstructors) {
162 if (substitutor != PsiSubstitutor.EMPTY) {
163 baseConstructor = GenerateMembersUtil.substituteGenericMethod(baseConstructor, substitutor);
165 constructors.add(new PsiGenerationInfo(generateConstructorPrototype(aClass, baseConstructor, myCopyJavadoc, fields)));
167 return constructors;
169 return Collections.<GenerationInfo>singletonList(new PsiGenerationInfo(generateConstructorPrototype(aClass, null, false, fields)));
172 public static PsiMethod generateConstructorPrototype(PsiClass aClass, PsiMethod baseConstructor, boolean copyJavaDoc, PsiField[] fields) throws IncorrectOperationException {
173 PsiManager manager = aClass.getManager();
174 PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
175 CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject());
177 PsiMethod constructor = factory.createConstructor();
178 @Modifier String modifier = getConstructorModifier(aClass);
179 if (modifier != null) {
180 PsiUtil.setModifierProperty(constructor, modifier, true);
183 if (baseConstructor != null){
184 PsiJavaCodeReferenceElement[] throwRefs = baseConstructor.getThrowsList().getReferenceElements();
185 for (PsiJavaCodeReferenceElement ref : throwRefs) {
186 constructor.getThrowsList().add(ref);
189 if(copyJavaDoc) {
190 final PsiDocComment docComment = ((PsiMethod)baseConstructor.getNavigationElement()).getDocComment();
191 if(docComment != null) {
192 constructor.addAfter(docComment, null);
197 @NonNls StringBuffer buffer = new StringBuffer();
198 buffer.append("{\n");
200 if (baseConstructor != null){
201 PsiClass superClass = aClass.getSuperClass();
202 LOG.assertTrue(superClass != null);
203 if (!CommonClassNames.JAVA_LANG_ENUM.equals(superClass.getQualifiedName())) {
204 if (baseConstructor instanceof PsiCompiledElement){ // to get some parameter names
205 PsiClass dummyClass = factory.createClass("Dummy");
206 baseConstructor = (PsiMethod)dummyClass.add(baseConstructor);
208 PsiParameter[] parms = baseConstructor.getParameterList().getParameters();
209 for (PsiParameter parm : parms) {
210 constructor.getParameterList().add(parm);
212 if (parms.length > 0){
213 buffer.append("super(");
214 for(int j = 0; j < parms.length; j++) {
215 PsiParameter parm = parms[j];
216 if (j > 0){
217 buffer.append(",");
219 buffer.append(parm.getName());
221 buffer.append(");\n");
226 JavaCodeStyleManager javaStyle = JavaCodeStyleManager.getInstance(aClass.getProject());
228 for (PsiField field : fields) {
229 String fieldName = field.getName();
230 String name = javaStyle.variableNameToPropertyName(fieldName, VariableKind.FIELD);
231 String parmName = javaStyle.propertyNameToVariableName(name, VariableKind.PARAMETER);
232 PsiParameter parm = factory.createParameter(parmName, field.getType());
235 if (AnnotationUtil.isAnnotated(field, AnnotationUtil.NOT_NULL, false)) {
236 final PsiAnnotation annotation = factory.createAnnotationFromText("@" + AnnotationUtil.NOT_NULL, field);
237 parm.getModifierList().addAfter(annotation, null);
240 constructor.getParameterList().add(parm);
241 if (fieldName.equals(parmName)) {
242 buffer.append("this.");
244 buffer.append(fieldName);
245 buffer.append("=");
246 buffer.append(parmName);
247 buffer.append(";\n");
250 buffer.append("}");
251 PsiCodeBlock body = factory.createCodeBlockFromText(buffer.toString(), null);
252 constructor.getBody().replace(body);
253 constructor = (PsiMethod)codeStyleManager.reformat(constructor);
254 return constructor;
257 @Modifier
258 @Nullable
259 private static String getConstructorModifier(final PsiClass aClass) {
260 @Modifier String modifier = PsiModifier.PUBLIC;
262 if (aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
263 modifier = PsiModifier.PROTECTED;
265 else if (aClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
266 modifier = PsiModifier.PACKAGE_LOCAL;
268 else if (aClass.hasModifierProperty(PsiModifier.PRIVATE)) {
269 modifier = PsiModifier.PRIVATE;
272 return modifier;
275 protected GenerationInfo[] generateMemberPrototypes(PsiClass aClass, ClassMember originalMember) {
276 LOG.assertTrue(false);
277 return null;