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
|