# Path: androguard/decompiler/dad/instruction.py
# class Variable(IRForm):
#     def __init__(self, value):
#         self.v = value
#         self.declared = False
#         self.type = None
#         self.name = value
# 
#     def get_used_vars(self):
#         return [self.v]
# 
#     def is_ident(self):
#         return True
# 
#     def value(self):
#         return self.v
# 
#     def visit(self, visitor):
#         return visitor.visit_variable(self)
# 
#     def visit_decl(self, visitor):
#         return visitor.visit_decl(self)
# 
#     def __str__(self):
#         return 'VAR_%s' % self.name
# 
# class ThisParam(Param):
#     def __init__(self, value, atype):
#         super().__init__(value, atype)
#         self.this = True
#         self.super = False
# 
#     def visit(self, visitor):
#         if self.super:
#             return visitor.visit_super()
#         return visitor.visit_this()
# 
#     def __str__(self):
#         return 'THIS'
# 
# class Param(Variable):
#     def __init__(self, value, atype):
#         super().__init__(value)
#         self.declared = True
#         self.type = atype
#         self.this = False
# 
#     def is_const(self):
#         return True
# 
#     def visit(self, visitor):
#         return visitor.visit_param(self.v, data=self.type)
# 
#     def __str__(self):
#         return 'PARAM_%s' % self.name
# 
# Path: androguard/decompiler/dad/util.py
# def build_path(graph, node1, node2, path=None):
#     """
#     Build the path from node1 to node2.
#     The path is composed of all the nodes between node1 and node2,
#     node1 excluded. Although if there is a loop starting from node1, it will be
#     included in the path.
#     """
#     if path is None:
#         path = []
#     if node1 is node2:
#         return path
#     path.append(node2)
#     for pred in graph.all_preds(node2):
#         if pred in path:
#             continue
#         build_path(graph, node1, pred, path)
#     return path
# 
# def common_dom(idom, cur, pred):
#     if not (cur and pred):
#         return cur or pred
#     while cur is not pred:
#         while cur.num < pred.num:
#             pred = idom[pred]
#         while cur.num > pred.num:
#             cur = idom[cur]
#     return cur
# 
# Path: androguard/decompiler/dad/node.py
# class Node:
#     def __init__(self, name):
#         self.name = name
#         self.num = 0
#         self.follow = {'if': None, 'loop': None, 'switch': None}
#         self.looptype = LoopType()
#         self.type = NodeType()
#         self.in_catch = False
#         self.interval = None
#         self.startloop = False
#         self.latch = None
#         self.loop_nodes = []
# 
#     def copy_from(self, node):
#         self.num = node.num
#         self.looptype = node.looptype.copy()
#         self.interval = node.interval
#         self.startloop = node.startloop
#         self.type = node.type.copy()
#         self.follow = node.follow.copy()
#         self.latch = node.latch
#         self.loop_nodes = node.loop_nodes
#         self.in_catch = node.in_catch
# 
#     def update_attribute_with(self, n_map):
#         self.latch = n_map.get(self.latch, self.latch)
#         for follow_type, value in self.follow.items():
#             self.follow[follow_type] = n_map.get(value, value)
#         self.loop_nodes = list({n_map.get(n, n) for n in self.loop_nodes})
# 
#     def get_head(self):
#         return self
# 
#     def get_end(self):
#         return self
# 
#     def __repr__(self):
#         return '%s' % self


import logging
from collections import defaultdict
from androguard.decompiler.dad.instruction import (Variable, ThisParam, Param)
from androguard.decompiler.dad.util import build_path, common_dom
from androguard.decompiler.dad.node import Node
                # e.g: a 'double' stored in v3 is also present in v4, so a call
                # to foo(v3), will in fact call foo(v3, v4).
                if var not in analysis.def_to_loc:
                    continue
                ldefs = analysis.defs[node]
                prior_def = -1
                for v in ldefs.get(var, set()):
                    if prior_def < v < i:
                        prior_def = v
                if prior_def >= 0:
                    UD[var, i].append(prior_def)
                else:
                    intersect = analysis.def_to_loc[var].intersection(
                        analysis.R[node])
                    UD[var, i].extend(intersect)
    DU = defaultdict(list)
    for var_loc, defs_loc in UD.items():
        var, loc = var_loc
        for def_loc in defs_loc:
            DU[var, def_loc].append(loc)

    return UD, DU


