2 * Created by IntelliJ IDEA.
6 * To change template for new class use
7 * Code Style | Class Templates options (Tools | IDE Options).
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
) {
33 if (opSign
!= null && ("==".equals(opSign
) || "!=".equals(opSign
) || "instanceof".equals(opSign
) || "+".equals(opSign
))) {
34 myOperationSign
= opSign
;
35 if (!"instanceof".equals(opSign
)) myIsInstanceofRedundant
= false;
38 myOperationSign
= null;
39 myIsInstanceofRedundant
= false;
42 setPsiAnchor(psiAnchor
);
45 public DfaInstructionState
[] apply(DataFlowRunner runner
, DfaMemoryState memState
) {
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());
62 memState
.push(factory
.getConstFactory().getFalse());
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());
78 states
.add(new DfaInstructionState(next
, trueCopy
));
81 DfaMemoryState falseCopy
= memState
;
82 if (falseCopy
.applyCondition(dfaRelation
.createNegated())) {
83 falseCopy
.push(factory
.getConstFactory().getFalse());
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.
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();
107 leftType
= ((DfaTypeValue
)dfaLeft
).getType();
108 myCanBeNullInInstanceof
= true;
111 if (!((DfaTypeValue
)dfaRight
).getType().isAssignableFrom(leftType
)) {
112 myIsInstanceofRedundant
= false;
116 myIsInstanceofRedundant
= false;
118 memState
.push(DfaUnknownValue
.getInstance());
122 memState
.push(DfaUnknownValue
.getInstance());
125 return new DfaInstructionState
[]{new DfaInstructionState(next
, memState
)};
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
;