2 * Copyright 2007-2008 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.
16 package com
.siyeh
.ig
.errorhandling
;
18 import com
.intellij
.codeInspection
.ProblemDescriptor
;
19 import com
.intellij
.openapi
.project
.Project
;
20 import com
.intellij
.psi
.*;
21 import com
.intellij
.psi
.search
.searches
.ReferencesSearch
;
22 import com
.intellij
.psi
.util
.PsiTreeUtil
;
23 import com
.intellij
.util
.IncorrectOperationException
;
24 import com
.intellij
.util
.Query
;
25 import com
.siyeh
.InspectionGadgetsBundle
;
26 import com
.siyeh
.ig
.BaseInspection
;
27 import com
.siyeh
.ig
.BaseInspectionVisitor
;
28 import com
.siyeh
.ig
.InspectionGadgetsFix
;
29 import com
.siyeh
.ig
.psiutils
.VariableSearchUtils
;
30 import org
.jetbrains
.annotations
.Nls
;
31 import org
.jetbrains
.annotations
.NotNull
;
32 import org
.jetbrains
.annotations
.Nullable
;
34 public class CaughtExceptionImmediatelyRethrownInspection
35 extends BaseInspection
{
40 public String
getDisplayName() {
41 return InspectionGadgetsBundle
.message(
42 "caught.exception.immediately.rethrown.display.name");
47 protected String
buildErrorString(Object
... infos
) {
48 return InspectionGadgetsBundle
.message(
49 "caught.exception.immediately.rethrown.problem.descriptor");
53 public boolean isEnabledByDefault() {
59 protected InspectionGadgetsFix
buildFix(Object
... infos
) {
60 final PsiTryStatement tryStatement
= (PsiTryStatement
) infos
[0];
61 final boolean removeTryCatch
=
62 tryStatement
.getCatchSections().length
== 1 &&
63 tryStatement
.getFinallyBlock() == null;
64 return new DeleteCatchSectionFix(removeTryCatch
);
67 private static class DeleteCatchSectionFix
extends InspectionGadgetsFix
{
69 private final boolean removeTryCatch
;
71 DeleteCatchSectionFix(boolean removeTryCatch
) {
72 this.removeTryCatch
= removeTryCatch
;
76 public String
getName() {
78 return InspectionGadgetsBundle
.message(
79 "remove.try.catch.quickfix");
81 return InspectionGadgetsBundle
.message(
82 "delete.catch.section.quickfix");
87 protected void doFix(Project project
, ProblemDescriptor descriptor
)
88 throws IncorrectOperationException
{
89 final PsiElement element
= descriptor
.getPsiElement();
90 final PsiElement parent
= element
.getParent();
91 if (!(parent
instanceof PsiParameter
)) {
94 final PsiParameter parameter
= (PsiParameter
)parent
;
95 final PsiElement grandParent
= parameter
.getParent();
96 if (!(grandParent
instanceof PsiCatchSection
)) {
99 final PsiCatchSection catchSection
= (PsiCatchSection
)grandParent
;
100 final PsiTryStatement tryStatement
= catchSection
.getTryStatement();
101 final boolean removeTryCatch
=
102 tryStatement
.getCatchSections().length
== 1 &&
103 tryStatement
.getFinallyBlock() == null;
104 if (removeTryCatch
) {
105 final PsiCodeBlock codeBlock
= tryStatement
.getTryBlock();
106 if (codeBlock
== null) {
109 final PsiStatement
[] statements
= codeBlock
.getStatements();
110 if (statements
.length
== 0) {
111 tryStatement
.delete();
113 final PsiElement containingElement
= tryStatement
.getParent();
114 final boolean keepBlock
;
115 if (containingElement
instanceof PsiCodeBlock
) {
116 final PsiCodeBlock parentBlock
=
117 (PsiCodeBlock
)containingElement
;
119 VariableSearchUtils
.containsConflictingDeclarations(
120 codeBlock
, parentBlock
);
125 final JavaPsiFacade psiFacade
=
126 JavaPsiFacade
.getInstance(project
);
127 final PsiElementFactory factory
=
128 psiFacade
.getElementFactory();
129 final PsiBlockStatement resultStatement
= (PsiBlockStatement
)
130 factory
.createStatementFromText("{}", element
);
131 final PsiCodeBlock resultBlock
=
132 resultStatement
.getCodeBlock();
133 for (PsiStatement statement
: statements
) {
134 resultBlock
.add(statement
);
136 tryStatement
.replace(resultStatement
);
138 for (PsiStatement statement
: statements
) {
139 containingElement
.addBefore(statement
, tryStatement
);
141 tryStatement
.delete();
144 catchSection
.delete();
150 public BaseInspectionVisitor
buildVisitor() {
151 return new CaughtExceptionImmediatelyRethrownVisitor();
154 private static class CaughtExceptionImmediatelyRethrownVisitor
155 extends BaseInspectionVisitor
{
158 public void visitThrowStatement(PsiThrowStatement statement
) {
159 super.visitThrowStatement(statement
);
160 final PsiExpression expression
= statement
.getException();
161 if (!(expression
instanceof PsiReferenceExpression
)) {
164 final PsiStatement previousStatement
=
165 PsiTreeUtil
.getPrevSiblingOfType(statement
,
167 if (previousStatement
!= null) {
170 final PsiElement parent
= statement
.getParent();
171 if (parent
instanceof PsiStatement
) {
172 // e.g. if (notsure) throw e;
175 final PsiReferenceExpression referenceExpression
=
176 (PsiReferenceExpression
)expression
;
177 final PsiElement target
= referenceExpression
.resolve();
178 if (!(target
instanceof PsiParameter
)) {
181 final PsiParameter parameter
= (PsiParameter
)target
;
182 final PsiElement declarationScope
= parameter
.getDeclarationScope();
183 if (!(declarationScope
instanceof PsiCatchSection
)) {
186 final PsiCatchSection catchSection
=
187 (PsiCatchSection
)declarationScope
;
188 final PsiCodeBlock block
=
189 PsiTreeUtil
.getParentOfType(statement
, PsiCodeBlock
.class);
193 final PsiElement blockParent
= block
.getParent();
194 if (blockParent
!= catchSection
) {
195 // e.g. if (notsure) { throw e; }
198 if (isSuperClassExceptionCaughtLater(parameter
, catchSection
)) {
201 final Query
<PsiReference
> query
=
202 ReferencesSearch
.search(parameter
);
203 for (PsiReference reference
: query
) {
204 final PsiElement element
= reference
.getElement();
205 if (element
!= expression
) {
209 final PsiTryStatement tryStatement
= catchSection
.getTryStatement();
210 registerVariableError(parameter
, tryStatement
);
213 private static boolean isSuperClassExceptionCaughtLater(
214 PsiVariable parameter
, PsiCatchSection catchSection
) {
215 final PsiTryStatement tryStatement
= catchSection
.getTryStatement();
216 final PsiCatchSection
[] catchSections
=
217 tryStatement
.getCatchSections();
219 while (catchSections
[index
] != catchSection
&&
220 index
< catchSections
.length
) {
223 final PsiType type
= parameter
.getType();
224 if (!(type
instanceof PsiClassType
)) {
227 final PsiClassType classType
= (PsiClassType
)type
;
228 final PsiClass parameterClass
= classType
.resolve();
229 if (parameterClass
== null) {
232 for (int i
= index
; i
< catchSections
.length
; i
++){
233 final PsiCatchSection nextCatchSection
= catchSections
[i
];
234 final PsiParameter nextParameter
=
235 nextCatchSection
.getParameter();
236 if (nextParameter
== null) {
239 final PsiType nextType
= nextParameter
.getType();
240 if (!(nextType
instanceof PsiClassType
)) {
243 final PsiClassType nextClassType
= (PsiClassType
)nextType
;
244 final PsiClass aClass
= nextClassType
.resolve();
245 if (aClass
== null) {
248 if (parameterClass
.isInheritor(aClass
, true)) {