2 * Copyright 2000-2009 JetBrains s.r.o.
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
.intellij
.codeInspection
.dataFlow
;
18 import com
.intellij
.codeInspection
.dataFlow
.instructions
.*;
19 import com
.intellij
.codeInspection
.dataFlow
.value
.DfaUnknownValue
;
20 import com
.intellij
.codeInspection
.dataFlow
.value
.DfaVariableValue
;
21 import com
.intellij
.codeInspection
.dataFlow
.value
.DfaValue
;
22 import com
.intellij
.psi
.PsiExpression
;
24 import java
.util
.ArrayList
;
29 public abstract class InstructionVisitor
{
31 public DfaInstructionState
[] visitAssign(AssignInstruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
33 memState
.push(memState
.pop());
34 return nextInstruction(instruction
, runner
, memState
);
37 protected static DfaInstructionState
[] nextInstruction(Instruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
38 return new DfaInstructionState
[]{new DfaInstructionState(runner
.getInstruction(instruction
.getIndex() + 1), memState
)};
41 public DfaInstructionState
[] visitInstanceof(InstanceofInstruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
42 return visitBinop(instruction
, runner
, memState
);
45 public DfaInstructionState
[] visitBinop(BinopInstruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
48 memState
.push(DfaUnknownValue
.getInstance());
49 return nextInstruction(instruction
, runner
, memState
);
52 public DfaInstructionState
[] visitCheckReturnValue(CheckReturnValueInstruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
54 return nextInstruction(instruction
, runner
, memState
);
57 public DfaInstructionState
[] visitConditionalGoto(ConditionalGotoInstruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
58 DfaValue cond
= memState
.pop();
63 if (instruction
.isNegated()) {
65 condTrue
= cond
.createNegated();
68 condFalse
= cond
.createNegated();
71 if (condTrue
== runner
.getFactory().getConstFactory().getTrue()) {
72 markBranchReachable(instruction
, true);
73 return new DfaInstructionState
[] {new DfaInstructionState(runner
.getInstruction(instruction
.getOffset()), memState
)};
76 if (condFalse
== runner
.getFactory().getConstFactory().getTrue()) {
77 markBranchReachable(instruction
, false);
78 return nextInstruction(instruction
, runner
, memState
);
81 ArrayList
<DfaInstructionState
> result
= new ArrayList
<DfaInstructionState
>();
83 DfaMemoryState thenState
= memState
.createCopy();
84 DfaMemoryState elseState
= memState
.createCopy();
86 if (thenState
.applyCondition(condTrue
)) {
87 result
.add(new DfaInstructionState(runner
.getInstruction(instruction
.getOffset()), thenState
));
88 markBranchReachable(instruction
, true);
91 if (elseState
.applyCondition(condFalse
)) {
92 result
.add(new DfaInstructionState(runner
.getInstruction(instruction
.getIndex() + 1), elseState
));
93 markBranchReachable(instruction
, false);
96 return result
.toArray(new DfaInstructionState
[result
.size()]);
99 private static void markBranchReachable(ConditionalGotoInstruction instruction
, boolean isTrueBranch
) {
100 if (isTrueBranch ^ instruction
.isNegated()) {
101 instruction
.setTrueReachable();
104 instruction
.setFalseReachable();
109 public DfaInstructionState
[] visitEmptyStack(EmptyStackInstruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
110 memState
.emptyStack();
111 return nextInstruction(instruction
, runner
, memState
);
114 public DfaInstructionState
[] visitFieldReference(FieldReferenceInstruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
116 return nextInstruction(instruction
, runner
, memState
);
119 public DfaInstructionState
[] visitFlushVariable(FlushVariableInstruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
120 final DfaVariableValue variable
= instruction
.getVariable();
121 if (variable
!= null) {
122 memState
.flushVariable(variable
);
124 memState
.flushFields(runner
);
126 return nextInstruction(instruction
, runner
, memState
);
129 public DfaInstructionState
[] visitMethodCall(MethodCallInstruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
130 //noinspection UnusedDeclaration
131 for (PsiExpression arg
: instruction
.getArgs()) {
135 memState
.pop(); //qualifier
136 memState
.push(DfaUnknownValue
.getInstance());
137 return nextInstruction(instruction
, runner
, memState
);
140 public DfaInstructionState
[] visitCast(MethodCallInstruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
141 return visitMethodCall(instruction
, runner
, memState
);
144 public DfaInstructionState
[] visitNot(NotInstruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
145 DfaValue dfaValue
= memState
.pop();
147 dfaValue
= dfaValue
.createNegated();
148 memState
.push(dfaValue
);
149 return nextInstruction(instruction
, runner
, memState
);
152 public DfaInstructionState
[] visitPush(PushInstruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
153 memState
.push(instruction
.getValue());
154 return nextInstruction(instruction
, runner
, memState
);
157 public DfaInstructionState
[] visitTypeCast(TypeCastInstruction instruction
, DataFlowRunner runner
, DfaMemoryState memState
) {
158 return nextInstruction(instruction
, runner
, memState
);