# pylint:disable=arguments-renamed,too-many-boolean-expressionsfrom__future__importannotationsfromtypingimportAnyimportailmentfromailment.expressionimportOpfromangr.analyses.decompiler.structuring.structurer_nodesimportConditionNodefromangr.analyses.decompiler.utilsimportstructured_node_is_simple_return,sequence_to_statementsfromangr.analyses.decompiler.sequence_walkerimportSequenceWalkerfrom.optimization_passimportSequenceOptimizationPass,OptimizationPassStageclassFlipBooleanWalker(SequenceWalker):""" Walks a SequenceNode and handles every sequence. Uses the flip_size to determine when to flip the condition on large if-statement bodies. """def__init__(self,graph,flip_size=10,last_node=None):super().__init__()self._graph=graphself._last_node=last_nodeself._flip_size=flip_sizedef_handle_Sequence(self,seq_node,**kwargs):# Type 1:# if (cond) { ... } else { return; } --> if (!cond) { return; } else { ... }## Type 2:# if (cond) { ... } return; --> if (!cond) return; ...type1_condition_nodes=[nodefornodeinseq_node.nodesifisinstance(node,ConditionNode)andnode.false_node]type2_condition_nodes:list[tuple[int,ConditionNode,Any]]=[]iflen(seq_node.nodes)>=2:idx=len(seq_node.nodes)-2node=seq_node.nodes[idx]if(isinstance(node,ConditionNode)andnode.true_nodeisnotNoneandnode.false_nodeisNoneandidx<len(seq_node.nodes)-1andstructured_node_is_simple_return(seq_node.nodes[idx+1],self._graph)andnodenotintype1_condition_nodes):type2_condition_nodes.append((idx,node,seq_node.nodes[idx+1]))fornodeintype1_condition_nodes:ifisinstance(node.condition,Op)andstructured_node_is_simple_return(node.false_node,self._graph):node.condition=ailment.expression.negate(node.condition)node.true_node,node.false_node=node.false_node,node.true_nodeforidx,cond_node,successorintype2_condition_nodes:# there are two possibilities when you might want to flip the condition and move the return statement:# 1. This if-stmt if found somewhere in the middle of the function# 2. This if-stmt is pretty large, but still ends in a return outside of the if-stmtif(successorisnotself._last_node)or(len(sequence_to_statements(cond_node.true_node))>=self._flip_size):cond_node.condition=ailment.expression.negate(cond_node.condition)seq_node.nodes[idx+1]=cond_node.true_nodecond_node.true_node=successorreturnsuper()._handle_Sequence(seq_node,**kwargs)
[文档]classFlipBooleanCmp(SequenceOptimizationPass):""" In the scenario in which a false node has no apparent successors, flip the condition on that if-stmt. This is only useful when StructuredCodeGenerator has simplify_else_scopes enabled, as this will allow the flipped if-stmt to remove the redundant else. """ARCHES=NonePLATFORMS=NoneSTAGE=OptimizationPassStage.AFTER_STRUCTURINGNAME="Flip small ret booleans"DESCRIPTION="When false node has no successors, flip condition so else scope can be simplified later"