blob: a714f1e75b5adc054363994ef729ffe0a9c954a3 [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInspection.dataFlow;
import com.intellij.codeInspection.dataFlow.instructions.*;
import com.intellij.codeInspection.dataFlow.value.DfaUnknownValue;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.psi.PsiExpression;
import java.util.ArrayList;
/**
* @author peter
*/
public abstract class InstructionVisitor {
public DfaInstructionState[] visitAssign(AssignInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
memState.pop();
memState.push(memState.pop());
return nextInstruction(instruction, runner, memState);
}
protected static DfaInstructionState[] nextInstruction(Instruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
return new DfaInstructionState[]{new DfaInstructionState(runner.getInstruction(instruction.getIndex() + 1), memState)};
}
public DfaInstructionState[] visitInstanceof(InstanceofInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
return visitBinop(instruction, runner, memState);
}
public DfaInstructionState[] visitBinop(BinopInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
memState.pop();
memState.pop();
memState.push(DfaUnknownValue.getInstance());
return nextInstruction(instruction, runner, memState);
}
public DfaInstructionState[] visitCheckReturnValue(CheckReturnValueInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
memState.pop();
return nextInstruction(instruction, runner, memState);
}
public DfaInstructionState[] visitLambdaExpression(LambdaInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
return nextInstruction(instruction, runner, memState);
}
public DfaInstructionState[] visitConditionalGoto(ConditionalGotoInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
DfaValue cond = memState.pop();
DfaValue condTrue;
DfaValue condFalse;
if (instruction.isNegated()) {
condFalse = cond;
condTrue = cond.createNegated();
} else {
condTrue = cond;
condFalse = cond.createNegated();
}
if (condTrue == runner.getFactory().getConstFactory().getTrue()) {
markBranchReachable(instruction, true);
return new DfaInstructionState[] {new DfaInstructionState(runner.getInstruction(instruction.getOffset()), memState)};
}
if (condFalse == runner.getFactory().getConstFactory().getTrue()) {
markBranchReachable(instruction, false);
return nextInstruction(instruction, runner, memState);
}
ArrayList<DfaInstructionState> result = new ArrayList<DfaInstructionState>();
DfaMemoryState thenState = memState.createCopy();
DfaMemoryState elseState = memState.createCopy();
if (thenState.applyCondition(condTrue)) {
result.add(new DfaInstructionState(runner.getInstruction(instruction.getOffset()), thenState));
markBranchReachable(instruction, true);
}
if (elseState.applyCondition(condFalse)) {
result.add(new DfaInstructionState(runner.getInstruction(instruction.getIndex() + 1), elseState));
markBranchReachable(instruction, false);
}
return result.toArray(new DfaInstructionState[result.size()]);
}
private static void markBranchReachable(ConditionalGotoInstruction instruction, boolean isTrueBranch) {
if (isTrueBranch ^ instruction.isNegated()) {
instruction.setTrueReachable();
}
else {
instruction.setFalseReachable();
}
}
public DfaInstructionState[] visitEmptyStack(EmptyStackInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
memState.emptyStack();
return nextInstruction(instruction, runner, memState);
}
public DfaInstructionState[] visitFieldReference(FieldReferenceInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
memState.pop();
return nextInstruction(instruction, runner, memState);
}
public DfaInstructionState[] visitFlushVariable(FlushVariableInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
final DfaVariableValue variable = instruction.getVariable();
if (variable != null) {
memState.flushVariable(variable);
} else {
memState.flushFields();
}
return nextInstruction(instruction, runner, memState);
}
public DfaInstructionState[] visitMethodCall(MethodCallInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
//noinspection UnusedDeclaration
for (PsiExpression arg : instruction.getArgs()) {
memState.pop();
}
memState.pop(); //qualifier
memState.push(DfaUnknownValue.getInstance());
return nextInstruction(instruction, runner, memState);
}
public DfaInstructionState[] visitCast(MethodCallInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
return visitMethodCall(instruction, runner, memState);
}
public DfaInstructionState[] visitNot(NotInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
DfaValue dfaValue = memState.pop();
dfaValue = dfaValue.createNegated();
memState.push(dfaValue);
return nextInstruction(instruction, runner, memState);
}
public DfaInstructionState[] visitPush(PushInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
memState.push(instruction.getValue());
return nextInstruction(instruction, runner, memState);
}
public DfaInstructionState[] visitTypeCast(TypeCastInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
return nextInstruction(instruction, runner, memState);
}
public DfaInstructionState[] visitEmptyInstruction(EmptyInstruction instruction, DataFlowRunner runner, DfaMemoryState before) {
return nextInstruction(instruction, runner, before);
}
}