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()]);
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());
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
)) {
94 if (array
.size() > 0){
95 if (array
.size() == 1){
96 baseConstructors
= new PsiMethod
[]{array
.get(0)};
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"));
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
;
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()]);
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
);
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
)));
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
);
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
];
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
);
246 buffer
.append(parmName
);
247 buffer
.append(";\n");
251 PsiCodeBlock body
= factory
.createCodeBlockFromText(buffer
.toString(), null);
252 constructor
.getBody().replace(body
);
253 constructor
= (PsiMethod
)codeStyleManager
.reformat(constructor
);
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
;
275 protected GenerationInfo
[] generateMemberPrototypes(PsiClass aClass
, ClassMember originalMember
) {
276 LOG
.assertTrue(false);