This repository has been archived by the owner on Mar 15, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 81
/
DocCheck.jl
196 lines (176 loc) · 7.54 KB
/
DocCheck.jl
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# Julia utilities for checking documentation
# This file contains a number of functions for checking julia documentation
#
# isdeprecated(v) : test if v is deprecated
# isdocumented(v) : true if v is documented
# undefined_exports(m) : returns a list of undefined exports in module m
# undocumented(m) : returns a list of undocumented exports in module m
# undocumented_by_file(m) : returns a dictionary of undocumented exports,
# with file, function, and line number information
# undocumented_rst(m) : produce a list of undocumented function suitable for
# pasting into github issue #2242
module DocCheck
import Base.Help: init_help, FUNCTION_DICT, MODULE_DICT
import Base: argtype_decl, uncompressed_ast
export isdeprecated, isdocumented, undefined_exports, undocumented, undocumented_by_file, undocumented_rst,
gen_undocumented_template
isdeprecated(m::Module, v) = try endswith(functionloc(eval(m, v))[1], "deprecated.jl") catch return false end
isdeprecated(v) = try endswith(functionloc(eval(v))[1], "deprecated.jl") catch return false end
isdocumented(v) = (s=string(v); haskey(FUNCTION_DICT, s) || haskey(MODULE_DICT, s))
modfuncjoin(m::String, f::String) = beginswith(f, '@') ? "@$m.$(f[2:end])" : "$m.$f"
modfuncjoin(m, f) = modfuncjoin(string(m), string(f))
# return a list of undefined exports in a module
undefined_exports(m::Module) = sort(filter(x->!isdefined(x), names(m)))
undefined_exports() = undefined(Base)
# Check for exported names that aren't documented,
# and return a Dict with (fn::Symbol, fullname::String) pairs
function undocumented(m::Module)
init_help()
undoc = Dict{Symbol, Array}()
for v in sort(names(m))
if isdefined(m,v) && !isdocumented(v) && !isdeprecated(m,v)
ms = modfuncjoin(m,v)
haskey(undoc, v) ? push!(undoc[v], ms) : (undoc[v] = [ms])
end
end
undoc
end
undocumented() = undocumented(Base)
# Check for exported names that aren't documented, and
# return the file, function names, and line numbers, if available
function undocumented_by_file(m::Module)
init_help()
undocf = Dict{String, Dict}()
for (f,_) in undocumented(m)
s = string(f)
try
for (file, line) in functionlocs(eval(f))
if beginswith(file, JULIA_HOME)
file = replace(file, JULIA_HOME, "\$JULIA_HOME", 1)
end
if !haskey(undocf, file)
undocf[file] = Dict{String, Vector{Integer}}()
end
if !haskey(undocf[file], s)
undocf[file][s] = [line]
else
push!(undocf[file][s], line)
end
end
catch
if !haskey(undocf, "UNKNOWN_FILE")
undocf["UNKNOWN_FILE"] = Dict{String, Vector{Integer}}()
end
undocf["UNKNOWN_FILE"][s] = Integer[-1]
end
end
undocf
end
undocumented_by_file() = undocumented_by_file(Base)
# Unlike the above functions, this version parses base/exports.jl,
# because that file groups the functions in a more systematic manner.
# The output can be pasted into https://github.com/JuliaLang/julia/issues/2242
# This also only works with Base functions; the other "undocumented*"
# functions are more general.
# Based on code by @jihao
function _undocumented_rst()
init_help()
depdoc = havecount = total = 0
out = String["The following exports are not documented:"]
undoc_exports = Set()
exports=[strip(x) for x in split(replace(open(readall, "$JULIA_HOME/../../base/exports.jl"),",",""),"\n")]
for line in exports
if search(line, "deprecated")!=0:-1; continue end
if haskey(MODULE_DICT, line); havecount+=1; total+=1; continue end
if length(line)>1
if line[1]=='#'
if line[2]!= ' ' continue end
else
s = symbol(line) # for submodules: string(:Sort) == "Base.Sort"
if !isdefined(s) continue end
if haskey(FUNCTION_DICT, line) || haskey(MODULE_DICT, line)
m = eval(symbol(getkey(MODULE_DICT, line, "Base")))
isdeprecated(m,s) && continue
havecount+=1; total+=1; continue
end
push!(undoc_exports, line)
if line[1]=='@'; line = line[2:end] end
line=string("- [ ] ", line)
total+=1
end
end
push!(out, line)
end
append!(out, String["", "Documented and deprecated functions/exports (please update docs)", ""])
deprecated=[strip(x) for x in split(replace(open(readall, "$JULIA_HOME/../../base/deprecated.jl"),",",""),"\n")]
for line in deprecated
if beginswith(line, "@deprecated")
fn = split(line, r" +")[2]
if haskey(MODULE_DICT, fn); push!(out, string("- [ ] ", fn)); depdoc += 1 end
elseif beginswith(line, "export")
for fn in split(line, r"[ ,]+")[2:end]
if haskey(MODULE_DICT, fn); push!(out, string("- [ ]", fn)); depdoc += 1 end
end
end
end
prepend!(out, String["$havecount/$total exports have been documented",
"(Additionally, $depdoc deprecated functions are still documentated)",
""])
(join(out, "\n"), undoc_exports)
end
undocumented_rst() = println(_undocumented_rst()[1])
function gen_undocumented_template(outfile = "$JULIA_HOME/../../doc/UNDOCUMENTED.rst")
out = open(outfile, "w")
init_help()
println(out, ".. currentmodule:: Base")
println(out)
exports=[strip(x) for x in split(replace(open(readall, "$JULIA_HOME/../../base/exports.jl"),",",""),"\n")]
for line in exports
if search(line, "deprecated")!=0:-1; continue end
if haskey(MODULE_DICT, line); continue end
if length(line)>1
if line[1]=='#'
if line[2]!= ' ' continue end
println(out)
println(out, line[3:end])
println(out, repeat("-", length(line)-2))
println(out)
continue
else
s = symbol(line) # for submodules: string(:Sort) == "Base.Sort"
if !isdefined(s) continue end
if haskey(FUNCTION_DICT, line) || haskey(MODULE_DICT, line)
continue
end
if line[1]=='@'; line = line[2:end] end
sym = try eval(symbol(line)) catch :() end
if isa(sym, Function)
mt = methods(sym)
if length(mt) == 1 # easy case
m = mt.defs
li = m.func.code
e = uncompressed_ast(li)
argnames = e.args[1]
decls = map(argtype_decl, argnames, {m.sig...})
args = join(decls, ",")
line = line * "($args)"
else
line = line * "(...)"
end
println(out, ".. function:: "*line)
println(out)
println(out, " UNDOCUMENTED")
println(out)
elseif isa(sym, Module)
println(out, ".. module:: "*line)
println(out)
println(out, " UNDOCUMENTED (may not appear in helpdb.jl)")
println(out)
end
end
end
end
close(out)
nothing
end
end