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.
16 package com
.siyeh
.ig
.resources
;
18 import com
.intellij
.psi
.*;
19 import com
.intellij
.psi
.util
.PsiTreeUtil
;
20 import com
.siyeh
.HardcodedMethodConstants
;
21 import com
.siyeh
.InspectionGadgetsBundle
;
22 import com
.siyeh
.ig
.BaseInspection
;
23 import com
.siyeh
.ig
.BaseInspectionVisitor
;
24 import com
.siyeh
.ig
.psiutils
.TypeUtils
;
25 import com
.siyeh
.ig
.psiutils
.VariableAccessUtils
;
26 import org
.jetbrains
.annotations
.NotNull
;
28 public class ChannelResourceInspection
extends BaseInspection
{
31 public String
getID(){
32 return "ChannelOpenedButNotSafelyClosed";
36 public String
getDisplayName(){
37 return InspectionGadgetsBundle
.message(
38 "channel.opened.not.closed.display.name");
42 public String
buildErrorString(Object
... infos
){
43 final PsiExpression expression
= (PsiExpression
) infos
[0];
44 final PsiType type
= expression
.getType();
46 final String text
= type
.getPresentableText();
47 return InspectionGadgetsBundle
.message(
48 "channel.opened.not.closed.problem.descriptor", text
);
51 public BaseInspectionVisitor
buildVisitor(){
52 return new ChannelResourceVisitor();
55 private static class ChannelResourceVisitor
extends BaseInspectionVisitor
{
57 @Override public void visitMethodCallExpression(
58 @NotNull PsiMethodCallExpression expression
){
59 super.visitMethodCallExpression(expression
);
60 if(!isChannelFactoryMethod(expression
)){
63 final PsiElement parent
= expression
.getParent();
64 final PsiVariable boundVariable
;
65 if (parent
instanceof PsiAssignmentExpression
) {
66 final PsiAssignmentExpression assignment
=
67 (PsiAssignmentExpression
) parent
;
68 final PsiExpression lhs
= assignment
.getLExpression();
69 if (!(lhs
instanceof PsiReferenceExpression
)) {
72 final PsiReferenceExpression referenceExpression
=
73 (PsiReferenceExpression
) lhs
;
74 final PsiElement referent
= referenceExpression
.resolve();
75 if (referent
== null || !(referent
instanceof PsiVariable
)) {
78 boundVariable
= (PsiVariable
) referent
;
79 } else if (parent
instanceof PsiVariable
) {
80 boundVariable
= (PsiVariable
) parent
;
84 final PsiStatement statement
=
85 PsiTreeUtil
.getParentOfType(expression
, PsiStatement
.class);
86 if (statement
== null) {
89 PsiStatement nextStatement
=
90 PsiTreeUtil
.getNextSiblingOfType(statement
,
92 while (!(nextStatement
instanceof PsiTryStatement
)) {
93 if (!(nextStatement
instanceof PsiDeclarationStatement
)) {
94 registerError(expression
, expression
);
97 if (boundVariable
!= null) {
98 if (VariableAccessUtils
.variableIsUsed(boundVariable
,
100 registerError(expression
, expression
);
105 PsiTreeUtil
.getNextSiblingOfType(nextStatement
,
108 PsiTryStatement tryStatement
= (PsiTryStatement
) nextStatement
;
109 if (boundVariable
!= null &&
110 resourceIsClosedInFinally(tryStatement
, boundVariable
)) {
113 if (isChannelFactoryClosedInFinally(expression
, tryStatement
)) {
116 registerError(expression
, expression
);
119 private static boolean isChannelFactoryClosedInFinally(
120 PsiMethodCallExpression expression
,
121 PsiTryStatement tryStatement
) {
122 final PsiReferenceExpression methodExpression
=
123 expression
.getMethodExpression();
124 final PsiExpression qualifier
=
125 methodExpression
.getQualifierExpression();
126 if (!(qualifier
instanceof PsiReferenceExpression
)) {
129 PsiReferenceExpression referenceExpression
=
130 (PsiReferenceExpression
) qualifier
;
131 final PsiElement target
= referenceExpression
.resolve();
132 if (!(target
instanceof PsiVariable
)) {
135 PsiVariable variable
= (PsiVariable
) target
;
136 return resourceIsClosedInFinally(tryStatement
, variable
);
139 private static boolean isChannelFactoryMethod(
140 PsiMethodCallExpression expression
){
141 final PsiReferenceExpression methodExpression
=
142 expression
.getMethodExpression();
143 final String methodName
= methodExpression
.getReferenceName();
144 if(!HardcodedMethodConstants
.GET_CHANNEL
.equals(methodName
)) {
147 final PsiExpression qualifier
=
148 methodExpression
.getQualifierExpression();
149 if(qualifier
== null) {
152 return TypeUtils
.expressionHasTypeOrSubtype(qualifier
,
154 "java.net.DatagramSocket",
155 "java.net.ServerSocket",
156 "java.io.FileInputStream",
157 "java.io.FileOutputStream",
158 "java.io.RandomAccessFile",
159 "com.sun.corba.se.pept.transport.EventHandler",
160 "sun.nio.ch.InheritedChannel");
163 private static boolean resourceIsClosedInFinally(
164 @NotNull PsiTryStatement tryStatement
,
165 @NotNull PsiVariable boundVariable
){
166 final PsiCodeBlock finallyBlock
= tryStatement
.getFinallyBlock();
167 if(finallyBlock
== null){
170 final PsiCodeBlock tryBlock
= tryStatement
.getTryBlock();
171 if(tryBlock
== null){
174 final CloseVisitor visitor
= new CloseVisitor(boundVariable
);
175 finallyBlock
.accept(visitor
);
176 return visitor
.containsClose();
180 private static class CloseVisitor
extends JavaRecursiveElementVisitor
{
182 private boolean containsClose
= false;
183 private PsiVariable objectToClose
;
185 private CloseVisitor(PsiVariable objectToClose
){
186 this.objectToClose
= objectToClose
;
189 @Override public void visitElement(@NotNull PsiElement element
){
191 super.visitElement(element
);
195 @Override public void visitMethodCallExpression(
196 @NotNull PsiMethodCallExpression call
){
200 super.visitMethodCallExpression(call
);
201 final PsiReferenceExpression methodExpression
=
202 call
.getMethodExpression();
203 final String methodName
= methodExpression
.getReferenceName();
204 if(!HardcodedMethodConstants
.CLOSE
.equals(methodName
)){
207 final PsiExpression qualifier
=
208 methodExpression
.getQualifierExpression();
209 if(!(qualifier
instanceof PsiReferenceExpression
)){
212 final PsiReferenceExpression referenceExpression
=
213 (PsiReferenceExpression
) qualifier
;
214 final PsiElement referent
= referenceExpression
.resolve();
215 if(objectToClose
.equals(referent
)){
216 containsClose
= true;
220 public boolean containsClose(){
221 return containsClose
;