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
.util
.IncorrectOperationException
;
34 import org
.jetbrains
.annotations
.NonNls
;
35 import org
.jetbrains
.annotations
.NotNull
;
36 import org
.jetbrains
.annotations
.Nullable
;
38 public abstract class InspectionGadgetsFix
implements LocalQuickFix
{
40 public static final InspectionGadgetsFix
[] EMPTY_ARRAY
= {};
41 private static final Logger LOG
=
42 Logger
.getInstance("#com.siyeh.ig.InspectionGadgetsFix");
44 private boolean myOnTheFly
= false;
47 * To appear in "Apply Fix" statement when multiple Quick Fixes exist
50 public String
getFamilyName() {
54 public final void applyFix(@NotNull Project project
,
55 @NotNull ProblemDescriptor descriptor
){
56 final PsiElement problemElement
= descriptor
.getPsiElement();
57 if(problemElement
== null || !problemElement
.isValid()){
60 if(isQuickFixOnReadOnlyFile(problemElement
)){
64 doFix(project
, descriptor
);
65 } catch(IncorrectOperationException e
){
66 final Class
<?
extends InspectionGadgetsFix
> aClass
= getClass();
67 final String className
= aClass
.getName();
68 final Logger logger
= Logger
.getInstance(className
);
73 protected abstract void doFix(Project project
, ProblemDescriptor descriptor
)
74 throws IncorrectOperationException
;
76 protected static void deleteElement(@NotNull PsiElement element
)
77 throws IncorrectOperationException
{
81 protected static void replaceExpression(
82 @NotNull PsiExpression expression
,
83 @NotNull @NonNls String newExpressionText
)
84 throws IncorrectOperationException
{
85 final Project project
= expression
.getProject();
86 final JavaPsiFacade psiFacade
= JavaPsiFacade
.getInstance(project
);
87 final PsiElementFactory factory
= psiFacade
.getElementFactory();
88 final PsiExpression newExpression
=
89 factory
.createExpressionFromText(newExpressionText
, expression
);
90 final PsiElement replacementExpression
=
91 expression
.replace(newExpression
);
92 final CodeStyleManager styleManager
=
93 CodeStyleManager
.getInstance(project
);
94 styleManager
.reformat(replacementExpression
);
97 protected static void replaceExpressionWithReferenceTo(
98 @NotNull PsiExpression expression
,
99 @NotNull PsiMember target
)
100 throws IncorrectOperationException
{
101 final Project project
= expression
.getProject();
102 final JavaPsiFacade psiFacade
= JavaPsiFacade
.getInstance(project
);
103 final PsiElementFactory factory
= psiFacade
.getElementFactory();
104 final PsiReferenceExpression newExpression
= (PsiReferenceExpression
)
105 factory
.createExpressionFromText("xxx", expression
);
106 final PsiReferenceExpression replacementExpression
=
107 (PsiReferenceExpression
)expression
.replace(newExpression
);
108 final PsiElement element
= replacementExpression
.bindToElement(target
);
109 final JavaCodeStyleManager styleManager
=
110 JavaCodeStyleManager
.getInstance(project
);
111 styleManager
.shortenClassReferences(element
);
114 protected static void replaceExpressionAndShorten(
115 @NotNull PsiExpression expression
,
116 @NotNull @NonNls String newExpressionText
)
117 throws IncorrectOperationException
{
118 final Project project
= expression
.getProject();
119 final JavaPsiFacade psiFacade
= JavaPsiFacade
.getInstance(project
);
120 final PsiElementFactory factory
= psiFacade
.getElementFactory();
121 final PsiExpression newExpression
=
122 factory
.createExpressionFromText(newExpressionText
, expression
);
123 final PsiElement replacementExp
= expression
.replace(newExpression
);
124 final JavaCodeStyleManager javaCodeStyleManager
=
125 JavaCodeStyleManager
.getInstance(project
);
126 javaCodeStyleManager
.shortenClassReferences(replacementExp
);
127 final CodeStyleManager styleManager
=
128 CodeStyleManager
.getInstance(project
);
129 styleManager
.reformat(replacementExp
);
132 protected static void replaceStatement(
133 @NotNull PsiStatement statement
,
134 @NotNull @NonNls String newStatementText
)
135 throws IncorrectOperationException
{
136 final Project project
= statement
.getProject();
137 final JavaPsiFacade psiFacade
= JavaPsiFacade
.getInstance(project
);
138 final PsiElementFactory factory
= psiFacade
.getElementFactory();
139 final PsiStatement newStatement
=
140 factory
.createStatementFromText(newStatementText
, statement
);
141 final PsiElement replacementExp
= statement
.replace(newStatement
);
142 final CodeStyleManager styleManager
=
143 CodeStyleManager
.getInstance(project
);
144 styleManager
.reformat(replacementExp
);
147 protected static void replaceStatementAndShortenClassNames(
148 @NotNull PsiStatement statement
,
149 @NotNull @NonNls String newStatementText
)
150 throws IncorrectOperationException
{
151 final Project project
= statement
.getProject();
152 final CodeStyleManager styleManager
=
153 CodeStyleManager
.getInstance(project
);
154 final JavaCodeStyleManager javaStyleManager
=
155 JavaCodeStyleManager
.getInstance(project
);
156 if (JspPsiUtil
.isInJspFile(statement
)) {
157 final PsiDocumentManager documentManager
=
158 PsiDocumentManager
.getInstance(project
);
159 final JspFile file
= JspPsiUtil
.getJspFile(statement
);
160 final Document document
= documentManager
.getDocument(file
);
161 if (document
== null) {
164 documentManager
.doPostponedOperationsAndUnblockDocument(document
);
165 final TextRange textRange
= statement
.getTextRange();
166 document
.replaceString(textRange
.getStartOffset(),
167 textRange
.getEndOffset(), newStatementText
);
168 documentManager
.commitDocument(document
);
169 final JspxFileViewProvider viewProvider
= file
.getViewProvider();
170 PsiElement elementAt
=
171 viewProvider
.findElementAt(textRange
.getStartOffset(),
173 if (elementAt
== null) {
176 final int endOffset
= textRange
.getStartOffset() +
177 newStatementText
.length();
178 while(elementAt
.getTextRange().getEndOffset() < endOffset
||
179 !(elementAt
instanceof PsiStatement
)) {
180 elementAt
= elementAt
.getParent();
181 if (elementAt
== null) {
182 LOG
.error("Cannot decode statement");
186 final PsiStatement newStatement
= (PsiStatement
) elementAt
;
187 javaStyleManager
.shortenClassReferences(newStatement
);
188 final TextRange newTextRange
= newStatement
.getTextRange();
189 final Language baseLanguage
= viewProvider
.getBaseLanguage();
190 final PsiFile element
= viewProvider
.getPsi(baseLanguage
);
191 if (element
!= null) {
192 styleManager
.reformatRange(element
,
193 newTextRange
.getStartOffset(),
194 newTextRange
.getEndOffset());
197 final JavaPsiFacade facade
= JavaPsiFacade
.getInstance(project
);
198 final PsiElementFactory factory
= facade
.getElementFactory();
199 PsiStatement newStatement
= factory
.createStatementFromText(
200 newStatementText
, statement
);
201 newStatement
= (PsiStatement
) statement
.replace(newStatement
);
202 javaStyleManager
.shortenClassReferences(newStatement
);
203 styleManager
.reformat(newStatement
);
207 protected static boolean isQuickFixOnReadOnlyFile(PsiElement problemElement
) {
208 final PsiFile containingPsiFile
= problemElement
.getContainingFile();
209 if (containingPsiFile
== null) {
212 final VirtualFile virtualFile
= containingPsiFile
.getVirtualFile();
213 final Project project
= problemElement
.getProject();
214 final ReadonlyStatusHandler handler
=
215 ReadonlyStatusHandler
.getInstance(project
);
216 final ReadonlyStatusHandler
.OperationStatus status
=
217 handler
.ensureFilesWritable(virtualFile
);
218 return status
.hasReadonlyFiles();
221 protected static String
getElementText(@NotNull PsiElement element
,
222 @Nullable PsiElement elementToReplace
,
223 @Nullable String replacement
) {
224 final StringBuilder out
= new StringBuilder();
225 getElementText(element
, elementToReplace
, replacement
, out
);
226 return out
.toString();
229 private static void getElementText(
230 @NotNull PsiElement element
,
231 @Nullable PsiElement elementToReplace
,
232 @Nullable String replacement
,
233 @NotNull StringBuilder out
) {
234 if (element
.equals(elementToReplace
)) {
235 out
.append(replacement
);
238 final PsiElement
[] children
= element
.getChildren();
239 if (children
.length
== 0) {
240 out
.append(element
.getText());
243 for (PsiElement child
: children
) {
244 getElementText(child
, elementToReplace
, replacement
, out
);
248 public final void setOnTheFly(boolean onTheFly
) {
249 myOnTheFly
= onTheFly
;
252 public final boolean isOnTheFly() {