update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInsight / intention / impl / MoveInitializerToConstructorAction.java
blobe71d52aa19e13f834aadc2a8212e56efa30fdf03
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.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;
38 import java.util.*;
40 /**
41 * @author cdr
43 public class MoveInitializerToConstructorAction extends PsiElementBaseIntentionAction {
44 @NotNull
45 public String getFamilyName() {
46 return getText();
49 @NotNull
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);
73 assert field != null;
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());
82 else {
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) {
88 iterator.remove();
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())) {
127 continue;
129 if (containsReference(blockStatement, field)) {
130 anchor = blockStatement;
131 break;
134 PsiElement newStatement = codeBlock.addBefore(statement,anchor);
135 replaceWithQualifiedReferences(newStatement, newStatement);
136 return 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);
163 else {
164 for (PsiElement child : expression.getChildren()) {
165 replaceWithQualifiedReferences(child, root);