2 * Copyright 2003-2008 Dave Griffith, Bas Leijdekkers
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.
18 import com
.intellij
.codeInspection
.LocalQuickFix
;
19 import com
.intellij
.codeInspection
.ProblemDescriptor
;
20 import com
.intellij
.lang
.StdLanguages
;
21 import com
.intellij
.lang
.Language
;
22 import com
.intellij
.lang
.jsp
.JspxFileViewProvider
;
23 import com
.intellij
.openapi
.diagnostic
.Logger
;
24 import com
.intellij
.openapi
.editor
.Document
;
25 import com
.intellij
.openapi
.project
.Project
;
26 import com
.intellij
.openapi
.util
.TextRange
;
27 import com
.intellij
.openapi
.vfs
.ReadonlyStatusHandler
;
28 import com
.intellij
.openapi
.vfs
.VirtualFile
;
29 import com
.intellij
.psi
.*;
30 import com
.intellij
.psi
.codeStyle
.CodeStyleManager
;
31 import com
.intellij
.psi
.codeStyle
.JavaCodeStyleManager
;
32 import com
.intellij
.psi
.jsp
.JspFile
;
33 import com
.intellij
.psi
.util
.PsiUtil
;
34 import com
.intellij
.util
.IncorrectOperationException
;
35 import org
.jetbrains
.annotations
.NonNls
;
36 import org
.jetbrains
.annotations
.NotNull
;
37 import org
.jetbrains
.annotations
.Nullable
;
39 public abstract class InspectionGadgetsFix
implements LocalQuickFix
{
41 public static final InspectionGadgetsFix
[] EMPTY_ARRAY
= {};
42 private static final Logger LOG
=
43 Logger
.getInstance("#com.siyeh.ig.InspectionGadgetsFix");
45 private boolean myOnTheFly
= false;
48 * To appear in "Apply Fix" statement when multiple Quick Fixes exist
51 public String
getFamilyName() {
55 public final void applyFix(@NotNull Project project
,
56 @NotNull ProblemDescriptor descriptor
){
57 final PsiElement problemElement
= descriptor
.getPsiElement();
58 if(problemElement
== null || !problemElement
.isValid()){
61 if(isQuickFixOnReadOnlyFile(problemElement
)){
65 doFix(project
, descriptor
);
66 } catch(IncorrectOperationException e
){
67 final Class
<?
extends InspectionGadgetsFix
> aClass
= getClass();
68 final String className
= aClass
.getName();
69 final Logger logger
= Logger
.getInstance(className
);
74 protected abstract void doFix(Project project
, ProblemDescriptor descriptor
)
75 throws IncorrectOperationException
;
77 protected static void deleteElement(@NotNull PsiElement element
)
78 throws IncorrectOperationException
{
82 protected static void replaceExpression(
83 @NotNull PsiExpression expression
,
84 @NotNull @NonNls String newExpressionText
)
85 throws IncorrectOperationException
{
86 final Project project
= expression
.getProject();
87 final JavaPsiFacade psiFacade
= JavaPsiFacade
.getInstance(project
);
88 final PsiElementFactory factory
= psiFacade
.getElementFactory();
89 final PsiExpression newExpression
=
90 factory
.createExpressionFromText(newExpressionText
, expression
);
91 final PsiElement replacementExpression
=
92 expression
.replace(newExpression
);
93 final CodeStyleManager styleManager
=
94 CodeStyleManager
.getInstance(project
);
95 styleManager
.reformat(replacementExpression
);
98 protected static void replaceExpressionWithReferenceTo(
99 @NotNull PsiExpression expression
,
100 @NotNull PsiMember target
)
101 throws IncorrectOperationException
{
102 final Project project
= expression
.getProject();
103 final JavaPsiFacade psiFacade
= JavaPsiFacade
.getInstance(project
);
104 final PsiElementFactory factory
= psiFacade
.getElementFactory();
105 final PsiReferenceExpression newExpression
= (PsiReferenceExpression
)
106 factory
.createExpressionFromText("xxx", expression
);
107 final PsiReferenceExpression replacementExpression
=
108 (PsiReferenceExpression
)expression
.replace(newExpression
);
109 final PsiElement element
= replacementExpression
.bindToElement(target
);
110 final JavaCodeStyleManager styleManager
=
111 JavaCodeStyleManager
.getInstance(project
);
112 styleManager
.shortenClassReferences(element
);
115 protected static void replaceExpressionAndShorten(
116 @NotNull PsiExpression expression
,
117 @NotNull @NonNls String newExpressionText
)
118 throws IncorrectOperationException
{
119 final Project project
= expression
.getProject();
120 final JavaPsiFacade psiFacade
= JavaPsiFacade
.getInstance(project
);
121 final PsiElementFactory factory
= psiFacade
.getElementFactory();
122 final PsiExpression newExpression
=
123 factory
.createExpressionFromText(newExpressionText
, expression
);
124 final PsiElement replacementExp
= expression
.replace(newExpression
);
125 final JavaCodeStyleManager javaCodeStyleManager
=
126 JavaCodeStyleManager
.getInstance(project
);
127 javaCodeStyleManager
.shortenClassReferences(replacementExp
);
128 final CodeStyleManager styleManager
=
129 CodeStyleManager
.getInstance(project
);
130 styleManager
.reformat(replacementExp
);
133 protected static void replaceStatement(
134 @NotNull PsiStatement statement
,
135 @NotNull @NonNls String newStatementText
)
136 throws IncorrectOperationException
{
137 final Project project
= statement
.getProject();
138 final JavaPsiFacade psiFacade
= JavaPsiFacade
.getInstance(project
);
139 final PsiElementFactory factory
= psiFacade
.getElementFactory();
140 final PsiStatement newStatement
=
141 factory
.createStatementFromText(newStatementText
, statement
);
142 final PsiElement replacementExp
= statement
.replace(newStatement
);
143 final CodeStyleManager styleManager
=
144 CodeStyleManager
.getInstance(project
);
145 styleManager
.reformat(replacementExp
);
148 protected static void replaceStatementAndShortenClassNames(
149 @NotNull PsiStatement statement
,
150 @NotNull @NonNls String newStatementText
)
151 throws IncorrectOperationException
{
152 final Project project
= statement
.getProject();
153 final CodeStyleManager styleManager
=
154 CodeStyleManager
.getInstance(project
);
155 final JavaCodeStyleManager javaStyleManager
=
156 JavaCodeStyleManager
.getInstance(project
);
157 if (PsiUtil
.isInJspFile(statement
)) {
158 final PsiDocumentManager documentManager
=
159 PsiDocumentManager
.getInstance(project
);
160 final JspFile file
= PsiUtil
.getJspFile(statement
);
161 final Document document
= documentManager
.getDocument(file
);
162 if (document
== null) {
165 documentManager
.doPostponedOperationsAndUnblockDocument(document
);
166 final TextRange textRange
= statement
.getTextRange();
167 document
.replaceString(textRange
.getStartOffset(),
168 textRange
.getEndOffset(), newStatementText
);
169 documentManager
.commitDocument(document
);
170 final JspxFileViewProvider viewProvider
= file
.getViewProvider();
171 PsiElement elementAt
=
172 viewProvider
.findElementAt(textRange
.getStartOffset(),
174 if (elementAt
== null) {
177 final int endOffset
= textRange
.getStartOffset() +
178 newStatementText
.length();
179 while(elementAt
.getTextRange().getEndOffset() < endOffset
||
180 !(elementAt
instanceof PsiStatement
)) {
181 elementAt
= elementAt
.getParent();
182 if (elementAt
== null) {
183 LOG
.error("Cannot decode statement");
187 final PsiStatement newStatement
= (PsiStatement
) elementAt
;
188 javaStyleManager
.shortenClassReferences(newStatement
);
189 final TextRange newTextRange
= newStatement
.getTextRange();
190 final Language baseLanguage
= viewProvider
.getBaseLanguage();
191 final PsiFile element
= viewProvider
.getPsi(baseLanguage
);
192 if (element
!= null) {
193 styleManager
.reformatRange(element
,
194 newTextRange
.getStartOffset(),
195 newTextRange
.getEndOffset());
198 final JavaPsiFacade facade
= JavaPsiFacade
.getInstance(project
);
199 final PsiElementFactory factory
= facade
.getElementFactory();
200 PsiStatement newStatement
= factory
.createStatementFromText(
201 newStatementText
, statement
);
202 newStatement
= (PsiStatement
) statement
.replace(newStatement
);
203 javaStyleManager
.shortenClassReferences(newStatement
);
204 styleManager
.reformat(newStatement
);
208 protected static boolean isQuickFixOnReadOnlyFile(PsiElement problemElement
) {
209 final PsiFile containingPsiFile
= problemElement
.getContainingFile();
210 if (containingPsiFile
== null) {
213 final VirtualFile virtualFile
= containingPsiFile
.getVirtualFile();
214 final Project project
= problemElement
.getProject();
215 final ReadonlyStatusHandler handler
=
216 ReadonlyStatusHandler
.getInstance(project
);
217 final ReadonlyStatusHandler
.OperationStatus status
=
218 handler
.ensureFilesWritable(virtualFile
);
219 return status
.hasReadonlyFiles();
222 protected static String
getElementText(@NotNull PsiElement element
,
223 @Nullable PsiElement elementToReplace
,
224 @Nullable String replacement
) {
225 final StringBuilder out
= new StringBuilder();
226 getElementText(element
, elementToReplace
, replacement
, out
);
227 return out
.toString();
230 private static void getElementText(
231 @NotNull PsiElement element
,
232 @Nullable PsiElement elementToReplace
,
233 @Nullable String replacement
,
234 @NotNull StringBuilder out
) {
235 if (element
.equals(elementToReplace
)) {
236 out
.append(replacement
);
239 final PsiElement
[] children
= element
.getChildren();
240 if (children
.length
== 0) {
241 out
.append(element
.getText());
244 for (PsiElement child
: children
) {
245 getElementText(child
, elementToReplace
, replacement
, out
);
249 public final void setOnTheFly(boolean onTheFly
) {
250 myOnTheFly
= onTheFly
;
253 public final boolean isOnTheFly() {