2 * Copyright 2008 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
.intellij
.psi
.util
.PsiUtil
;
21 import com
.siyeh
.HardcodedMethodConstants
;
22 import com
.siyeh
.ig
.BaseInspection
;
23 import org
.jetbrains
.annotations
.NotNull
;
24 import org
.jetbrains
.annotations
.Nullable
;
26 public abstract class ResourceInspection
extends BaseInspection
{
29 protected static PsiVariable
getVariable(
30 @NotNull PsiElement element
) {
31 if (element
instanceof PsiAssignmentExpression
) {
32 final PsiAssignmentExpression assignment
=
33 (PsiAssignmentExpression
) element
;
34 final PsiExpression lhs
= assignment
.getLExpression();
35 if (!(lhs
instanceof PsiReferenceExpression
)) {
38 final PsiReferenceExpression referenceExpression
=
39 (PsiReferenceExpression
) lhs
;
40 final PsiElement referent
= referenceExpression
.resolve();
41 if (referent
== null || !(referent
instanceof PsiVariable
)) {
44 return (PsiVariable
) referent
;
45 } else if (element
instanceof PsiVariable
) {
46 return (PsiVariable
) element
;
52 protected static PsiElement
getExpressionParent(PsiExpression expression
) {
53 PsiElement parent
= expression
.getParent();
54 while (parent
instanceof PsiParenthesizedExpression
||
55 parent
instanceof PsiTypeCastExpression
) {
56 parent
= parent
.getParent();
61 protected static boolean isSafelyClosed(@Nullable PsiVariable boundVariable
,
62 PsiExpression creationContext
64 if (boundVariable
== null) {
67 final PsiStatement statement
=
68 PsiTreeUtil
.getParentOfType(creationContext
, PsiStatement
.class);
69 if (statement
== null) {
72 final PsiStatement nextStatement
=
73 PsiTreeUtil
.getNextSiblingOfType(statement
,
75 if (!(nextStatement
instanceof PsiTryStatement
)) {
76 // exception in next statement can prevent closing of the resource
79 final PsiTryStatement tryStatement
= (PsiTryStatement
) nextStatement
;
80 return resourceIsClosedInFinally(tryStatement
, boundVariable
);
83 protected static boolean resourceIsClosedInFinally(
84 @NotNull PsiTryStatement tryStatement
,
85 @NotNull PsiVariable boundVariable
) {
86 final PsiCodeBlock finallyBlock
= tryStatement
.getFinallyBlock();
87 if (finallyBlock
== null) {
90 final PsiCodeBlock tryBlock
= tryStatement
.getTryBlock();
91 if (tryBlock
== null) {
94 final CloseVisitor visitor
= new CloseVisitor(boundVariable
);
95 finallyBlock
.accept(visitor
);
96 return visitor
.containsClose();
99 protected static boolean isResourceEscapedFromMethod(
100 PsiVariable boundVariable
, PsiElement context
){
102 final PsiMethod method
=
103 PsiTreeUtil
.getParentOfType(context
, PsiMethod
.class, true,
108 final PsiCodeBlock body
= method
.getBody();
112 final EscapeVisitor visitor
= new EscapeVisitor(boundVariable
);
113 body
.accept(visitor
);
114 return visitor
.isEscaped();
117 private static class CloseVisitor
extends JavaRecursiveElementVisitor
{
119 private boolean containsClose
= false;
120 private final PsiVariable resource
;
121 private final String resourceName
;
123 private CloseVisitor(PsiVariable resource
) {
124 this.resource
= resource
;
125 this.resourceName
= resource
.getName();
129 public void visitElement(@NotNull PsiElement element
) {
130 if (!containsClose
) {
131 super.visitElement(element
);
136 public void visitMethodCallExpression(
137 @NotNull PsiMethodCallExpression call
) {
141 super.visitMethodCallExpression(call
);
142 if (!isResourceClose(call
, resource
)) {
145 containsClose
= true;
149 public void visitReferenceExpression(
150 PsiReferenceExpression referenceExpression
) {
151 // check if resource is closed in IOUtils.silentClose() like method
152 super.visitReferenceExpression(referenceExpression
);
156 final String text
= referenceExpression
.getText();
157 if (text
== null || !text
.equals(resourceName
)) {
160 final PsiElement parent
= referenceExpression
.getParent();
161 if (!(parent
instanceof PsiExpressionList
)) {
164 final PsiExpressionList argumentList
= (PsiExpressionList
) parent
;
165 final PsiExpression
[] arguments
= argumentList
.getExpressions();
166 if (arguments
.length
!= 1) {
169 final PsiElement grandParent
= parent
.getParent();
170 if (!(grandParent
instanceof PsiMethodCallExpression
)) {
173 final PsiMethodCallExpression methodCallExpression
=
174 (PsiMethodCallExpression
) grandParent
;
175 final PsiElement target
= referenceExpression
.resolve();
176 if (target
== null || !target
.equals(resource
)) {
179 final PsiMethod method
= methodCallExpression
.resolveMethod();
180 if (method
== null) {
183 final PsiCodeBlock codeBlock
= method
.getBody();
184 if (codeBlock
== null) {
187 final PsiParameterList parameterList
= method
.getParameterList();
188 final PsiParameter
[] parameters
= parameterList
.getParameters();
189 if (parameters
.length
!= 1) {
192 final PsiParameter parameter
= parameters
[0];
193 final PsiStatement
[] statements
= codeBlock
.getStatements();
194 for (PsiStatement statement
: statements
) {
195 if (!(statement
instanceof PsiTryStatement
)) {
198 final PsiTryStatement tryStatement
= (PsiTryStatement
) statement
;
199 final PsiCodeBlock tryBlock
= tryStatement
.getTryBlock();
200 if (tryBlock
== null) {
203 final PsiStatement
[] innerStatements
= tryBlock
.getStatements();
204 for (PsiStatement innerStatement
: innerStatements
) {
205 if (!(innerStatement
instanceof PsiExpressionStatement
)) {
208 final PsiExpressionStatement expressionStatement
=
209 (PsiExpressionStatement
) innerStatement
;
210 final PsiExpression expression
=
211 expressionStatement
.getExpression();
212 if (!(expression
instanceof PsiMethodCallExpression
)) {
215 final PsiMethodCallExpression potentialCloseExpression
=
216 (PsiMethodCallExpression
) expression
;
217 if (isResourceClose(potentialCloseExpression
, parameter
)) {
218 containsClose
= true;
225 private static boolean isResourceClose(PsiMethodCallExpression call
,
226 PsiVariable resource
) {
227 final PsiReferenceExpression methodExpression
=
228 call
.getMethodExpression();
229 final String methodName
= methodExpression
.getReferenceName();
230 if (!HardcodedMethodConstants
.CLOSE
.equals(methodName
)) {
233 final PsiExpression qualifier
=
234 methodExpression
.getQualifierExpression();
235 if (!(qualifier
instanceof PsiReferenceExpression
)) {
238 final PsiReference reference
= (PsiReference
) qualifier
;
239 final PsiElement referent
= reference
.resolve();
240 return referent
!= null && referent
.equals(resource
);
243 public boolean containsClose() {
244 return containsClose
;
248 private static class EscapeVisitor
extends JavaRecursiveElementVisitor
{
250 private final PsiVariable boundVariable
;
251 private boolean escaped
= false;
253 public EscapeVisitor(PsiVariable boundVariable
){
254 this.boundVariable
= boundVariable
;
257 @Override public void visitAnonymousClass(PsiAnonymousClass aClass
){}
260 public void visitElement(PsiElement element
){
264 super.visitElement(element
);
267 @Override public void visitReturnStatement(
268 PsiReturnStatement statement
){
269 PsiExpression value
= statement
.getReturnValue();
270 value
= PsiUtil
.deparenthesizeExpression(value
);
271 if (value
instanceof PsiReferenceExpression
){
272 final PsiReferenceExpression referenceExpression
=
273 (PsiReferenceExpression
) value
;
274 final PsiElement target
= referenceExpression
.resolve();
275 if(target
== boundVariable
){
281 public boolean isEscaped(){