/* * 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.DfaValue; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; 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<>(); 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) { if (instruction.isDependentsOnly()) { for (DfaVariableValue qualified : runner.getFactory().getVarFactory().getAllQualifiedBy(variable)) { memState.flushVariable(qualified); } } else { 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[] visitArrayAccess(ArrayAccessInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) { memState.pop(); // index memState.pop(); // array reference 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); } }