def place_declarations(graph, dvars, du, ud):
    idom = graph.immediate_dominators()
    for node in graph.post_order():
        for loc, ins in node.get_loc_with_ins():
            for var in ins.get_used_vars():
                if (not isinstance(dvars[var], Variable) or

# Path: androguard/decompiler/dad/instruction.py
# class Variable(IRForm):
#     def __init__(self, value):
#         self.v = value
#         self.declared = False
#         self.type = None
#         self.name = value
# 
#     def get_used_vars(self):
#         return [self.v]
# 
#     def is_ident(self):
#         return True
# 
#     def value(self):
#         return self.v
# 
#     def visit(self, visitor):
#         return visitor.visit_variable(self)
# 
#     def visit_decl(self, visitor):
#         return visitor.visit_decl(self)
# 
#     def __str__(self):
#         return 'VAR_%s' % self.name
# 
# class ThisParam(Param):
#     def __init__(self, value, atype):
#         super().__init__(value, atype)
#         self.this = True
#         self.super = False
# 
#     def visit(self, visitor):
#         if self.super:
#             return visitor.visit_super()
#         return visitor.visit_this()
# 
#     def __str__(self):
#         return 'THIS'
# 
# class Param(Variable):
#     def __init__(self, value, atype):
#         super().__init__(value)
#         self.declared = True
#         self.type = atype
#         self.this = False
# 
#     def is_const(self):
#         return True
# 
#     def visit(self, visitor):
#         return visitor.visit_param(self.v, data=self.type)
# 
#     def __str__(self):
#         return 'PARAM_%s' % self.name
# 
# Path: androguard/decompiler/dad/util.py
# def build_path(graph, node1, node2, path=None):
#     """
#     Build the path from node1 to node2.
#     The path is composed of all the nodes between node1 and node2,
#     node1 excluded. Although if there is a loop starting from node1, it will be
#     included in the path.
#     """
#     if path is None:
#         path = []
#     if node1 is node2:
#         return path
#     path.append(node2)
#     for pred in graph.all_preds(node2):
#         if pred in path:
#             continue
#         build_path(graph, node1, pred, path)
#     return path
# 
# def common_dom(idom, cur, pred):
#     if not (cur and pred):
#         return cur or pred
#     while cur is not pred:
#         while cur.num < pred.num:
#             pred = idom[pred]
#         while cur.num > pred.num:
#             cur = idom[cur]
#     return cur
# 
# Path: androguard/decompiler/dad/node.py
# class Node:
#     def __init__(self, name):
#         self.name = name
#         self.num = 0
#         self.follow = {'if': None, 'loop': None, 'switch': None}
#         self.looptype = LoopType()
#         self.type = NodeType()
#         self.in_catch = False
#         self.interval = None
#         self.startloop = False
#         self.latch = None
#         self.loop_nodes = []
# 
#     def copy_from(self, node):
#         self.num = node.num
#         self.looptype = node.looptype.copy()
#         self.interval = node.interval
#         self.startloop = node.startloop
#         self.type = node.type.copy()
#         self.follow = node.follow.copy()
#         self.latch = node.latch
#         self.loop_nodes = node.loop_nodes
#         self.in_catch = node.in_catch
# 
#     def update_attribute_with(self, n_map):
#         self.latch = n_map.get(self.latch, self.latch)
#         for follow_type, value in self.follow.items():
#             self.follow[follow_type] = n_map.get(value, value)
#         self.loop_nodes = list({n_map.get(n, n) for n in self.loop_nodes})
# 
#     def get_head(self):
#         return self
# 
#     def get_end(self):
#         return self
# 
#     def __repr__(self):
#         return '%s' % self


# Path: androguard/decompiler/dad/dataflow.py
import logging
from collections import defaultdict
from androguard.decompiler.dad.instruction import (Variable, ThisParam, Param)
from androguard.decompiler.dad.util import build_path, common_dom
from androguard.decompiler.dad.node import Node

                # e.g: a 'double' stored in v3 is also present in v4, so a call
                # to foo(v3), will in fact call foo(v3, v4).
                if var not in analysis.def_to_loc:
                    continue
                ldefs = analysis.defs[node]
                prior_def = -1
                for v in ldefs.get(var, set()):
                    if prior_def < v < i:
                        prior_def = v
                if prior_def >= 0:
                    UD[var, i].append(prior_def)
                else:
                    intersect = analysis.def_to_loc[var].intersection(
                        analysis.R[node])
                    UD[var, i].extend(intersect)
    DU = defaultdict(list)
    for var_loc, defs_loc in UD.items():
        var, loc = var_loc
        for def_loc in defs_loc:
            DU[var, def_loc].append(loc)

    return UD, DU


def place_declarations(graph, dvars, du, ud):
    idom = graph.immediate_dominators()
    for node in graph.post_order():
        for loc, ins in node.get_loc_with_ins():
            for var in ins.get_used_vars():
                if (not isinstance(dvars[var], Variable) or

                        isinstance(dvars[var], Param)):