IDEADEV-25371 and some cleanup
[fedora-idea.git] / plugins / InspectionGadgets / src / com / siyeh / ig / resources / ChannelResourceInspection.java
blobcc16c3b072357027dc2dcda8f7f4bff4c4112048
1 /*
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{
29 @NotNull
30 public String getID(){
31 return "ChannelOpenedButNotSafelyClosed";
34 @NotNull
35 public String getDisplayName(){
36 return InspectionGadgetsBundle.message(
37 "channel.opened.not.closed.display.name");
40 @NotNull
41 public String buildErrorString(Object... infos){
42 final PsiExpression expression = (PsiExpression) infos[0];
43 final PsiType type = expression.getType();
44 assert type != null;
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)){
60 return;
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)) {
69 return;
71 final PsiReferenceExpression referenceExpression =
72 (PsiReferenceExpression) lhs;
73 final PsiElement referent = referenceExpression.resolve();
74 if (referent == null || !(referent instanceof PsiVariable)) {
75 return;
77 boundVariable = (PsiVariable) referent;
78 } else if (parent instanceof PsiVariable) {
79 boundVariable = (PsiVariable) parent;
80 } else {
81 registerError(expression, expression);
82 return;
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 if (!(nextStatement instanceof PsiTryStatement)) {
93 registerError(expression, expression);
94 return;
96 //while (!(nextStatement instanceof PsiTryStatement)) {
97 //if (!(nextStatement instanceof PsiDeclarationStatement)) {
98 // registerError(expression, expression);
99 // return;
101 //final VariableReferenceVisitor visitor =
102 // new VariableReferenceVisitor(boundVariable);
103 //nextStatement.accept(visitor);
104 //if (visitor.containsReference()) {
105 // registerError(expression, expression);
106 // return;
108 //nextStatement =
109 // PsiTreeUtil.getNextSiblingOfType(nextStatement,
110 // PsiStatement.class);
112 PsiTryStatement tryStatement = (PsiTryStatement) nextStatement;
113 if (resourceIsClosedInFinally(tryStatement, boundVariable)) {
114 return;
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)) {
125 return false;
127 final PsiExpression qualifier =
128 methodExpression.getQualifierExpression();
129 if(qualifier == null) {
130 return false;
132 return TypeUtils.expressionHasTypeOrSubtype(qualifier,
133 "java.net.Socket",
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){
145 return false;
147 final PsiCodeBlock tryBlock = tryStatement.getTryBlock();
148 if(tryBlock == null){
149 return false;
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;
168 @Override
169 public void visitReferenceExpression(
170 PsiReferenceExpression expression) {
171 if (containsReference) {
172 return;
174 final PsiExpression qualifier = expression.getQualifierExpression();
175 if (qualifier != null) {
176 return;
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){
200 if(!containsClose){
201 super.visitElement(element);
205 @Override public void visitMethodCallExpression(
206 @NotNull PsiMethodCallExpression call){
207 if(containsClose){
208 return;
210 super.visitMethodCallExpression(call);
211 final PsiReferenceExpression methodExpression =
212 call.getMethodExpression();
213 final String methodName = methodExpression.getReferenceName();
214 if(!HardcodedMethodConstants.CLOSE.equals(methodName)){
215 return;
217 final PsiExpression qualifier =
218 methodExpression.getQualifierExpression();
219 if(!(qualifier instanceof PsiReferenceExpression)){
220 return;
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;