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
.intention
.impl
;
18 import com
.intellij
.codeInsight
.CodeInsightBundle
;
19 import com
.intellij
.codeInsight
.CodeInsightUtilBase
;
20 import com
.intellij
.codeInsight
.daemon
.impl
.analysis
.HighlightControlFlowUtil
;
21 import com
.intellij
.codeInsight
.daemon
.impl
.analysis
.HighlightUtil
;
22 import com
.intellij
.codeInsight
.daemon
.impl
.quickfix
.CreateFromUsageUtils
;
23 import com
.intellij
.codeInsight
.intention
.IntentionAction
;
24 import com
.intellij
.codeInsight
.intention
.PsiElementBaseIntentionAction
;
25 import com
.intellij
.codeInsight
.intention
.QuickFixFactory
;
26 import com
.intellij
.openapi
.editor
.Editor
;
27 import com
.intellij
.openapi
.editor
.ScrollType
;
28 import com
.intellij
.openapi
.project
.Project
;
29 import com
.intellij
.openapi
.util
.Ref
;
30 import com
.intellij
.psi
.*;
31 import com
.intellij
.psi
.impl
.source
.jsp
.jspJava
.JspClass
;
32 import com
.intellij
.psi
.javadoc
.PsiDocComment
;
33 import com
.intellij
.psi
.util
.PsiTreeUtil
;
34 import com
.intellij
.util
.IncorrectOperationException
;
35 import org
.jetbrains
.annotations
.NotNull
;
36 import org
.jetbrains
.annotations
.Nullable
;
43 public class MoveInitializerToConstructorAction
extends PsiElementBaseIntentionAction
{
45 public String
getFamilyName() {
50 public String
getText() {
51 return CodeInsightBundle
.message("intention.move.initializer.to.constructor");
54 public boolean isAvailable(@NotNull Project project
, Editor editor
, @Nullable PsiElement element
) {
55 if (element
== null) return false;
56 if (element
instanceof PsiCompiledElement
) return false;
57 final PsiField field
= PsiTreeUtil
.getParentOfType(element
, PsiField
.class, false, PsiMember
.class, PsiCodeBlock
.class, PsiDocComment
.class);
58 if (field
== null || field
.hasModifierProperty(PsiModifier
.STATIC
)) return false;
59 if (!field
.hasInitializer()) return false;
60 PsiClass psiClass
= field
.getContainingClass();
62 return psiClass
!= null && !psiClass
.isInterface() && !(psiClass
instanceof PsiAnonymousClass
) && !(psiClass
instanceof JspClass
);
65 public void invoke(@NotNull Project project
, Editor editor
, PsiFile file
) throws IncorrectOperationException
{
66 if (!CodeInsightUtilBase
.prepareFileForWrite(file
)) return;
68 int offset
= editor
.getCaretModel().getOffset();
70 PsiElement element
= file
.findElementAt(offset
);
71 final PsiField field
= PsiTreeUtil
.getParentOfType(element
, PsiField
.class);
74 PsiClass aClass
= field
.getContainingClass();
75 PsiMethod
[] constructors
= aClass
.getConstructors();
76 Collection
<PsiMethod
> constructorsToAddInitialization
;
77 if (constructors
.length
== 0) {
78 IntentionAction addDefaultConstructorFix
= QuickFixFactory
.getInstance().createAddDefaultConstructorFix(aClass
);
79 addDefaultConstructorFix
.invoke(project
, editor
, file
);
80 constructorsToAddInitialization
= Arrays
.asList(aClass
.getConstructors());
83 constructorsToAddInitialization
= new ArrayList
<PsiMethod
>(Arrays
.asList(constructors
));
84 for (Iterator
<PsiMethod
> iterator
= constructorsToAddInitialization
.iterator(); iterator
.hasNext();) {
85 PsiMethod ctr
= iterator
.next();
86 List
<PsiMethod
> chained
= HighlightControlFlowUtil
.getChainedConstructors(ctr
);
87 if (chained
!= null) {
93 PsiElement toMove
= null;
94 for (PsiMethod constructor
: constructorsToAddInitialization
) {
95 PsiCodeBlock codeBlock
= constructor
.getBody();
96 if (codeBlock
== null) {
97 CreateFromUsageUtils
.setupMethodBody(constructor
);
98 codeBlock
= constructor
.getBody();
100 PsiElement added
= addAssignment(codeBlock
, field
);
101 if (toMove
== null) toMove
= added
;
103 field
.getInitializer().delete();
104 if (toMove
!= null) {
105 editor
.getCaretModel().moveToOffset(toMove
.getTextOffset());
106 editor
.getScrollingModel().scrollToCaret(ScrollType
.MAKE_VISIBLE
);
110 private static PsiElement
addAssignment(@NotNull PsiCodeBlock codeBlock
, @NotNull PsiField field
) throws IncorrectOperationException
{
111 PsiElementFactory factory
= JavaPsiFacade
.getInstance(codeBlock
.getProject()).getElementFactory();
112 PsiExpressionStatement statement
= (PsiExpressionStatement
)factory
.createStatementFromText(field
.getName()+" = y;", codeBlock
);
113 PsiAssignmentExpression expression
= (PsiAssignmentExpression
)statement
.getExpression();
114 PsiExpression initializer
= field
.getInitializer();
115 if (initializer
instanceof PsiArrayInitializerExpression
) {
116 PsiType type
= initializer
.getType();
117 PsiNewExpression newExpression
= (PsiNewExpression
)factory
.createExpressionFromText("new " + type
.getCanonicalText() + "{}", codeBlock
);
118 newExpression
.getArrayInitializer().replace(initializer
);
119 initializer
= newExpression
;
121 expression
.getRExpression().replace(initializer
);
122 PsiStatement
[] statements
= codeBlock
.getStatements();
123 PsiElement anchor
= null;
124 for (PsiStatement blockStatement
: statements
) {
125 if (blockStatement
instanceof PsiExpressionStatement
&&
126 HighlightUtil
.isSuperOrThisMethodCall(((PsiExpressionStatement
)blockStatement
).getExpression())) {
129 if (containsReference(blockStatement
, field
)) {
130 anchor
= blockStatement
;
134 PsiElement newStatement
= codeBlock
.addBefore(statement
,anchor
);
135 replaceWithQualifiedReferences(newStatement
, newStatement
);
139 private static boolean containsReference(final PsiElement element
, final PsiField field
) {
140 final Ref
<Boolean
> result
= new Ref
<Boolean
>(Boolean
.FALSE
);
141 element
.accept(new JavaRecursiveElementWalkingVisitor() {
142 @Override public void visitReferenceExpression(PsiReferenceExpression expression
) {
143 if (expression
.resolve() == field
) {
144 result
.set(Boolean
.TRUE
);
146 super.visitReferenceExpression(expression
);
149 return result
.get().booleanValue();
152 private static void replaceWithQualifiedReferences(final PsiElement expression
, PsiElement root
) throws IncorrectOperationException
{
153 PsiReference reference
= expression
.getReference();
154 if (reference
!= null) {
155 PsiElement resolved
= reference
.resolve();
156 if (resolved
instanceof PsiVariable
&& !(resolved
instanceof PsiField
) && !PsiTreeUtil
.isAncestor(root
, resolved
, false)) {
157 PsiVariable variable
= (PsiVariable
)resolved
;
158 PsiElementFactory factory
= JavaPsiFacade
.getInstance(resolved
.getProject()).getElementFactory();
159 PsiElement qualifiedExpr
= factory
.createExpressionFromText("this." + variable
.getName(), expression
);
160 expression
.replace(qualifiedExpr
);
164 for (PsiElement child
: expression
.getChildren()) {
165 replaceWithQualifiedReferences(child
, root
);