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
.codeInspection
.unneededThrows
;
18 import com
.intellij
.codeInsight
.ExceptionUtil
;
19 import com
.intellij
.codeInsight
.daemon
.GroupNames
;
20 import com
.intellij
.codeInsight
.daemon
.JavaErrorMessages
;
21 import com
.intellij
.codeInsight
.daemon
.impl
.analysis
.HighlightMethodUtil
;
22 import com
.intellij
.codeInsight
.daemon
.impl
.analysis
.HighlightUtil
;
23 import com
.intellij
.codeInspection
.*;
24 import com
.intellij
.psi
.*;
25 import org
.jetbrains
.annotations
.NonNls
;
26 import org
.jetbrains
.annotations
.NotNull
;
27 import org
.jetbrains
.annotations
.Nullable
;
29 import java
.util
.Collection
;
30 import java
.util
.HashSet
;
37 public class RedundantThrowsDeclaration
extends BaseJavaLocalInspectionTool
{
39 public String
getGroupDisplayName() {
40 return GroupNames
.DECLARATION_REDUNDANCY
;
44 public String
getDisplayName() {
45 return InspectionsBundle
.message("redundant.throws.declaration");
50 public String
getShortName() {
51 return "RedundantThrowsDeclaration";
55 public ProblemDescriptor
[] checkFile(@NotNull PsiFile file
, @NotNull final InspectionManager manager
, boolean isOnTheFly
) {
56 final Set
<ProblemDescriptor
> problems
= new HashSet
<ProblemDescriptor
>();
57 file
.accept(new JavaRecursiveElementWalkingVisitor() {
58 @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference
) {
59 final ProblemDescriptor descriptor
= checkExceptionsNeverThrown(reference
, manager
);
60 if (descriptor
!= null) {
61 problems
.add(descriptor
);
66 return problems
.isEmpty() ?
null : problems
.toArray(new ProblemDescriptor
[problems
.size()]);
72 private static ProblemDescriptor
checkExceptionsNeverThrown(PsiJavaCodeReferenceElement referenceElement
, InspectionManager inspectionManager
) {
73 if (!(referenceElement
.getParent() instanceof PsiReferenceList
)) return null;
74 PsiReferenceList referenceList
= (PsiReferenceList
)referenceElement
.getParent();
75 if (!(referenceList
.getParent() instanceof PsiMethod
)) return null;
76 PsiMethod method
= (PsiMethod
)referenceList
.getParent();
77 if (referenceList
!= method
.getThrowsList()) return null;
78 PsiClass containingClass
= method
.getContainingClass();
79 if (containingClass
== null) return null;
81 PsiManager manager
= referenceElement
.getManager();
82 PsiClassType exceptionType
= JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory().createType(referenceElement
);
83 if (ExceptionUtil
.isUncheckedExceptionOrSuperclass(exceptionType
)) return null;
85 PsiCodeBlock body
= method
.getBody();
86 if (body
== null) return null;
88 PsiModifierList modifierList
= method
.getModifierList();
89 if (!modifierList
.hasModifierProperty(PsiModifier
.PRIVATE
)
90 && !modifierList
.hasModifierProperty(PsiModifier
.STATIC
)
91 && !modifierList
.hasModifierProperty(PsiModifier
.FINAL
)
92 && !method
.isConstructor()
93 && !(containingClass
instanceof PsiAnonymousClass
)
94 && !containingClass
.hasModifierProperty(PsiModifier
.FINAL
)) {
98 Collection
<PsiClassType
> types
= ExceptionUtil
.collectUnhandledExceptions(body
, method
);
99 Collection
<PsiClassType
> unhandled
= new HashSet
<PsiClassType
>(types
);
100 if (method
.isConstructor()) {
101 // there may be field initializer throwing exception
102 // that exception must be caught in the constructor
103 PsiField
[] fields
= containingClass
.getFields();
104 for (final PsiField field
: fields
) {
105 if (field
.hasModifierProperty(PsiModifier
.STATIC
)) continue;
106 PsiExpression initializer
= field
.getInitializer();
107 if (initializer
== null) continue;
108 unhandled
.addAll(ExceptionUtil
.collectUnhandledExceptions(initializer
, field
));
112 for (PsiClassType unhandledException
: unhandled
) {
113 if (unhandledException
.isAssignableFrom(exceptionType
) ||
114 exceptionType
.isAssignableFrom(unhandledException
)) {
119 if (HighlightMethodUtil
.isSerializationRelatedMethod(method
, containingClass
)) return null;
121 String description
= JavaErrorMessages
.message("exception.is.never.thrown", HighlightUtil
.formatType(exceptionType
));
123 final LocalQuickFix quickFixes
= new DeleteThrowsFix(method
, exceptionType
);
124 return inspectionManager
.createProblemDescriptor(referenceElement
, description
, quickFixes
, ProblemHighlightType
.LIKE_UNUSED_SYMBOL
);