InstructionVisitor in dfa
[fedora-idea.git] / inspections / impl / com / intellij / codeInspection / dataFlow / instructions / BinopInstruction.java
blob74da0311e038c4e412d04fa04c1e30c426842a10
1 /*
2 * Created by IntelliJ IDEA.
3 * User: max
4 * Date: Feb 7, 2002
5 * Time: 1:11:08 PM
6 * To change template for new class use
7 * Code Style | Class Templates options (Tools | IDE Options).
8 */
9 package com.intellij.codeInspection.dataFlow.instructions;
11 import com.intellij.codeInspection.dataFlow.DataFlowRunner;
12 import com.intellij.codeInspection.dataFlow.DfaInstructionState;
13 import com.intellij.codeInspection.dataFlow.DfaMemoryState;
14 import com.intellij.codeInspection.dataFlow.InstructionVisitor;
15 import com.intellij.codeInspection.dataFlow.value.*;
16 import com.intellij.openapi.project.Project;
17 import com.intellij.psi.*;
18 import com.intellij.psi.search.GlobalSearchScope;
19 import org.jetbrains.annotations.NonNls;
20 import org.jetbrains.annotations.NotNull;
22 import java.util.ArrayList;
24 public class BinopInstruction extends BranchingInstruction {
25 private final String myOperationSign;
26 private boolean myIsInstanceofRedundant = true;
27 private boolean myIsReachable = false;
28 private boolean myCanBeNullInInstanceof = false;
29 private final Project myProject;
31 public BinopInstruction(@NonNls String opSign, PsiElement psiAnchor, @NotNull Project project) {
32 myProject = project;
33 if (opSign != null && ("==".equals(opSign) || "!=".equals(opSign) || "instanceof".equals(opSign) || "+".equals(opSign))) {
34 myOperationSign = opSign;
35 if (!"instanceof".equals(opSign)) myIsInstanceofRedundant = false;
37 else {
38 myOperationSign = null;
39 myIsInstanceofRedundant = false;
42 setPsiAnchor(psiAnchor);
45 public DfaInstructionState[] apply(DataFlowRunner runner, DfaMemoryState memState) {
46 myIsReachable = true;
47 final Instruction next = runner.getInstruction(getIndex() + 1);
49 DfaValue dfaRight = memState.pop();
50 DfaValue dfaLeft = memState.pop();
52 if (myOperationSign != null) {
53 final DfaValueFactory factory = runner.getFactory();
54 if (("==".equals(myOperationSign) || "!=".equals(myOperationSign)) &&
55 dfaLeft instanceof DfaConstValue && dfaRight instanceof DfaConstValue) {
56 boolean negated = "!=".equals(myOperationSign) ^ (memState.canBeNaN(dfaLeft) || memState.canBeNaN(dfaRight));
57 if (dfaLeft == dfaRight ^ negated) {
58 memState.push(factory.getConstFactory().getTrue());
59 setTrueReachable();
61 else {
62 memState.push(factory.getConstFactory().getFalse());
63 setFalseReachable();
65 return new DfaInstructionState[]{new DfaInstructionState(next, memState)};
68 boolean negated = memState.canBeNaN(dfaLeft) || memState.canBeNaN(dfaRight);
69 DfaRelationValue dfaRelation = factory.getRelationFactory().create(dfaLeft, dfaRight, myOperationSign, negated);
70 if (dfaRelation != null) {
71 myCanBeNullInInstanceof = true;
72 ArrayList<DfaInstructionState> states = new ArrayList<DfaInstructionState>();
74 final DfaMemoryState trueCopy = memState.createCopy();
75 if (trueCopy.applyCondition(dfaRelation)) {
76 trueCopy.push(factory.getConstFactory().getTrue());
77 setTrueReachable();
78 states.add(new DfaInstructionState(next, trueCopy));
81 DfaMemoryState falseCopy = memState;
82 if (falseCopy.applyCondition(dfaRelation.createNegated())) {
83 falseCopy.push(factory.getConstFactory().getFalse());
84 setFalseReachable();
85 states.add(new DfaInstructionState(next, falseCopy));
86 if (myIsInstanceofRedundant && !falseCopy.isNull(dfaLeft)) {
87 myIsInstanceofRedundant = false;
91 return states.toArray(new DfaInstructionState[states.size()]);
93 else if ("+".equals(myOperationSign)) {
94 memState.push(getNonNullStringValue(factory));
95 setTrueReachable(); // Not a branching instruction actually.
96 setFalseReachable();
98 else {
99 if (PsiKeyword.INSTANCEOF.equals(myOperationSign) &&
100 (dfaLeft instanceof DfaTypeValue || dfaLeft instanceof DfaNotNullValue) &&
101 dfaRight instanceof DfaTypeValue) {
102 final PsiType leftType;
103 if (dfaLeft instanceof DfaNotNullValue) {
104 leftType = ((DfaNotNullValue)dfaLeft).getType();
106 else {
107 leftType = ((DfaTypeValue)dfaLeft).getType();
108 myCanBeNullInInstanceof = true;
111 if (!((DfaTypeValue)dfaRight).getType().isAssignableFrom(leftType)) {
112 myIsInstanceofRedundant = false;
115 else {
116 myIsInstanceofRedundant = false;
118 memState.push(DfaUnknownValue.getInstance());
121 else {
122 memState.push(DfaUnknownValue.getInstance());
125 return new DfaInstructionState[]{new DfaInstructionState(next, memState)};
128 @Override
129 public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState stateBefore, InstructionVisitor visitor) {
130 return visitor.visitBinop(this, runner, stateBefore);
133 private DfaValue getNonNullStringValue(final DfaValueFactory factory) {
134 PsiElement anchor = getPsiAnchor();
135 PsiClassType string = PsiType.getJavaLangString(PsiManager.getInstance(myProject), anchor == null ? GlobalSearchScope.allScope(myProject) : anchor.getResolveScope());
136 return factory.getNotNullFactory().create(string);
139 public boolean isInstanceofRedundant() {
140 return myIsInstanceofRedundant && !isConditionConst() && myIsReachable;
143 public boolean canBeNull() {
144 return myCanBeNullInInstanceof;
147 public String toString() {
148 return "BINOP " + myOperationSign;