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
|
#!/usr/bin/python
# -*- python -*-
import sys
def identifier_start(string, startpos=0):
#print string, startpos
while (startpos < len(string) and
("() \t\r\n.,".find(string[startpos]) != -1)):
startpos = startpos + 1
return startpos
def identifier_end(string, startpos=0):
#print string, startpos
while (startpos < len(string) and
("() \t\r\n.,".find(string[startpos]) == -1)):
startpos = startpos + 1
return startpos
class Def:
def __init__(self, filename, lineno, autoload, symbol):
self.filename = filename
self.lineno = lineno
self.autoload = autoload
self.symbol = symbol
def __str__(self):
return ("%s:%d %s %s" % (self.filename,
self.lineno,
self.symbol,
self.autoload))
def find_defs(filename, pattern="(defun", pos=0):
"""Find definitions of pattern in the given file.
Returns defined symbols."""
symbols = []
fd = open(filename)
lineno = 0
autoload = False
for l in fd:
lineno = lineno + 1
if l.startswith(";;;###autoload"):
autoload = True
continue
s = l.find(pattern)
if s == -1 or s != pos:
continue
s = identifier_start(l, s + len(pattern))
while "() \t\r\n.,".find(l[s]) != -1:
s = s + 1
e = identifier_end(l, s)
if s == e:
raise "Could not find identifier end in " + repr(l)
continue
#print s, e
#print l[s : e]
symbols.append(Def(filename, lineno, autoload, l[s : e]))
autoload = False
fd.close()
return symbols
preloaded = ["vm-version.el", "vm-misc.el", "vm-macro.el", "vm-folder.el",
"vm-summary.el", "vm-minibuf.el", "vm-motion.el", "vm-page.el",
"vm-mouse.el", "vm-window.el", "vm-menu.el", "vm-message.el",
"vm-toolbar.el", "vm.el", "vm-undo.el", "vm-mime.el",
"vm-vars.el"]
def check_calls(filename, funs, missing):
#print "-" * 50
#print filename
fd = open(filename)
required = []
for l in fd:
s = l.find("(require")
if s != -1:
s = identifier_start(l, s + len("(require '" ))
e = identifier_end(l, s)
#print l[s:e], "*" * 50
required.append(l[s:e] + ".el")
#print required
continue
# check for calls to external function without autoloads or require
for c in l.split("("):
s = identifier_start(c, 0)
e = identifier_end(c, s)
#print repr(c)
s = identifier_start(c, 0)
e = identifier_end(c, s)
f = c[s:e]
if f not in funs:
continue
d = funs[f]
if ((d.filename != filename) and (not d.autoload) and
(d.filename not in preloaded) and
(d.filename not in required)):
#print preloaded
#print "'%s' : '%s' => '%s' %s" % (filename, f, d.filename,
#d.filename in preloaded)
#print preloaded
if not missing.has_key(d.filename):
missing[d.filename] = []
if f not in missing[d.filename]:
missing[d.filename].append(f)
fd.close()
# emit cross references with missing autoloads
if __name__ == '__main__':
funs = {}
for filename in sys.argv[3:]:
for d in find_defs(filename):
if funs.has_key(d.symbol):
print "Duplicate %s <> %s" % (d, funs[d.symbol])
else:
funs[d.symbol] = d
missing = {}
for filename in sys.argv[3:]:
check_calls(filename, funs, missing)
for f in missing.keys():
print f
for m in missing[f]:
print "\t", m
|