fix for NPE and cleanup
[fedora-idea.git] / plugins / InspectionGadgets / src / com / siyeh / ig / resources / ChannelResourceInspection.java
blob60f33bdde7bda52daa5f113cc0496d812f3b5abb
1 /*
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{
30 @NotNull
31 public String getID(){
32 return "ChannelOpenedButNotSafelyClosed";
35 @NotNull
36 public String getDisplayName(){
37 return InspectionGadgetsBundle.message(
38 "channel.opened.not.closed.display.name");
41 @NotNull
42 public String buildErrorString(Object... infos){
43 final PsiExpression expression = (PsiExpression) infos[0];
44 final PsiType type = expression.getType();
45 assert type != null;
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)){
61 return;
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)) {
70 return;
72 final PsiReferenceExpression referenceExpression =
73 (PsiReferenceExpression) lhs;
74 final PsiElement referent = referenceExpression.resolve();
75 if (referent == null || !(referent instanceof PsiVariable)) {
76 return;
78 boundVariable = (PsiVariable) referent;
79 } else if (parent instanceof PsiVariable) {
80 boundVariable = (PsiVariable) parent;
81 } else {
82 boundVariable = null;
84 final PsiStatement statement =
85 PsiTreeUtil.getParentOfType(expression, PsiStatement.class);
86 if (statement == null) {
87 return;
89 PsiStatement nextStatement =
90 PsiTreeUtil.getNextSiblingOfType(statement,
91 PsiStatement.class);
92 while (!(nextStatement instanceof PsiTryStatement)) {
93 if (!(nextStatement instanceof PsiDeclarationStatement)) {
94 registerError(expression, expression);
95 return;
97 if (boundVariable != null) {
98 if (VariableAccessUtils.variableIsUsed(boundVariable,
99 nextStatement)) {
100 registerError(expression, expression);
101 return;
104 nextStatement =
105 PsiTreeUtil.getNextSiblingOfType(nextStatement,
106 PsiStatement.class);
108 PsiTryStatement tryStatement = (PsiTryStatement) nextStatement;
109 if (boundVariable != null &&
110 resourceIsClosedInFinally(tryStatement, boundVariable)) {
111 return;
113 if (isChannelFactoryClosedInFinally(expression, tryStatement)) {
114 return;
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)) {
127 return false;
129 PsiReferenceExpression referenceExpression =
130 (PsiReferenceExpression) qualifier;
131 final PsiElement target = referenceExpression.resolve();
132 if (!(target instanceof PsiVariable)) {
133 return false;
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)) {
145 return false;
147 final PsiExpression qualifier =
148 methodExpression.getQualifierExpression();
149 if(qualifier == null) {
150 return false;
152 return TypeUtils.expressionHasTypeOrSubtype(qualifier,
153 "java.net.Socket",
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){
168 return false;
170 final PsiCodeBlock tryBlock = tryStatement.getTryBlock();
171 if(tryBlock == null){
172 return false;
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){
190 if(!containsClose){
191 super.visitElement(element);
195 @Override public void visitMethodCallExpression(
196 @NotNull PsiMethodCallExpression call){
197 if(containsClose){
198 return;
200 super.visitMethodCallExpression(call);
201 final PsiReferenceExpression methodExpression =
202 call.getMethodExpression();
203 final String methodName = methodExpression.getReferenceName();
204 if(!HardcodedMethodConstants.CLOSE.equals(methodName)){
205 return;
207 final PsiExpression qualifier =
208 methodExpression.getQualifierExpression();
209 if(!(qualifier instanceof PsiReferenceExpression)){
210 return;
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;