2 * Copyright 2003-2007 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 org
.jetbrains
.annotations
.NotNull
;
27 public class ChannelResourceInspection
extends BaseInspection
{
30 public String
getID(){
31 return "ChannelOpenedButNotSafelyClosed";
35 public String
getDisplayName(){
36 return InspectionGadgetsBundle
.message(
37 "channel.opened.not.closed.display.name");
41 public String
buildErrorString(Object
... infos
){
42 final PsiExpression expression
= (PsiExpression
) infos
[0];
43 final PsiType type
= expression
.getType();
45 final String text
= type
.getPresentableText();
46 return InspectionGadgetsBundle
.message(
47 "channel.opened.not.closed.problem.descriptor", text
);
50 public BaseInspectionVisitor
buildVisitor(){
51 return new ChannelResourceVisitor();
54 private static class ChannelResourceVisitor
extends BaseInspectionVisitor
{
56 @Override public void visitMethodCallExpression(
57 @NotNull PsiMethodCallExpression expression
){
58 super.visitMethodCallExpression(expression
);
59 if(!isChannelFactoryMethod(expression
)){
62 final PsiElement parent
= expression
.getParent();
63 final PsiVariable boundVariable
;
64 if (parent
instanceof PsiAssignmentExpression
) {
65 final PsiAssignmentExpression assignment
=
66 (PsiAssignmentExpression
) parent
;
67 final PsiExpression lhs
= assignment
.getLExpression();
68 if (!(lhs
instanceof PsiReferenceExpression
)) {
71 final PsiReferenceExpression referenceExpression
=
72 (PsiReferenceExpression
) lhs
;
73 final PsiElement referent
= referenceExpression
.resolve();
74 if (referent
== null || !(referent
instanceof PsiVariable
)) {
77 boundVariable
= (PsiVariable
) referent
;
78 } else if (parent
instanceof PsiVariable
) {
79 boundVariable
= (PsiVariable
) parent
;
81 registerError(expression
, expression
);
84 final PsiStatement statement
=
85 PsiTreeUtil
.getParentOfType(expression
, PsiStatement
.class);
86 if (statement
== null) {
89 PsiStatement nextStatement
=
90 PsiTreeUtil
.getNextSiblingOfType(statement
,
92 if (!(nextStatement
instanceof PsiTryStatement
)) {
93 registerError(expression
, expression
);
96 //while (!(nextStatement instanceof PsiTryStatement)) {
97 //if (!(nextStatement instanceof PsiDeclarationStatement)) {
98 // registerError(expression, expression);
101 //final VariableReferenceVisitor visitor =
102 // new VariableReferenceVisitor(boundVariable);
103 //nextStatement.accept(visitor);
104 //if (visitor.containsReference()) {
105 // registerError(expression, expression);
109 // PsiTreeUtil.getNextSiblingOfType(nextStatement,
110 // PsiStatement.class);
112 PsiTryStatement tryStatement
= (PsiTryStatement
) nextStatement
;
113 if (resourceIsClosedInFinally(tryStatement
, boundVariable
)) {
116 registerError(expression
, expression
);
119 private static boolean isChannelFactoryMethod(
120 PsiMethodCallExpression expression
){
121 final PsiReferenceExpression methodExpression
=
122 expression
.getMethodExpression();
123 final String methodName
= methodExpression
.getReferenceName();
124 if(!HardcodedMethodConstants
.GET_CHANNEL
.equals(methodName
)) {
127 final PsiExpression qualifier
=
128 methodExpression
.getQualifierExpression();
129 if(qualifier
== null) {
132 return TypeUtils
.expressionHasTypeOrSubtype(qualifier
,
134 "java.net.DatagramSocket",
135 "java.net.ServerSocket",
136 "java.io.FileInputStream",
137 "java.io.FileOutputStream",
138 "java.io.RandomAccessFile");
141 private static boolean resourceIsClosedInFinally(
142 PsiTryStatement tryStatement
, PsiVariable boundVariable
){
143 final PsiCodeBlock finallyBlock
= tryStatement
.getFinallyBlock();
144 if(finallyBlock
== null){
147 final PsiCodeBlock tryBlock
= tryStatement
.getTryBlock();
148 if(tryBlock
== null){
151 final CloseVisitor visitor
= new CloseVisitor(boundVariable
);
152 finallyBlock
.accept(visitor
);
153 return visitor
.containsStreamClose();
158 private static class VariableReferenceVisitor
159 extends JavaRecursiveElementVisitor{
161 private boolean containsReference = false;
162 private PsiVariable variable;
164 VariableReferenceVisitor(@NotNull PsiVariable variable) {
165 this.variable = variable;
169 public void visitReferenceExpression(
170 PsiReferenceExpression expression) {
171 if (containsReference) {
174 final PsiExpression qualifier = expression.getQualifierExpression();
175 if (qualifier != null) {
178 final PsiElement target = expression.resolve();
179 if (variable.equals(target)) {
180 containsReference = true;
184 public boolean containsReference() {
185 return containsReference;
190 private static class CloseVisitor
extends JavaRecursiveElementVisitor
{
192 private boolean containsClose
= false;
193 private PsiVariable objectToClose
;
195 private CloseVisitor(PsiVariable objectToClose
){
196 this.objectToClose
= objectToClose
;
199 @Override public void visitElement(@NotNull PsiElement element
){
201 super.visitElement(element
);
205 @Override public void visitMethodCallExpression(
206 @NotNull PsiMethodCallExpression call
){
210 super.visitMethodCallExpression(call
);
211 final PsiReferenceExpression methodExpression
=
212 call
.getMethodExpression();
213 final String methodName
= methodExpression
.getReferenceName();
214 if(!HardcodedMethodConstants
.CLOSE
.equals(methodName
)){
217 final PsiExpression qualifier
=
218 methodExpression
.getQualifierExpression();
219 if(!(qualifier
instanceof PsiReferenceExpression
)){
222 final PsiReferenceExpression referenceExpression
=
223 (PsiReferenceExpression
) qualifier
;
224 final PsiElement referent
= referenceExpression
.resolve();
225 if(objectToClose
.equals(referent
)){
226 containsClose
= true;
230 public boolean containsStreamClose(){
231 return containsClose
;