1
+ #!/usr/bin/env python
2
+
3
+ import os
4
+ import re
5
+ import json
6
+
7
+ level_re = re .compile (r'''(Forbid|Deny|Warn|Allow)''' )
8
+ conf_re = re .compile (r'''define_Conf! {\n([^}]*)\n}''' , re .MULTILINE )
9
+ confvar_re = re .compile (r'''/// Lint: (\w+). (.*).*\n *\("([^"]*)", (?:[^,]*), (.*) => (.*)\),''' )
10
+ lint_subheadline = re .compile (r'''^\*\*([\w\s]+)[:?.!]\*\*(.*)''' )
11
+
12
+ # TODO: actual logging
13
+ def warn (* args ): print (args )
14
+ def debug (* args ): print (args )
15
+ def info (* args ): print (args )
16
+
17
+ def parse_path (p = "clippy_lints/src" ):
18
+ d = []
19
+ for f in os .listdir (p ):
20
+ if f .endswith (".rs" ):
21
+ parse_file (d , os .path .join (p , f ))
22
+ return (d , parse_conf (p ))
23
+
24
+
25
+ def parse_conf (p ):
26
+ c = {}
27
+ with open (p + '/utils/conf.rs' ) as f :
28
+ f = f .read ()
29
+
30
+ m = re .search (conf_re , f )
31
+ m = m .groups ()[0 ]
32
+
33
+ m = re .findall (confvar_re , m )
34
+
35
+ for (lint , doc , name , default , ty ) in m :
36
+ c [lint .lower ()] = (name , ty , doc , default )
37
+
38
+ return c
39
+
40
+ def parseLintDef (level , comment , name ):
41
+ lint = {}
42
+ lint ['id' ] = name
43
+ lint ['level' ] = level
44
+ lint ['docs' ] = {}
45
+
46
+ last_section = None
47
+
48
+ for line in comment :
49
+ if len (line .strip ()) == 0 :
50
+ continue
51
+
52
+ match = re .match (lint_subheadline , line )
53
+ if match :
54
+ last_section = match .groups ()[0 ]
55
+ text = match and match .groups ()[1 ] or line
56
+
57
+ if not last_section :
58
+ warn ("Skipping comment line as it was not preceded by a heading" )
59
+ debug ("in lint `%s`, line `%s`" % name , line )
60
+
61
+ lint ['docs' ][last_section ] = (lint ['docs' ].get (last_section , "" ) + "\n " + text ).strip ()
62
+
63
+ return lint
64
+
65
+ def parse_file (d , f ):
66
+ last_comment = []
67
+ comment = True
68
+
69
+ with open (f ) as rs :
70
+ for line in rs :
71
+ if comment :
72
+ if line .startswith ("///" ):
73
+ if line .startswith ("/// " ):
74
+ last_comment .append (line [4 :])
75
+ else :
76
+ last_comment .append (line [3 :])
77
+ elif line .startswith ("declare_lint!" ):
78
+ comment = False
79
+ deprecated = False
80
+ restriction = False
81
+ elif line .startswith ("declare_restriction_lint!" ):
82
+ comment = False
83
+ deprecated = False
84
+ restriction = True
85
+ elif line .startswith ("declare_deprecated_lint!" ):
86
+ comment = False
87
+ deprecated = True
88
+ else :
89
+ last_comment = []
90
+ if not comment :
91
+ l = line .strip ()
92
+ m = re .search (r"pub\s+([A-Z_][A-Z_0-9]*)" , l )
93
+
94
+ if m :
95
+ name = m .group (1 ).lower ()
96
+
97
+ # Intentionally either a never looping or infinite loop
98
+ while not deprecated and not restriction :
99
+ m = re .search (level_re , line )
100
+ if m :
101
+ level = m .group (0 )
102
+ break
103
+
104
+ line = next (rs )
105
+
106
+ if deprecated :
107
+ level = "Deprecated"
108
+ elif restriction :
109
+ level = "Allow"
110
+
111
+ info ("found %s with level %s in %s" % (name , level , f ))
112
+ d .append (parseLintDef (level , last_comment , name = name ))
113
+ last_comment = []
114
+ comment = True
115
+ if "}" in l :
116
+ warn ("Warning: Missing Lint-Name in" , f )
117
+ comment = True
118
+
119
+ def main ():
120
+ (lints , config ) = parse_path ()
121
+ info ("got %s lints" % len (lints ))
122
+ with open ("util/gh-pages/lints.json" , "w" ) as file :
123
+ json .dump (lints , file , indent = 2 )
124
+ info ("wrote JSON for greate justice" )
125
+
126
+ if __name__ == "__main__" :
127
+ main ()
0 commit comments