-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvis.py
156 lines (130 loc) · 4.94 KB
/
vis.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import glob
import os
import re
import graphviz
RE_FIND_CLASS = r'\w+\.class'
RE_FIND_ADAPTER = r'new \w+\('
RE_FIND_INFLATED = r'R\.\w+\.\w+,'
RE_FIND_MAIN_LAYOUT = r'R\.\w+\.\w+\)'
layout_dir = "./app/src/main/res/layout/"
java_dir = "./app/src/main/java/com/example/nutritionapp/"
RELATIONS = [
"INFLATES"
"CONTAINS_ADAPTER"
"OPENS"
]
class Node:
def __init__(self, filename):
self.name = os.path.basename(filename)
self.filename = filename
self.jclass = None
self.xml = None
if filename.endswith(".java"):
self.jclass = self.name.replace(".java", ".class")
else:
self.xml = self.name
self.OPENS = []
self.CONTAINS_ADAPTER = []
self.INFLATES = []
self.LAYOUT = None
self.isXML = filename.endswith(".xml")
self.isAdapter = "Adapter" in filename
self.parents = []
def __eq__(self, node):
return self.filename == node.filename
def __hash__(self):
return hash(self.filename)
LIST_XML = {}
LIST_JAVA = {}
# get all files XML + java #
for filename in glob.iglob(java_dir + '**/**', recursive=True):
node = Node(filename)
LIST_JAVA.update({node.jclass : node})
for filename in glob.iglob(layout_dir + '**/**', recursive=True):
node = Node(filename)
LIST_XML.update({node.xml : node})
VISITED = {}
NODES = []
def rec(current):
with open(current.filename) as f:
for line in f:
# layout #
if "setContentView" in line:
match = re.search(RE_FIND_MAIN_LAYOUT, line)
if match:
xml = match.group().split('.')[-1].strip(')') + ".xml"
if xml in LIST_XML:
node = LIST_XML[xml]
current.LAYOUT = node
if not VISITED.get(xml):
VISITED.update({ xml : True })
node.parents.append(current)
rec(node)
print(xml)
# CONTAINS_ADAPTER #
if "new" in line and "Adapter" in line:
match = re.search(RE_FIND_ADAPTER, line)
if match:
jclass = match.group()[4:].strip('(') + ".class"
if jclass in LIST_JAVA:
node = LIST_JAVA[jclass]
current.CONTAINS_ADAPTER.append(node)
if not VISITED.get(jclass):
VISITED.update({ jclass : True })
node.parents.append(current)
rec(node)
print(jclass)
# opens #
if "new Intent(" in line:
match = jclass = re.search(RE_FIND_CLASS, line)
if match:
jclass = match.group()
node = LIST_JAVA[jclass]
current.OPENS.append(node)
node.parents.append(current)
if not VISITED.get(jclass):
VISITED.update({ jclass : True })
rec(node)
print(jclass)
# inflates #
if "inflate(" in line:
match = re.search(RE_FIND_INFLATED, line)
if match:
xml = match.group().split('.')[-1].strip(',') + ".xml"
node = LIST_XML[xml]
current.INFLATES.append(node)
node.parents.append(current)
if not VISITED.get(xml) and xml in LIST_XML:
VISITED.update({ xml : True })
print(xml)
# run analysis #
starting_node = LIST_JAVA["MainActivity.class"]
rec(starting_node)
def isParentOfParent(node, other):
return "Apdapter" in node.filename and (other in node.parents or any([other in p.parents for p in node.parents]))
VISTED_DOT = {}
def rec_dot(current, dot):
if VISTED_DOT.get(current):
return
VISTED_DOT.update({current : True})
for el in current.CONTAINS_ADAPTER:
dot.node(el.name, el.jclass, color="red")
dot.edge(current.name, el.name, label="CONTAINS_ADAPTER")
rec_dot(el, dot)
for el in current.OPENS:
if not isParentOfParent(current, el):
layout = ""
if el.LAYOUT:
layout = " \\n({})".format(el.LAYOUT.name)
dot.node(el.name, el.jclass + layout, color="green")
dot.edge(current.name, el.name, label="OPENS")
rec_dot(el, dot)
for el in current.INFLATES:
dot.node(el.name, el.jclass, color="blue")
dot.edge(current.name, el.name, label="INFLATES")
rec_dot(el, dot)
# genreate and render dot #
dot = graphviz.Graph('Overview', engine="neato", strict=True)
dot.attr(overlap='false')
rec_dot(starting_node, dot)
dot.render()