mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 09:19:13 +07:00
Try-with-resource support: variable usage inspection
This commit is contained in:
@@ -97,7 +97,7 @@ public class DefUseInspection extends BaseLocalInspectionTool {
|
||||
PsiElement context = info.getContext();
|
||||
PsiVariable psiVariable = info.getVariable();
|
||||
|
||||
if (context instanceof PsiDeclarationStatement) {
|
||||
if (context instanceof PsiDeclarationStatement || context instanceof PsiResource) {
|
||||
if (!info.isRead()) {
|
||||
if (!isOnTheFly) {
|
||||
holder.registerProblem(psiVariable.getNameIdentifier(),
|
||||
|
||||
@@ -474,7 +474,8 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
|
||||
finishElement(statement);
|
||||
}
|
||||
|
||||
@Override public void visitDeclarationStatement(PsiDeclarationStatement statement) {
|
||||
@Override
|
||||
public void visitDeclarationStatement(PsiDeclarationStatement statement) {
|
||||
startElement(statement);
|
||||
int pc = myCurrentFlow.getSize();
|
||||
PsiElement[] elements = statement.getDeclaredElements();
|
||||
@@ -484,28 +485,7 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
|
||||
element.accept(this);
|
||||
}
|
||||
else if (element instanceof PsiVariable) {
|
||||
PsiExpression initializer = ((PsiVariable)element).getInitializer();
|
||||
if (initializer != null) {
|
||||
myStartStatementStack.pushStatement(initializer, false);
|
||||
myEndStatementStack.pushStatement(initializer, false);
|
||||
initializer.accept(this);
|
||||
myStartStatementStack.popStatement();
|
||||
myEndStatementStack.popStatement();
|
||||
}
|
||||
if (element instanceof PsiLocalVariable && initializer != null
|
||||
|| element instanceof PsiField) {
|
||||
if (element instanceof PsiLocalVariable && !myPolicy.isLocalVariableAccepted((PsiLocalVariable)element)) continue;
|
||||
|
||||
if (myAssignmentTargetsAreElements) {
|
||||
startElement(element);
|
||||
}
|
||||
|
||||
generateWriteInstruction((PsiVariable)element);
|
||||
|
||||
if (myAssignmentTargetsAreElements) {
|
||||
finishElement(element);
|
||||
}
|
||||
}
|
||||
processVariable((PsiVariable)element);
|
||||
}
|
||||
}
|
||||
if (pc == myCurrentFlow.getSize()) {
|
||||
@@ -515,6 +495,31 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
|
||||
finishElement(statement);
|
||||
}
|
||||
|
||||
private void processVariable(final PsiVariable element) {
|
||||
final PsiExpression initializer = element.getInitializer();
|
||||
if (initializer != null) {
|
||||
myStartStatementStack.pushStatement(initializer, false);
|
||||
myEndStatementStack.pushStatement(initializer, false);
|
||||
initializer.accept(this);
|
||||
myStartStatementStack.popStatement();
|
||||
myEndStatementStack.popStatement();
|
||||
}
|
||||
if (element instanceof PsiLocalVariable && initializer != null ||
|
||||
element instanceof PsiField) {
|
||||
if (element instanceof PsiLocalVariable && !myPolicy.isLocalVariableAccepted((PsiLocalVariable)element)) return;
|
||||
|
||||
if (myAssignmentTargetsAreElements) {
|
||||
startElement(element);
|
||||
}
|
||||
|
||||
generateWriteInstruction(element);
|
||||
|
||||
if (myAssignmentTargetsAreElements) {
|
||||
finishElement(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void visitDoWhileStatement(PsiDoWhileStatement statement) {
|
||||
startElement(statement);
|
||||
myStartStatementStack.pushStatement(statement.getBody() == null ? statement : statement.getBody(), true);
|
||||
@@ -1030,17 +1035,17 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
|
||||
myFinallyBlocks.push(finallyBlock);
|
||||
}
|
||||
|
||||
PsiResourceList resourceList = statement.getResourceList();
|
||||
if (resourceList != null) {
|
||||
generateCheckedExceptionJumps(resourceList);
|
||||
resourceList.accept(this);
|
||||
}
|
||||
PsiCodeBlock tryBlock = statement.getTryBlock();
|
||||
if (tryBlock != null) {
|
||||
// javac works as if all checked exceptions can occur at the top of the block
|
||||
generateCheckedExceptionJumps(tryBlock);
|
||||
tryBlock.accept(this);
|
||||
}
|
||||
PsiResourceList resourceList = statement.getResourceList();
|
||||
if (resourceList != null) {
|
||||
generateCheckedExceptionJumps(resourceList);
|
||||
resourceList.accept(this);
|
||||
}
|
||||
|
||||
//noinspection StatementWithEmptyBody
|
||||
while (myUnhandledExceptionCatchBlocks.pop() != null) ;
|
||||
@@ -1157,8 +1162,36 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
|
||||
finishElement(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitResourceList(final PsiResourceList resourceList) {
|
||||
startElement(resourceList);
|
||||
|
||||
@Override public void visitWhileStatement(PsiWhileStatement statement) {
|
||||
final List<PsiResource> resources = resourceList.getResources();
|
||||
for (PsiResource resource : resources) {
|
||||
ProgressManager.checkCanceled();
|
||||
resource.accept(this);
|
||||
}
|
||||
|
||||
finishElement(resourceList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitResource(final PsiResource resource) {
|
||||
startElement(resource);
|
||||
|
||||
final PsiElement resourceElement = resource.getResourceElement();
|
||||
if (resourceElement instanceof PsiLocalVariable) {
|
||||
processVariable((PsiLocalVariable)resourceElement);
|
||||
}
|
||||
else if (resourceElement instanceof PsiExpression) {
|
||||
resourceElement.accept(this);
|
||||
}
|
||||
|
||||
finishElement(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhileStatement(PsiWhileStatement statement) {
|
||||
startElement(statement);
|
||||
if (statement.getBody() == null) {
|
||||
myStartStatementStack.pushStatement(statement, false);
|
||||
|
||||
@@ -13,15 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: max
|
||||
* Date: Mar 22, 2002
|
||||
* Time: 7:25:02 PM
|
||||
* To change template for new class use
|
||||
* Code Style | Class Templates options (Tools | IDE Options).
|
||||
*/
|
||||
package com.intellij.psi.controlFlow;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -34,16 +25,20 @@ import com.intellij.util.containers.IntArrayList;
|
||||
import com.intellij.util.containers.Queue;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
* Date: Mar 22, 2002
|
||||
*/
|
||||
public class DefUseUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.defUse.DefUseUtil");
|
||||
|
||||
private DefUseUtil() {
|
||||
}
|
||||
private DefUseUtil() { }
|
||||
|
||||
public static class Info {
|
||||
private final PsiVariable myVariable;
|
||||
@@ -132,6 +127,7 @@ public class DefUseUtil {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static List<Info> getUnusedDefs(PsiCodeBlock body, Set<PsiVariable> outUsedVariables) {
|
||||
if (body == null) {
|
||||
return null;
|
||||
@@ -232,12 +228,13 @@ public class DefUseUtil {
|
||||
if (instruction instanceof WriteVariableInstruction) {
|
||||
WriteVariableInstruction writeInstruction = (WriteVariableInstruction)instruction;
|
||||
if (!defsArmed[i]) {
|
||||
PsiElement context = flow.getElement(i);
|
||||
context = PsiTreeUtil.getNonStrictParentOfType(context, PsiStatement.class, PsiAssignmentExpression.class,
|
||||
PsiPostfixExpression.class, PsiPrefixExpression.class);
|
||||
PsiElement context = PsiTreeUtil.getNonStrictParentOfType(flow.getElement(i),
|
||||
PsiStatement.class, PsiAssignmentExpression.class,
|
||||
PsiPostfixExpression.class, PsiPrefixExpression.class,
|
||||
PsiResource.class);
|
||||
PsiVariable psiVariable = writeInstruction.variable;
|
||||
if (context != null && !(context instanceof PsiTryStatement)) {
|
||||
if (context instanceof PsiDeclarationStatement && psiVariable.getInitializer() == null) {
|
||||
if (isDeclaration(context) && psiVariable.getInitializer() == null) {
|
||||
if (!assignedVariables.contains(psiVariable)) {
|
||||
unusedDefs.add(new Info(psiVariable, context, false));
|
||||
}
|
||||
@@ -251,7 +248,11 @@ public class DefUseUtil {
|
||||
}
|
||||
|
||||
return unusedDefs;
|
||||
}
|
||||
|
||||
private static boolean isDeclaration(final PsiElement context) {
|
||||
return context instanceof PsiDeclarationStatement ||
|
||||
context instanceof PsiResource && ((PsiResource)context).getResourceElement() instanceof PsiLocalVariable;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -476,5 +477,4 @@ public class DefUseUtil {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
import java.lang.Exception;
|
||||
|
||||
class C {
|
||||
static class MyResource implements AutoCloseable {
|
||||
@Override public void close() { }
|
||||
}
|
||||
|
||||
void m1() throws Exception {
|
||||
MyResource r1;
|
||||
try (r1 = new MyResource()) {
|
||||
System.out.println(r1);
|
||||
}
|
||||
|
||||
try (MyResource r2 = new MyResource()) {
|
||||
System.out.println(r2);
|
||||
}
|
||||
|
||||
MyResource r3 = new MyResource();
|
||||
try (MyResource r = r3) {
|
||||
System.out.println(r);
|
||||
}
|
||||
}
|
||||
|
||||
void m2() throws Exception {
|
||||
MyResource r1 = <warning descr="Variable 'r1' initializer 'null' is redundant">null</warning>;
|
||||
try (r1 = new MyResource()) {
|
||||
System.out.println(r1);
|
||||
}
|
||||
|
||||
try (MyResource r2 = <warning descr="Variable 'r2' initializer 'new MyResource()' is redundant">new MyResource()</warning>) {
|
||||
r2 = null; // todo: check for NPE
|
||||
System.out.println(r2);
|
||||
}
|
||||
|
||||
MyResource r3 = null;
|
||||
System.out.println(r3);
|
||||
try (r3 = <warning descr="The value 'new MyResource()' assigned to r3 is never used">new MyResource()</warning>) { }
|
||||
|
||||
try (MyResource <warning descr="Variable 'r4' is never used">r4</warning> = new MyResource()) { }
|
||||
|
||||
try (MyResource r5 = new MyResource()) {
|
||||
System.out.println(r5);
|
||||
r5 = <warning descr="The value 'new MyResource()' assigned to r5 is never used">new MyResource()</warning>;
|
||||
}
|
||||
|
||||
MyResource <warning descr="Variable 'r6' is never assigned">r6</warning>;
|
||||
try (MyResource r = <error descr="Variable 'r6' might not have been initialized">r6</error>) {
|
||||
System.out.println(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-1
@@ -4,6 +4,7 @@ import com.intellij.ExtensionPoints;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection;
|
||||
import com.intellij.codeInspection.defUse.DefUseInspection;
|
||||
import com.intellij.codeInspection.reference.EntryPoint;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection;
|
||||
@@ -31,7 +32,7 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
|
||||
|
||||
@Override
|
||||
protected LocalInspectionTool[] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{new UnusedSymbolLocalInspection(), new UncheckedWarningLocalInspection()};
|
||||
return new LocalInspectionTool[]{new UnusedSymbolLocalInspection(), new UncheckedWarningLocalInspection(), new DefUseInspection()};
|
||||
}
|
||||
|
||||
public void testDuplicateAnnotations() throws Exception {
|
||||
@@ -192,6 +193,10 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
|
||||
doTest(false, false);
|
||||
}
|
||||
|
||||
public void testTryWithResourcesWarn() throws Exception {
|
||||
doTest(true, false);
|
||||
}
|
||||
|
||||
public void testSafeVarargsApplicability() throws Exception {
|
||||
doTest(true, false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user