IDEADEV-25371 and some cleanup
[fedora-idea.git] / plugins / InspectionGadgets / src / com / siyeh / ig / resources / JNDIResourceInspection.java
blob1dde99f973c5c1cc562889156aa4dae77ed09cf2
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 org.jetbrains.annotations.NonNls;
26 import org.jetbrains.annotations.NotNull;
28 public class JNDIResourceInspection extends BaseInspection {
30 @NotNull
31 public String getID(){
32 return "JNDIResourceOpenedButNotSafelyClosed";
35 @NotNull
36 public String getDisplayName(){
37 return InspectionGadgetsBundle.message(
38 "jndi.resource.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 "resource.opened.not.closed.problem.descriptor", text);
51 public BaseInspectionVisitor buildVisitor(){
52 return new JNDIResourceVisitor();
55 private static class JNDIResourceVisitor extends BaseInspectionVisitor{
57 @NonNls private static final String LIST = "list";
58 @NonNls private static final String LIST_BINDING = "listBindings";
59 @NonNls private static final String GET_ALL = "getAll";
61 @Override public void visitMethodCallExpression(
62 @NotNull PsiMethodCallExpression expression){
63 super.visitMethodCallExpression(expression);
64 if(!isJNDIFactoryMethod(expression)){
65 return;
67 final PsiElement parent = expression.getParent();
68 if(!(parent instanceof PsiAssignmentExpression)){
69 registerError(expression, expression);
70 return;
72 final PsiAssignmentExpression assignment =
73 (PsiAssignmentExpression) parent;
74 final PsiExpression lhs = assignment.getLExpression();
75 if(!(lhs instanceof PsiReferenceExpression)){
76 return;
78 final PsiElement referent =
79 ((PsiReference) lhs).resolve();
80 if(referent == null || !(referent instanceof PsiVariable)){
81 return;
83 final PsiVariable boundVariable = (PsiVariable) referent;
85 PsiElement currentContext = expression;
86 while(true){
87 final PsiTryStatement tryStatement =
88 PsiTreeUtil.getParentOfType(currentContext,
89 PsiTryStatement.class);
90 if(tryStatement == null){
91 registerError(expression, expression);
92 return;
94 if(resourceIsOpenedInTryAndClosedInFinally(tryStatement,
95 expression,
96 boundVariable)){
97 return;
99 currentContext = tryStatement;
104 @Override public void visitNewExpression(
105 @NotNull PsiNewExpression expression){
106 super.visitNewExpression(expression);
107 if(!isJNDIResource(expression)){
108 return;
110 if(expression.getType() == null){
111 return;
113 final PsiElement parent = expression.getParent();
114 if(!(parent instanceof PsiAssignmentExpression)){
115 registerError(expression, expression);
116 return;
118 final PsiAssignmentExpression assignment =
119 (PsiAssignmentExpression) parent;
120 final PsiExpression lhs = assignment.getLExpression();
121 if(!(lhs instanceof PsiReferenceExpression)){
122 return;
124 final PsiElement referent =
125 ((PsiReference) lhs).resolve();
126 if(referent == null || !(referent instanceof PsiVariable)){
127 return;
129 final PsiVariable boundVariable = (PsiVariable) referent;
131 PsiElement currentContext = expression;
132 while(true){
133 final PsiTryStatement tryStatement =
134 PsiTreeUtil.getParentOfType(currentContext,
135 PsiTryStatement.class);
136 if(tryStatement == null){
137 registerError(expression, expression);
138 return;
140 if(resourceIsOpenedInTryAndClosedInFinally(tryStatement,
141 expression, boundVariable)) {
142 return;
144 currentContext = tryStatement;
148 private static boolean resourceIsOpenedInTryAndClosedInFinally(
149 PsiTryStatement tryStatement, PsiExpression resourceExpression,
150 PsiVariable boundVariable){
151 final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
152 if(finallyBlock == null){
153 return false;
155 final PsiCodeBlock tryBlock = tryStatement.getTryBlock();
156 if(tryBlock == null){
157 return false;
159 if(!PsiTreeUtil.isAncestor(tryBlock, resourceExpression, true)){
160 return false;
162 return containsResourceClose(finallyBlock, boundVariable);
165 private static boolean containsResourceClose(PsiCodeBlock finallyBlock,
166 PsiVariable boundVariable){
167 final CloseVisitor visitor =
168 new CloseVisitor(boundVariable);
169 finallyBlock.accept(visitor);
170 return visitor.containsStreamClose();
173 private static boolean isJNDIResource(PsiNewExpression expression){
174 return TypeUtils.expressionHasTypeOrSubtype(expression,
175 "javax.naming.InitialContext");
178 private static boolean isJNDIFactoryMethod(
179 PsiMethodCallExpression expression){
180 final PsiReferenceExpression methodExpression =
181 expression.getMethodExpression();
182 final String methodName = methodExpression.getReferenceName();
183 if (LIST.equals(methodName) || LIST_BINDING.equals(methodName)) {
184 final PsiExpression qualifier =
185 methodExpression.getQualifierExpression();
186 if (qualifier == null) {
187 return false;
189 return TypeUtils.expressionHasTypeOrSubtype(qualifier,
190 "javax.naming.Context");
191 } else if (GET_ALL.equals(methodName)) {
192 final PsiExpression qualifier =
193 methodExpression.getQualifierExpression();
194 if (qualifier == null) {
195 return false;
197 return TypeUtils.expressionHasTypeOrSubtype(qualifier,
198 "javax.naming.directory.Attribute") ||
199 TypeUtils.expressionHasTypeOrSubtype(qualifier,
200 "javax.naming.directory.Attributes");
201 } else {
202 return false;
207 private static class CloseVisitor extends JavaRecursiveElementVisitor{
209 private boolean containsClose = false;
210 private PsiVariable socketToClose;
212 private CloseVisitor(PsiVariable socketToClose){
213 super();
214 this.socketToClose = socketToClose;
217 @Override public void visitElement(@NotNull PsiElement element){
218 if(!containsClose){
219 super.visitElement(element);
223 @Override public void visitMethodCallExpression(
224 @NotNull PsiMethodCallExpression call){
225 if(containsClose){
226 return;
228 super.visitMethodCallExpression(call);
229 final PsiReferenceExpression methodExpression =
230 call.getMethodExpression();
231 final String methodName = methodExpression.getReferenceName();
232 if(!HardcodedMethodConstants.CLOSE.equals(methodName)){
233 return;
235 final PsiExpression qualifier =
236 methodExpression.getQualifierExpression();
237 if(!(qualifier instanceof PsiReferenceExpression)){
238 return;
240 final PsiElement referent =
241 ((PsiReference) qualifier).resolve();
242 if(referent == null){
243 return;
245 if(referent.equals(socketToClose)){
246 containsClose = true;
250 public boolean containsStreamClose(){
251 return containsClose;