analyze.scm 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468
  1. ;;; Diagnostic warnings for Tree-IL
  2. ;; Copyright (C) 2001,2008-2014,2016,2018-2024 Free Software Foundation, Inc.
  3. ;;;; This library is free software; you can redistribute it and/or
  4. ;;;; modify it under the terms of the GNU Lesser General Public
  5. ;;;; License as published by the Free Software Foundation; either
  6. ;;;; version 3 of the License, or (at your option) any later version.
  7. ;;;;
  8. ;;;; This library is distributed in the hope that it will be useful,
  9. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;;; Lesser General Public License for more details.
  12. ;;;;
  13. ;;;; You should have received a copy of the GNU Lesser General Public
  14. ;;;; License along with this library; if not, write to the Free Software
  15. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. ;;; Code:
  17. (define-module (language tree-il analyze)
  18. #:use-module (srfi srfi-1)
  19. #:use-module (srfi srfi-9)
  20. #:use-module (srfi srfi-11)
  21. #:use-module (srfi srfi-26)
  22. #:use-module (ice-9 vlist)
  23. #:use-module (ice-9 match)
  24. #:use-module (system base syntax)
  25. #:use-module (system base message)
  26. #:use-module (system vm program)
  27. #:use-module (language tree-il)
  28. #:use-module (system base pmatch)
  29. #:export (analyze-tree
  30. unused-variable-analysis
  31. unused-toplevel-analysis
  32. shadowed-toplevel-analysis
  33. make-use-before-definition-analysis
  34. arity-analysis
  35. format-analysis
  36. make-analyzer))
  37. ;;;
  38. ;;; Tree analyses for warnings.
  39. ;;;
  40. (define-record-type <tree-analysis>
  41. (make-tree-analysis down up post init)
  42. tree-analysis?
  43. (down tree-analysis-down) ;; (lambda (x result env locs) ...)
  44. (up tree-analysis-up) ;; (lambda (x result env locs) ...)
  45. (post tree-analysis-post) ;; (lambda (result env) ...)
  46. (init tree-analysis-init)) ;; arbitrary value
  47. (define (analyze-tree analyses tree env)
  48. "Run all tree analyses listed in ANALYSES on TREE for ENV, using
  49. `tree-il-fold'. Return TREE. The down and up procedures of each
  50. analysis are passed a ``location stack', which is the stack of
  51. `tree-il-src' values for each parent tree (a list); it can be used to
  52. approximate source location when accurate information is missing from a
  53. given `tree-il' element."
  54. (define (traverse proc update-locs)
  55. ;; Return a tree traversing procedure that returns a list of analysis
  56. ;; results prepended by the location stack.
  57. (lambda (x results)
  58. (let ((locs (update-locs x (car results))))
  59. (cons locs ;; the location stack
  60. (map (lambda (analysis result)
  61. ((proc analysis) x result env locs))
  62. analyses
  63. (cdr results))))))
  64. ;; Extending and shrinking the location stack.
  65. (define (extend-locs x locs) (cons (tree-il-srcv x) locs))
  66. (define (shrink-locs x locs) (cdr locs))
  67. (let ((results
  68. (tree-il-fold (traverse tree-analysis-down extend-locs)
  69. (traverse tree-analysis-up shrink-locs)
  70. (cons '() ;; empty location stack
  71. (map tree-analysis-init analyses))
  72. tree)))
  73. (for-each (lambda (analysis result)
  74. ((tree-analysis-post analysis) result env))
  75. analyses
  76. (cdr results)))
  77. tree)
  78. ;;;
  79. ;;; Unused variable analysis.
  80. ;;;
  81. ;; <binding-info> records are used during tree traversals in
  82. ;; `unused-variable-analysis'. They contain a list of the local vars
  83. ;; currently in scope, and a list of locals vars that have been referenced.
  84. (define-record-type <binding-info>
  85. (make-binding-info vars refs)
  86. binding-info?
  87. (vars binding-info-vars) ;; ((GENSYM NAME LOCATION) ...)
  88. (refs binding-info-refs)) ;; (GENSYM ...)
  89. (define (gensym? sym)
  90. ;; Return #t if SYM is (likely) a generated symbol.
  91. (string-any #\space (symbol->string sym)))
  92. (define unused-variable-analysis
  93. ;; Report unused variables in the given tree.
  94. (make-tree-analysis
  95. (lambda (x info env locs)
  96. ;; Going down into X: extend INFO's variable list
  97. ;; accordingly.
  98. (let ((refs (binding-info-refs info))
  99. (vars (binding-info-vars info))
  100. (src (tree-il-srcv x)))
  101. (define (extend inner-vars inner-names)
  102. (fold (lambda (var name vars)
  103. (vhash-consq var (list name src) vars))
  104. vars
  105. inner-vars
  106. inner-names))
  107. (match x
  108. (($ <lexical-ref> src name gensym)
  109. (make-binding-info vars (vhash-consq gensym #t refs)))
  110. (($ <lexical-set> src name gensym)
  111. (make-binding-info vars (vhash-consq gensym #t refs)))
  112. (($ <lambda-case> src req opt rest kw inits gensyms body alt)
  113. (let ((names `(,@req
  114. ,@opt
  115. ,@(if rest (list rest) '())
  116. ,@(if kw (map cadr (cdr kw)) '()))))
  117. (make-binding-info (extend gensyms names) refs)))
  118. (($ <let> src names gensyms)
  119. (make-binding-info (extend gensyms names) refs))
  120. (($ <letrec> src in-order? names gensyms)
  121. (make-binding-info (extend gensyms names) refs))
  122. (($ <fix> src names gensyms)
  123. (make-binding-info (extend gensyms names) refs))
  124. (_ info))))
  125. (lambda (x info env locs)
  126. ;; Leaving X's scope: shrink INFO's variable list
  127. ;; accordingly and reported unused nested variables.
  128. (let ((refs (binding-info-refs info))
  129. (vars (binding-info-vars info)))
  130. (define (shrink inner-vars refs)
  131. (vlist-for-each
  132. (lambda (var)
  133. (let ((gensym (car var)))
  134. ;; Don't report lambda parameters as unused.
  135. (if (and (memq gensym inner-vars)
  136. (not (vhash-assq gensym refs))
  137. (not (lambda-case? x)))
  138. (let ((name (cadr var))
  139. ;; We can get approximate source location by going up
  140. ;; the LOCS location stack.
  141. (loc (or (caddr var)
  142. (find pair? locs))))
  143. (if (and (not (gensym? name))
  144. (not (eq? name '_)))
  145. (warning 'unused-variable loc name))))))
  146. vars)
  147. (vlist-drop vars (length inner-vars)))
  148. ;; For simplicity, we leave REFS untouched, i.e., with
  149. ;; names of variables that are now going out of scope.
  150. ;; It doesn't hurt as these are unique names, it just
  151. ;; makes REFS unnecessarily fat.
  152. (match x
  153. (($ <lambda-case> src req opt rest kw inits gensyms)
  154. (make-binding-info (shrink gensyms refs) refs))
  155. (($ <let> src names gensyms)
  156. (make-binding-info (shrink gensyms refs) refs))
  157. (($ <letrec> src in-order? names gensyms)
  158. (make-binding-info (shrink gensyms refs) refs))
  159. (($ <fix> src names gensyms)
  160. (make-binding-info (shrink gensyms refs) refs))
  161. (_ info))))
  162. (lambda (result env) #t)
  163. (make-binding-info vlist-null vlist-null)))
  164. ;;;
  165. ;;; Unused top-level variable analysis.
  166. ;;;
  167. ;; <reference-graph> record top-level definitions that are made, references to
  168. ;; top-level definitions and their context (the top-level definition in which
  169. ;; the reference appears), as well as the current context (the top-level
  170. ;; definition we're currently in). The second part (`refs' below) is
  171. ;; effectively a graph from which we can determine unused top-level definitions.
  172. (define-record-type <reference-graph>
  173. (make-reference-graph defs refs toplevel-context)
  174. reference-graph?
  175. (defs reference-graph-defs) ;; ((NAME . LOC) ...)
  176. (refs reference-graph-refs) ;; ((REF-CONTEXT REF ...) ...)
  177. (toplevel-context reference-graph-toplevel-context)) ;; NAME | #f
  178. (define (graph-reachable-nodes root refs reachable)
  179. ;; Add to REACHABLE the nodes reachable from ROOT in graph REFS. REFS is a
  180. ;; vhash mapping nodes to the list of their children: for instance,
  181. ;; ((A -> (B C)) (B -> (A)) (C -> ())) corresponds to
  182. ;;
  183. ;; ,-------.
  184. ;; v |
  185. ;; A ----> B
  186. ;; |
  187. ;; v
  188. ;; C
  189. ;;
  190. ;; REACHABLE is a vhash of nodes known to be otherwise reachable.
  191. (let loop ((root root)
  192. (path vlist-null)
  193. (result reachable))
  194. (if (or (vhash-assq root path)
  195. (vhash-assq root result))
  196. result
  197. (let* ((children (or (and=> (vhash-assq root refs) cdr) '()))
  198. (path (vhash-consq root #t path))
  199. (result (fold (lambda (kid result)
  200. (loop kid path result))
  201. result
  202. children)))
  203. (fold (lambda (kid result)
  204. (vhash-consq kid #t result))
  205. result
  206. children)))))
  207. (define (graph-reachable-nodes* roots refs)
  208. ;; Return the list of nodes in REFS reachable from the nodes listed in ROOTS.
  209. (vlist-fold (lambda (root+true result)
  210. (let* ((root (car root+true))
  211. (reachable (graph-reachable-nodes root refs result)))
  212. (vhash-consq root #t reachable)))
  213. vlist-null
  214. roots))
  215. (define (partition* pred vhash)
  216. ;; Partition VHASH according to PRED. Return the two resulting vhashes.
  217. (let ((result
  218. (vlist-fold (lambda (k+v result)
  219. (let ((k (car k+v))
  220. (v (cdr k+v))
  221. (r1 (car result))
  222. (r2 (cdr result)))
  223. (if (pred k)
  224. (cons (vhash-consq k v r1) r2)
  225. (cons r1 (vhash-consq k v r2)))))
  226. (cons vlist-null vlist-null)
  227. vhash)))
  228. (values (car result) (cdr result))))
  229. (define unused-toplevel-analysis
  230. ;; Report unused top-level definitions that are not exported.
  231. (let ()
  232. (define initial-graph
  233. (make-reference-graph vlist-null vlist-null #f))
  234. (define (add-def graph name src)
  235. (match graph
  236. (($ <reference-graph> defs refs ctx)
  237. (make-reference-graph (vhash-consq name src defs) refs name))))
  238. (define (add-ref graph pred succ)
  239. ;; Add a ref edge PRED -> SUCC in GRAPH.
  240. (match graph
  241. (($ <reference-graph> defs refs ctx)
  242. (let* ((succs (match (vhash-assq pred refs)
  243. ((pred . succs) succs)
  244. (#f '())))
  245. (refs (vhash-consq pred (cons succ succs) refs)))
  246. (make-reference-graph defs refs ctx)))))
  247. (define (add-ref-from-context graph name)
  248. ;; Add a ref edge from the current context to NAME in GRAPH.
  249. (add-ref graph (reference-graph-toplevel-context graph) name))
  250. (define (add-root-ref graph name)
  251. ;; Add a ref edge to NAME from the root, because its metadata is
  252. ;; marked maybe-unused.
  253. (add-ref graph #f name))
  254. (define (macro-variable? name env)
  255. (and (module? env)
  256. (let ((var (module-variable env name)))
  257. (and var (variable-bound? var)
  258. (macro? (variable-ref var))))))
  259. (define (maybe-unused? metadata)
  260. (assq 'maybe-unused metadata))
  261. (make-tree-analysis
  262. (lambda (x graph env locs)
  263. ;; Going down into X.
  264. (match x
  265. (($ <toplevel-ref> src mod name)
  266. (add-ref-from-context graph name))
  267. (($ <toplevel-define> src mod name expr)
  268. (let ((graph (add-def graph name (or src (find pair? locs)))))
  269. (match expr
  270. (($ <lambda> src (? maybe-unused?) body)
  271. (add-root-ref graph name))
  272. (_ graph))))
  273. (($ <toplevel-set> src mod name expr)
  274. (add-ref-from-context graph name))
  275. (_ graph)))
  276. (lambda (x graph env locs)
  277. ;; Leaving X's scope.
  278. (match x
  279. (($ <toplevel-define>)
  280. (match graph
  281. (($ <reference-graph> defs refs ctx)
  282. (make-reference-graph defs refs #f))))
  283. (_ graph)))
  284. (lambda (graph env)
  285. ;; Process the resulting reference graph: determine all private definitions
  286. ;; not reachable from any public definition. Macros
  287. ;; (syntax-transformers), which are globally bound, never considered
  288. ;; unused since we can't tell whether a macro is actually used; in
  289. ;; addition, macros are considered roots of the graph since they may use
  290. ;; private bindings. FIXME: The `make-syntax-transformer' calls don't
  291. ;; contain any literal `toplevel-ref' of the global bindings they use so
  292. ;; this strategy fails.
  293. (define exports (make-hash-table))
  294. (when (module? env)
  295. (module-for-each (lambda (name var) (hashq-set! exports var name))
  296. (module-public-interface env)))
  297. (define (exported? name)
  298. (if (module? env)
  299. (and=> (module-variable env name)
  300. (lambda (var)
  301. (hashq-ref exports var)))
  302. #t))
  303. (let-values (((public-defs private-defs)
  304. (partition* (lambda (name)
  305. (or (exported? name)
  306. (macro-variable? name env)))
  307. (reference-graph-defs graph))))
  308. (let* ((roots (vhash-consq #f #t public-defs))
  309. (refs (reference-graph-refs graph))
  310. (reachable (graph-reachable-nodes* roots refs))
  311. (unused (vlist-filter (lambda (name+src)
  312. (not (vhash-assq (car name+src)
  313. reachable)))
  314. private-defs)))
  315. (vlist-for-each (lambda (name+loc)
  316. (let ((name (car name+loc))
  317. (loc (cdr name+loc)))
  318. (if (not (gensym? name))
  319. (warning 'unused-toplevel loc name))))
  320. unused))))
  321. initial-graph)))
  322. ;;;
  323. ;;; Unused module analysis.
  324. ;;;
  325. ;; Module uses and references to bindings of imported modules.
  326. (define-record-type <module-info>
  327. (module-info location qualified-references
  328. toplevel-references toplevel-definitions)
  329. module-info?
  330. (location module-info-location) ;location vector | #f
  331. (qualified-references module-info-qualified-references) ;module name vhash
  332. (toplevel-references module-info-toplevel-references) ;list of symbols
  333. (toplevel-definitions module-info-toplevel-definitions)) ;symbol vhash
  334. (define unused-module-analysis
  335. ;; Report unused modules in the given tree.
  336. (make-tree-analysis
  337. (lambda (x info env locs)
  338. ;; Going down into X: extend INFO accordingly.
  339. (match x
  340. ((or ($ <module-ref> loc module name)
  341. ($ <module-set> loc module name))
  342. (let ((references (module-info-qualified-references info)))
  343. (if (vhash-assoc module references)
  344. info
  345. (module-info (module-info-location info)
  346. (vhash-cons module #t references)
  347. (module-info-toplevel-references info)
  348. (module-info-toplevel-definitions info)))))
  349. ((or ($ <toplevel-ref> loc module name)
  350. ($ <toplevel-set> loc module name))
  351. (if (equal? module (module-name env))
  352. (let ((references (module-info-toplevel-references info)))
  353. (module-info (module-info-location info)
  354. (module-info-qualified-references info)
  355. (cons x references)
  356. (module-info-toplevel-definitions info)))
  357. (let ((references (module-info-qualified-references info)))
  358. (module-info (module-info-location info)
  359. (vhash-cons module #t references)
  360. (module-info-toplevel-references info)
  361. (module-info-toplevel-definitions info)))))
  362. (($ <toplevel-define> loc module name)
  363. (module-info (module-info-location info)
  364. (module-info-qualified-references info)
  365. (module-info-toplevel-references info)
  366. (vhash-consq name x
  367. (module-info-toplevel-definitions info))))
  368. ;; Record the approximate location of the module import. We
  369. ;; could parse the #:imports arguments to determine the location
  370. ;; of each #:use-module but we'll leave that as an exercise for
  371. ;; the reader.
  372. (($ <call> loc ($ <module-ref> _ '(guile) 'define-module*))
  373. (module-info loc
  374. (module-info-qualified-references info)
  375. (module-info-toplevel-references info)
  376. (module-info-toplevel-definitions info)))
  377. (($ <call> loc ($ <module-ref> _ '(guile) 'process-use-modules))
  378. (module-info loc
  379. (module-info-qualified-references info)
  380. (module-info-toplevel-references info)
  381. (module-info-toplevel-definitions info)))
  382. (_
  383. info)))
  384. (lambda (x info env locs) ;leaving X's scope
  385. info)
  386. (lambda (info env) ;finishing
  387. (define (defining-module ref env)
  388. ;; Return the name of the module that defines REF, a
  389. ;; <toplevel-ref> or <toplevel-set>, in ENV.
  390. (let ((name (if (toplevel-ref? ref)
  391. (toplevel-ref-name ref)
  392. (toplevel-set-name ref))))
  393. (match (vhash-assq name (module-info-toplevel-definitions info))
  394. (#f
  395. ;; NAME is not among the top-level definitions of this
  396. ;; compilation unit, so check which module provides it.
  397. (and=> (module-variable env name)
  398. (lambda (variable)
  399. (and=> (find (lambda (module)
  400. (module-reverse-lookup module variable))
  401. (module-uses env))
  402. module-name))))
  403. (_
  404. (if (toplevel-ref? ref)
  405. (toplevel-ref-mod ref)
  406. (toplevel-set-mod ref))))))
  407. (define (module-bindings-reexported? module env)
  408. ;; Return true if ENV reexports one or more bindings from MODULE.
  409. (let ((module (resolve-interface module))
  410. (tag (make-prompt-tag)))
  411. (call-with-prompt tag
  412. (lambda ()
  413. (module-for-each (lambda (symbol variable)
  414. (when (module-reverse-lookup module variable)
  415. (abort-to-prompt tag)))
  416. (module-public-interface env))
  417. #f)
  418. (const #t))))
  419. (define (module-exports-macros? module)
  420. ;; Return #t if MODULE exports one or more macros.
  421. (let ((tag (make-prompt-tag)))
  422. (call-with-prompt tag
  423. (lambda ()
  424. (module-for-each (lambda (symbol variable)
  425. (when (and (variable-bound? variable)
  426. (macro?
  427. (variable-ref variable)))
  428. (abort-to-prompt tag)))
  429. module)
  430. #f)
  431. (const #t))))
  432. (let ((used-modules ;list of modules actually used
  433. (fold (lambda (reference modules)
  434. (let ((module (defining-module reference env)))
  435. (if (or (not module) (vhash-assoc module modules))
  436. modules
  437. (vhash-cons module #t modules))))
  438. (module-info-qualified-references info)
  439. (module-info-toplevel-references info))))
  440. ;; Compare the modules imported by ENV with USED-MODULES, the
  441. ;; list of modules actually referenced. When a module is not in
  442. ;; USED-MODULES, check whether ENV reexports bindings from it.
  443. (for-each (lambda (module)
  444. (unless (or (vhash-assoc (module-name module)
  445. used-modules)
  446. (module-bindings-reexported?
  447. (module-name module) env))
  448. ;; If MODULE exports macros, and if the expansion
  449. ;; of those macros doesn't contain <module-ref>s
  450. ;; inside MODULE, then we cannot conclude whether
  451. ;; or not MODULE is used.
  452. (warning 'unused-module
  453. (module-info-location info)
  454. (module-name module)
  455. (not (module-exports-macros? module)))))
  456. (module-uses env))))
  457. (module-info #f vlist-null '() vlist-null)))
  458. ;;;
  459. ;;; Shadowed top-level definition analysis.
  460. ;;;
  461. (define shadowed-toplevel-analysis
  462. ;; Report top-level definitions that shadow previous top-level
  463. ;; definitions from the same compilation unit.
  464. (make-tree-analysis
  465. (lambda (x defs env locs)
  466. ;; Going down into X.
  467. (match x
  468. (($ <toplevel-define> src mod name expr)
  469. (match (vhash-assq name defs)
  470. ((_ . previous-definition)
  471. (warning 'shadowed-toplevel src name
  472. (tree-il-srcv previous-definition))
  473. defs)
  474. (#f
  475. (vhash-consq name x defs))))
  476. (else defs)))
  477. (lambda (x defs env locs)
  478. ;; Leaving X's scope.
  479. defs)
  480. (lambda (defs env)
  481. #t)
  482. vlist-null))
  483. ;;;
  484. ;;; Use before definition analysis.
  485. ;;;
  486. ;;; This analysis collects all definitions of top-level variables, and
  487. ;;; references to top-level variables. As it visits the term, it tries
  488. ;;; to match uses to the definition that corresponds to that program
  489. ;;; point. For example, in this sample program:
  490. ;;;
  491. ;;; (define a 42)
  492. ;;; (define b a)
  493. ;;;
  494. ;;; The analysis will be able to know that the definition of "a"
  495. ;;; referred to when defining "b" is 42.
  496. ;;;
  497. ;;; In many cases this definition is conservative. For example, in this
  498. ;;; code:
  499. ;;;
  500. ;;; (define a 42)
  501. ;;; (define b (lambda () a))
  502. ;;;
  503. ;;; We don't necessarily know that the "a" in the lambda is 42, as a
  504. ;;; further top-level definition could provide a different value.
  505. ;;; However, we do know that "a" is bound, unlike in this code:
  506. ;;;
  507. ;;; (define b (lambda () a))
  508. ;;;
  509. ;;; Here we should issue a warning if no import provides an "a" binding.
  510. ;;;
  511. ;;; Use-before-def analysis also issues specialized warnings for some
  512. ;;; less common errors. One relates specifically to macro use before
  513. ;;; definition. If a compilation unit defines a macro and has some uses
  514. ;;; of the macro, usually the uses will be expanded out by the
  515. ;;; macro-expander. If there is any reference to a macro as a value,
  516. ;;; that usually indicates a bug in the user's program. Like in this
  517. ;;; program:
  518. ;;;
  519. ;;; (define (a) (b))
  520. ;;; (define-syntax-rule (b) 42)
  521. ;;;
  522. ;;; If this program is expanded one top-level expression at a time,
  523. ;;; which is Guile's default compilation mode, the expander will assume
  524. ;;; that the reference to (b) is a call to a top-level procedure, only
  525. ;;; to find out it's a macro later on. Use-before-def analysis can warn
  526. ;;; for this case.
  527. ;;;
  528. ;;; Similarly, if a compilation unit uses an imported binding, then
  529. ;;; provides a local definition for the binding, this may cause problems
  530. ;;; if the module is re-loaded. Consider:
  531. ;;;
  532. ;;; (define-module (foo))
  533. ;;; (define a +)
  534. ;;; (define + -)
  535. ;;;
  536. ;;; In this fragment, we see the intention of the programmer is to
  537. ;;; locally redefine `+', but to preserve the previous definition in
  538. ;;; `a'.
  539. ;;;
  540. ;;; However, if the module is loaded twice, `a' will be bound not to the
  541. ;;; `(guile)' binding of `+', but rather to `-'. This is because each
  542. ;;; module has a single global instance, and the first definition
  543. ;;; already bound `+' to `-'. Use-before-def analysis can detect this
  544. ;;; situation as well.
  545. ;;;
  546. ;;; <use-before-def-info> records are used during tree traversal in
  547. ;;; search of possible uses of values before they are defined. They
  548. ;;; contain a list of references to top-level variables, and a list of
  549. ;;; the top-level definitions that have been encountered. Any definition
  550. ;;; which is a macro should in theory be expanded out already; if that's
  551. ;;; not the case, the program likely has a bug.
  552. (define-record-type <use-before-def-info>
  553. (make-use-before-def-info depth uses defs)
  554. use-before-def-info?
  555. ;; LOCAL-DEF := #(MACRO? DEPTH LOCATION)
  556. ;; DEF := LOCAL-DEF ; Defined in compilation unit already at use.
  557. ;; | import ; Def provided by imported module.
  558. ;; | unknown-module ; Module at use site not known.
  559. ;; | unknown-declarative ; Defined, but def not within compilation unit.
  560. ;; | unknown-imperative ; Same as above, but in non-declarative module.
  561. ;; | unbound ; No top-level definition known at use
  562. ;; USE := #(MOD-NAME VAR-NAME DEPTH DEF LOCATION)
  563. (depth use-before-def-info-depth) ;; Zero if definitely evaluated
  564. (uses use-before-def-info-uses) ;; List of USE
  565. (defs use-before-def-info-defs)) ;; Vhash of ((MOD . NAME) . LOCAL-DEF)
  566. (define (goops-toplevel-definition proc args env)
  567. ;; If call of PROC to ARGS is a GOOPS top-level definition, return the
  568. ;; name of the variable being defined; otherwise return #f. This
  569. ;; assumes knowledge of the current implementation of `define-class'
  570. ;; et al.
  571. (match (cons proc args)
  572. ((($ <module-ref> _ '(oop goops) 'toplevel-define! #f)
  573. ($ <const> _ (? symbol? name))
  574. exp)
  575. ;; We don't know the precise module in which we are defining the
  576. ;; variable :/ Guess that it's in `env'.
  577. (vector (module-name env) name exp))
  578. ((($ <toplevel-ref> _ '(oop goops) 'toplevel-define!)
  579. ($ <const> _ (? symbol? name))
  580. exp)
  581. (vector '(oop goops) name exp))
  582. (_ #f)))
  583. (define* (make-use-before-definition-analysis #:key (warning-level 0)
  584. (enabled-warnings '()))
  585. ;; Report possibly unbound variables in the given tree.
  586. (define (enabled-for-level? level) (<= level warning-level))
  587. (define-syntax-rule (define-warning enabled
  588. #:level level #:name warning-name)
  589. (define enabled
  590. (or (enabled-for-level? level)
  591. (memq 'warning-name enabled-warnings))))
  592. (define-warning use-before-definition-enabled
  593. #:level 1 #:name use-before-definition)
  594. (define-warning unbound-variable-enabled
  595. #:level 1 #:name unbound-variable)
  596. (define-warning macro-use-before-definition-enabled
  597. #:level 1 #:name macro-use-before-definition)
  598. (define-warning non-idempotent-definition-enabled
  599. #:level 1 #:name non-idempotent-definition)
  600. (define (resolve mod name defs)
  601. (match (vhash-assoc (cons mod name) defs)
  602. ((_ . local-def)
  603. ;; Top-level def present in this compilation unit, before this
  604. ;; use.
  605. local-def)
  606. (#f
  607. (let ((mod (and mod (resolve-module mod #f #:ensure #f))))
  608. (cond
  609. ((not mod)
  610. ;; We don't know the module with respect to which this var
  611. ;; is being resolved.
  612. 'unknown-module)
  613. ((module-local-variable mod name)
  614. ;; The variable is locally bound in the module, but not by
  615. ;; any definition in the compilation unit; perhaps by load
  616. ;; or load-extension or something.
  617. (if (module-declarative? mod)
  618. 'unknown-declarative
  619. 'unknown-imperative))
  620. ((module-variable mod name)
  621. ;; The variable is an import. At the time of use, the
  622. ;; name is bound to the import.
  623. 'import)
  624. ((and=> (module-public-interface mod)
  625. (lambda (interface)
  626. (module-variable interface name)))
  627. ;; The variable is re-exported from another module.
  628. 'import)
  629. (else
  630. ;; Variable unbound in the module.
  631. 'unbound))))))
  632. (and
  633. (or use-before-definition-enabled
  634. unbound-variable-enabled
  635. macro-use-before-definition-enabled
  636. non-idempotent-definition-enabled)
  637. (make-tree-analysis
  638. (lambda (x info env locs)
  639. ;; Going down into X.
  640. (define (make-use mod name depth def src)
  641. (vector mod name depth def src))
  642. (define (make-def is-macro? depth src)
  643. (vector is-macro? depth src))
  644. (define (nearest-loc src)
  645. (or src (find pair? locs)))
  646. (define (add-use mod name src)
  647. (match info
  648. (($ <use-before-def-info> depth uses defs)
  649. (let* ((def (resolve mod name defs))
  650. (use (make-use mod name depth def src)))
  651. (make-use-before-def-info depth (cons use uses) defs)))))
  652. (define (add-def mod name src is-macro?)
  653. (match info
  654. (($ <use-before-def-info> depth uses defs)
  655. (let ((def (make-def is-macro? depth src)))
  656. (make-use-before-def-info depth uses
  657. (vhash-cons (cons mod name) def
  658. defs))))))
  659. (define (macro? x)
  660. (match x
  661. (($ <primcall> _ 'make-syntax-transformer) #t)
  662. (_ #f)))
  663. (match x
  664. (($ <toplevel-ref> src mod name)
  665. (add-use mod name (nearest-loc src)))
  666. (($ <toplevel-set> src mod name)
  667. (add-use mod name (nearest-loc src)))
  668. (($ <toplevel-define> src mod name exp)
  669. (add-def mod name (nearest-loc src) (macro? exp)))
  670. (($ <call> src proc args)
  671. ;; Check for a dynamic top-level definition, as is
  672. ;; done by code expanded from GOOPS macros.
  673. (match (goops-toplevel-definition proc args env)
  674. (#f info)
  675. (#(mod name exp) (add-def mod name (nearest-loc src) (macro? exp)))))
  676. ((or ($ <lambda>) ($ <conditional>))
  677. (match info
  678. (($ <use-before-def-info> depth uses defs)
  679. (make-use-before-def-info (1+ depth) uses defs))))
  680. (_ info)))
  681. (lambda (x info env locs)
  682. ;; Leaving X's scope.
  683. (match x
  684. ((or ($ <lambda>) ($ <conditional>))
  685. (match info
  686. (($ <use-before-def-info> depth uses defs)
  687. (make-use-before-def-info (1- depth) uses defs))))
  688. (_ info)))
  689. (lambda (info env)
  690. (define (compute-macros defs)
  691. (let ((macros (make-hash-table)))
  692. (vlist-for-each (match-lambda
  693. ((mod+name . #(is-macro? depth src))
  694. (when is-macro?
  695. (hash-set! macros mod+name src))))
  696. defs)
  697. macros))
  698. ;; Post-process the result.
  699. ;; FIXME: What to do with defs at nonzero depth?
  700. (match info
  701. (($ <use-before-def-info> 0 uses defs)
  702. ;; The way the traversal works is that we only add entries to
  703. ;; `defs' as we go, corresponding to local bindings.
  704. ;; Therefore the result of `resolve' can only go from being an
  705. ;; import, unbound, or top-level definition to being a
  706. ;; definition within the compilation unit. It can't go from
  707. ;; e.g. being an import to being a top-level definition, for
  708. ;; the purposes of our analysis, without the definition being
  709. ;; local to the compilation unit.
  710. (let ((macros (compute-macros defs))
  711. (issued-unbound-warnings (make-hash-table)))
  712. (for-each
  713. (match-lambda
  714. (#(mod name use-depth def-at-use use-loc)
  715. (cond
  716. ((and (hash-ref macros (cons mod name))
  717. macro-use-before-definition-enabled)
  718. ;; Something bound to this name is a macro, probably
  719. ;; later in the compilation unit. Probably the author
  720. ;; made a mistake somewhere!
  721. (warning 'macro-use-before-definition use-loc name))
  722. (else
  723. (let ((def-at-end (resolve mod name defs)))
  724. (match (cons def-at-use def-at-end)
  725. (('import . 'import) #t)
  726. (('import . #(is-macro? def-depth def-loc))
  727. ;; At use, the binding was an import, but later
  728. ;; had a local definition. Warn as this could
  729. ;; pose a hazard when reloading the module, as the
  730. ;; initial binding wouldn't come from the import.
  731. ;; If depth nonzero though, use might happen later
  732. ;; as it might be in a lambda, so no warning in
  733. ;; that case.
  734. (when (and non-idempotent-definition-enabled
  735. (zero? use-depth) (zero? def-depth))
  736. (warning 'non-idempotent-definition use-loc name)))
  737. (('unbound . 'unbound)
  738. ;; No binding at all; probably an error at
  739. ;; run-time, but we just warn at compile-time.
  740. (when unbound-variable-enabled
  741. (unless (hash-ref issued-unbound-warnings
  742. (cons mod name))
  743. (hash-set! issued-unbound-warnings (cons mod name) #t)
  744. (warning 'unbound-variable use-loc name))))
  745. (('unbound . _)
  746. ;; If the depth at the use is 0, then the use
  747. ;; definitely occurs before the definition.
  748. (when (and use-before-definition-enabled
  749. (zero? use-depth))
  750. (warning 'use-before-definition use-loc name)))
  751. (('unknown-module . _)
  752. ;; Could issue a warning here that for whatever
  753. ;; reason, we weren't able to reason about what
  754. ;; module was current!
  755. #t)
  756. (('unknown-declarative . 'unknown-declarative)
  757. ;; FIXME: Probably we should emit a warning as in
  758. ;; a declarative module perhaps this should not
  759. ;; happen.
  760. #t)
  761. (('unknown-declarative . _)
  762. ;; Def later in compilation unit than use; no
  763. ;; problem. Can occur when reloading declarative
  764. ;; modules.
  765. #t)
  766. (('unknown-imperative . _)
  767. ;; Def present and although not visible at the
  768. ;; use, don't warn as use module is
  769. ;; non-declarative.
  770. #t)
  771. (((? vector) . (? vector?))
  772. ;; Def locally bound at use; no problem.
  773. #t)))))))
  774. (reverse uses))))))
  775. (make-use-before-def-info 0 '() vlist-null))))
  776. ;;;
  777. ;;; Arity analysis.
  778. ;;;
  779. ;; <arity-info> records contain information about lexical definitions of
  780. ;; procedures currently in scope, top-level procedure definitions that have
  781. ;; been encountered, and calls to top-level procedures that have been
  782. ;; encountered.
  783. (define-record-type <arity-info>
  784. (make-arity-info toplevel-calls lexical-lambdas toplevel-lambdas)
  785. arity-info?
  786. (toplevel-calls toplevel-procedure-calls) ;; ((NAME . CALL) ...)
  787. (lexical-lambdas lexical-lambdas) ;; ((GENSYM . DEFINITION) ...)
  788. (toplevel-lambdas toplevel-lambdas)) ;; ((NAME . DEFINITION) ...)
  789. (define (validate-arity proc call lexical?)
  790. ;; Validate the argument count of CALL, a tree-il call of
  791. ;; PROC, emitting a warning in case of argument count mismatch.
  792. (define (filter-keyword-args keywords allow-other-keys? args)
  793. ;; Filter keyword arguments from ARGS and return the resulting list.
  794. ;; KEYWORDS is the list of allowed keywords, and ALLOW-OTHER-KEYS?
  795. ;; specified whethere keywords not listed in KEYWORDS are allowed.
  796. (let loop ((args args)
  797. (result '()))
  798. (if (null? args)
  799. (reverse result)
  800. (let ((arg (car args)))
  801. (if (and (const? arg)
  802. (or (memq (const-exp arg) keywords)
  803. (and allow-other-keys?
  804. (keyword? (const-exp arg)))))
  805. (loop (if (pair? (cdr args))
  806. (cddr args)
  807. '())
  808. result)
  809. (loop (cdr args)
  810. (cons arg result)))))))
  811. (define (arities proc)
  812. ;; Return the arities of PROC, which can be either a tree-il or a
  813. ;; procedure.
  814. (cond ((program? proc)
  815. (values (procedure-name proc)
  816. (map (lambda (a)
  817. (list (length (or (assq-ref a 'required) '()))
  818. (length (or (assq-ref a 'optional) '()))
  819. (and (assq-ref a 'rest) #t)
  820. (map car (or (assq-ref a 'keyword) '()))
  821. (assq-ref a 'allow-other-keys?)))
  822. (program-arguments-alists proc))))
  823. ((procedure? proc)
  824. (if (struct? proc)
  825. ;; An applicable struct.
  826. (arities (struct-ref proc 0))
  827. ;; An applicable smob.
  828. (let ((arity (procedure-minimum-arity proc)))
  829. (values (procedure-name proc)
  830. (list (list (car arity) (cadr arity) (caddr arity)
  831. #f #f))))))
  832. (else
  833. (let loop ((name #f)
  834. (proc proc)
  835. (arities '()))
  836. (if (not proc)
  837. (values name (reverse arities))
  838. (match proc
  839. (($ <lambda-case> src req opt rest kw inits gensyms body alt)
  840. (loop name alt
  841. (cons (list (length req) (length opt) rest
  842. (and (pair? kw) (map car (cdr kw)))
  843. (and (pair? kw) (car kw)))
  844. arities)))
  845. (($ <lambda> src meta body)
  846. (loop (assoc-ref meta 'name) body arities))
  847. (_
  848. (values #f #f))))))))
  849. (let ((args (call-args call))
  850. (src (tree-il-srcv call)))
  851. (call-with-values (lambda () (arities proc))
  852. (lambda (name arities)
  853. (define matches?
  854. (find (lambda (arity)
  855. (pmatch arity
  856. ((,req ,opt ,rest? ,kw ,aok?)
  857. (let ((args (if (pair? kw)
  858. (filter-keyword-args kw aok? args)
  859. args)))
  860. (if (and req opt)
  861. (let ((count (length args)))
  862. (and (>= count req)
  863. (or rest?
  864. (<= count (+ req opt)))))
  865. #t)))
  866. (else #t)))
  867. arities))
  868. (if (not matches?)
  869. (warning 'arity-mismatch src
  870. (or name (with-output-to-string (lambda () (write proc))))
  871. lexical?)))))
  872. #t)
  873. (define arity-analysis
  874. ;; Report arity mismatches in the given tree.
  875. (make-tree-analysis
  876. (lambda (x info env locs)
  877. ;; Down into X.
  878. (define (extend lexical-name val info)
  879. ;; If VAL is a lambda, add NAME to the lexical-lambdas of INFO.
  880. (let ((toplevel-calls (toplevel-procedure-calls info))
  881. (lexical-lambdas (lexical-lambdas info))
  882. (toplevel-lambdas (toplevel-lambdas info)))
  883. (match val
  884. (($ <lambda> src meta body)
  885. (make-arity-info toplevel-calls
  886. (vhash-consq lexical-name val
  887. lexical-lambdas)
  888. toplevel-lambdas))
  889. (($ <lexical-ref> src name gensym)
  890. ;; lexical alias
  891. (let ((val* (vhash-assq gensym lexical-lambdas)))
  892. (if (pair? val*)
  893. (extend lexical-name (cdr val*) info)
  894. info)))
  895. (($ <toplevel-ref> src mod name)
  896. ;; top-level alias
  897. (make-arity-info toplevel-calls
  898. (vhash-consq lexical-name val
  899. lexical-lambdas)
  900. toplevel-lambdas))
  901. (_ info))))
  902. (let ((toplevel-calls (toplevel-procedure-calls info))
  903. (lexical-lambdas (lexical-lambdas info))
  904. (toplevel-lambdas (toplevel-lambdas info)))
  905. (match x
  906. (($ <toplevel-define> src mod name exp)
  907. (match exp
  908. (($ <lambda> src' meta body)
  909. (make-arity-info toplevel-calls
  910. lexical-lambdas
  911. (vhash-consq name exp toplevel-lambdas)))
  912. (($ <toplevel-ref> src' mod name)
  913. ;; alias for another toplevel
  914. (let ((proc (vhash-assq name toplevel-lambdas)))
  915. (make-arity-info toplevel-calls
  916. lexical-lambdas
  917. (vhash-consq (toplevel-define-name x)
  918. (if (pair? proc)
  919. (cdr proc)
  920. exp)
  921. toplevel-lambdas))))
  922. (_ info)))
  923. (($ <let> src names gensyms vals)
  924. (fold extend info gensyms vals))
  925. (($ <letrec> src in-order? names gensyms vals)
  926. (fold extend info gensyms vals))
  927. (($ <fix> src names gensyms vals)
  928. (fold extend info gensyms vals))
  929. (($ <call> src proc args)
  930. (match proc
  931. (($ <lambda> src' meta body)
  932. (validate-arity proc x #t)
  933. info)
  934. (($ <toplevel-ref> src' mod name)
  935. (make-arity-info (vhash-consq name x toplevel-calls)
  936. lexical-lambdas
  937. toplevel-lambdas))
  938. (($ <lexical-ref> src' name gensym)
  939. (match (vhash-assq gensym lexical-lambdas)
  940. ((gensym . ($ <toplevel-ref> src'' mod name'))
  941. ;; alias to toplevel
  942. (make-arity-info (vhash-consq name' x toplevel-calls)
  943. lexical-lambdas
  944. toplevel-lambdas))
  945. ((gensym . proc)
  946. (validate-arity proc x #t)
  947. info)
  948. (#f
  949. ;; If GENSYM wasn't found, it may be because it's an
  950. ;; argument of the procedure being compiled.
  951. info)))
  952. (_ info)))
  953. (_ info))))
  954. (lambda (x info env locs)
  955. ;; Up from X.
  956. (define (shrink name val info)
  957. ;; Remove NAME from the lexical-lambdas of INFO.
  958. (let ((toplevel-calls (toplevel-procedure-calls info))
  959. (lexical-lambdas (lexical-lambdas info))
  960. (toplevel-lambdas (toplevel-lambdas info)))
  961. (make-arity-info toplevel-calls
  962. (if (vhash-assq name lexical-lambdas)
  963. (vlist-tail lexical-lambdas)
  964. lexical-lambdas)
  965. toplevel-lambdas)))
  966. (let ((toplevel-calls (toplevel-procedure-calls info))
  967. (lexical-lambdas (lexical-lambdas info))
  968. (toplevel-lambdas (toplevel-lambdas info)))
  969. (match x
  970. (($ <let> src names gensyms vals)
  971. (fold shrink info gensyms vals))
  972. (($ <letrec> src in-order? names gensyms vals)
  973. (fold shrink info gensyms vals))
  974. (($ <fix> src names gensyms vals)
  975. (fold shrink info gensyms vals))
  976. (_ info))))
  977. (lambda (result env)
  978. ;; Post-processing: check all top-level procedure calls that have been
  979. ;; encountered.
  980. (let ((toplevel-calls (toplevel-procedure-calls result))
  981. (toplevel-lambdas (toplevel-lambdas result)))
  982. (vlist-for-each
  983. (lambda (name+call)
  984. (let* ((name (car name+call))
  985. (call (cdr name+call))
  986. (proc
  987. (or (and=> (vhash-assq name toplevel-lambdas) cdr)
  988. (and (module? env)
  989. (false-if-exception
  990. (module-ref env name)))))
  991. (proc*
  992. ;; handle toplevel aliases
  993. (if (toplevel-ref? proc)
  994. (let ((name (toplevel-ref-name proc)))
  995. (and (module? env)
  996. (false-if-exception
  997. (module-ref env name))))
  998. proc)))
  999. (cond ((lambda? proc*)
  1000. (validate-arity proc* call #t))
  1001. ((procedure? proc*)
  1002. (validate-arity proc* call #f)))))
  1003. toplevel-calls)))
  1004. (make-arity-info vlist-null vlist-null vlist-null)))
  1005. ;;;
  1006. ;;; `format' argument analysis.
  1007. ;;;
  1008. (define &syntax-error
  1009. ;; The `throw' key for syntax errors.
  1010. (gensym "format-string-syntax-error"))
  1011. (define (format-string-argument-count fmt)
  1012. ;; Return the minimum and maxium number of arguments that should
  1013. ;; follow format string FMT (or, ahem, a good estimate thereof) or
  1014. ;; `any' if the format string can be followed by any number of
  1015. ;; arguments.
  1016. (define (drop-group chars end)
  1017. ;; Drop characters from CHARS until "~END" is encountered.
  1018. (let loop ((chars chars)
  1019. (tilde? #f))
  1020. (if (null? chars)
  1021. (throw &syntax-error 'unterminated-iteration)
  1022. (if tilde?
  1023. (if (eq? (car chars) end)
  1024. (cdr chars)
  1025. (loop (cdr chars) #f))
  1026. (if (eq? (car chars) #\~)
  1027. (loop (cdr chars) #t)
  1028. (loop (cdr chars) #f))))))
  1029. (define (digit? char)
  1030. ;; Return true if CHAR is a digit, #f otherwise.
  1031. (memq char '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)))
  1032. (define (previous-number chars)
  1033. ;; Return the previous series of digits found in CHARS.
  1034. (let ((numbers (take-while digit? chars)))
  1035. (and (not (null? numbers))
  1036. (string->number (list->string (reverse numbers))))))
  1037. (let loop ((chars (string->list fmt))
  1038. (state 'literal)
  1039. (params '())
  1040. (conditions '())
  1041. (end-group #f)
  1042. (min-count 0)
  1043. (max-count 0))
  1044. (if (null? chars)
  1045. (if end-group
  1046. (throw &syntax-error 'unterminated-conditional)
  1047. (values min-count max-count))
  1048. (case state
  1049. ((tilde)
  1050. (case (car chars)
  1051. ((#\~ #\% #\& #\t #\T #\_ #\newline #\( #\) #\! #\| #\/ #\q #\Q)
  1052. (loop (cdr chars) 'literal '()
  1053. conditions end-group
  1054. min-count max-count))
  1055. ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\, #\: #\@ #\+ #\- #\#)
  1056. (loop (cdr chars)
  1057. 'tilde (cons (car chars) params)
  1058. conditions end-group
  1059. min-count max-count))
  1060. ((#\v #\V) (loop (cdr chars)
  1061. 'tilde (cons (car chars) params)
  1062. conditions end-group
  1063. (+ 1 min-count)
  1064. (+ 1 max-count)))
  1065. ((#\p #\P) (let* ((colon? (memq #\: params))
  1066. (min-count (if colon?
  1067. (max 1 min-count)
  1068. (+ 1 min-count))))
  1069. (loop (cdr chars) 'literal '()
  1070. conditions end-group
  1071. min-count
  1072. (if colon?
  1073. (max max-count min-count)
  1074. (+ 1 max-count)))))
  1075. ((#\[)
  1076. (loop chars 'literal '() '()
  1077. (let ((selector (previous-number params))
  1078. (at? (memq #\@ params)))
  1079. (lambda (chars conds)
  1080. ;; end of group
  1081. (let ((mins (map car conds))
  1082. (maxs (map cdr conds))
  1083. (sel? (and selector
  1084. (< selector (length conds)))))
  1085. (if (and (every number? mins)
  1086. (every number? maxs))
  1087. (loop chars 'literal '() conditions end-group
  1088. (+ min-count
  1089. (if sel?
  1090. (car (list-ref conds selector))
  1091. (+ (if at? 0 1)
  1092. (if (null? mins)
  1093. 0
  1094. (apply min mins)))))
  1095. (+ max-count
  1096. (if sel?
  1097. (cdr (list-ref conds selector))
  1098. (+ (if at? 0 1)
  1099. (if (null? maxs)
  1100. 0
  1101. (apply max maxs))))))
  1102. (values 'any 'any))))) ;; XXX: approximation
  1103. 0 0))
  1104. ((#\;)
  1105. (if end-group
  1106. (loop (cdr chars) 'literal '()
  1107. (cons (cons min-count max-count) conditions)
  1108. end-group
  1109. 0 0)
  1110. (throw &syntax-error 'unexpected-semicolon)))
  1111. ((#\])
  1112. (if end-group
  1113. (end-group (cdr chars)
  1114. (reverse (cons (cons min-count max-count)
  1115. conditions)))
  1116. (throw &syntax-error 'unexpected-conditional-termination)))
  1117. ((#\{) (if (memq #\@ params)
  1118. (values min-count 'any)
  1119. (loop (drop-group (cdr chars) #\})
  1120. 'literal '()
  1121. conditions end-group
  1122. (+ 1 min-count) (+ 1 max-count))))
  1123. ((#\*) (if (memq #\@ params)
  1124. (values 'any 'any) ;; it's unclear what to do here
  1125. (loop (cdr chars)
  1126. 'literal '()
  1127. conditions end-group
  1128. (+ (or (previous-number params) 1)
  1129. min-count)
  1130. (+ (or (previous-number params) 1)
  1131. max-count))))
  1132. ((#\? #\k #\K)
  1133. ;; We don't have enough info to determine the exact number
  1134. ;; of args, but we could determine a lower bound (TODO).
  1135. (values 'any 'any))
  1136. ((#\^)
  1137. (values min-count 'any))
  1138. ((#\h #\H)
  1139. (let ((argc (if (memq #\: params) 2 1)))
  1140. (loop (cdr chars) 'literal '()
  1141. conditions end-group
  1142. (+ argc min-count)
  1143. (+ argc max-count))))
  1144. ((#\')
  1145. (if (null? (cdr chars))
  1146. (throw &syntax-error 'unexpected-termination)
  1147. (loop (cddr chars) 'tilde (cons (cadr chars) params)
  1148. conditions end-group min-count max-count)))
  1149. (else (loop (cdr chars) 'literal '()
  1150. conditions end-group
  1151. (+ 1 min-count) (+ 1 max-count)))))
  1152. ((literal)
  1153. (case (car chars)
  1154. ((#\~) (loop (cdr chars) 'tilde '()
  1155. conditions end-group
  1156. min-count max-count))
  1157. (else (loop (cdr chars) 'literal '()
  1158. conditions end-group
  1159. min-count max-count))))
  1160. (else (error "computer bought the farm" state))))))
  1161. (define (proc-ref? exp proc special-name env)
  1162. "Return #t when EXP designates procedure PROC in ENV. As a last
  1163. resort, return #t when EXP refers to the global variable SPECIAL-NAME."
  1164. (define special?
  1165. (cut eq? <> special-name))
  1166. (match exp
  1167. (($ <toplevel-ref> _ _ (? special?))
  1168. ;; Allow top-levels like: (define G_ (cut gettext <> "my-domain")).
  1169. #t)
  1170. (($ <toplevel-ref> _ _ name)
  1171. (let ((var (module-variable env name)))
  1172. (and var (variable-bound? var)
  1173. (eq? (variable-ref var) proc))))
  1174. (($ <module-ref> _ _ (? special?))
  1175. #t)
  1176. (($ <module-ref> _ module name public?)
  1177. (let* ((mod (if public?
  1178. (false-if-exception (resolve-interface module))
  1179. (resolve-module module #:ensure #f)))
  1180. (var (and mod (module-variable mod name))))
  1181. (and var (variable-bound? var) (eq? (variable-ref var) proc))))
  1182. (($ <lexical-ref> _ (? special?))
  1183. #t)
  1184. (_ #f)))
  1185. (define gettext? (cut proc-ref? <> gettext 'G_ <>))
  1186. (define ngettext? (cut proc-ref? <> ngettext 'N_ <>))
  1187. (define (const-fmt x env)
  1188. ;; Return the literal format string for X, or #f.
  1189. (match x
  1190. (($ <const> _ (? string? exp))
  1191. exp)
  1192. (($ <call> _ (? (cut gettext? <> env))
  1193. (($ <const> _ (? string? fmt))))
  1194. ;; Gettexted literals, like `(G_ "foo")'.
  1195. fmt)
  1196. (($ <call> _ (? (cut ngettext? <> env))
  1197. (($ <const> _ (? string? fmt)) ($ <const> _ (? string?)) _ ..1))
  1198. ;; Plural gettextized literals, like `(N_ "singular" "plural" n)'.
  1199. ;; TODO: Check whether the singular and plural strings have the
  1200. ;; same format escapes.
  1201. fmt)
  1202. (_ #f)))
  1203. (define format-analysis
  1204. ;; Report arity mismatches in the given tree.
  1205. (make-tree-analysis
  1206. (lambda (x res env locs)
  1207. ;; Down into X.
  1208. (define (check-format-args args loc)
  1209. (pmatch args
  1210. ((,port ,fmt . ,rest)
  1211. (guard (const-fmt fmt env))
  1212. (if (and (const? port)
  1213. (not (boolean? (const-exp port))))
  1214. (warning 'format loc 'wrong-port (const-exp port)))
  1215. (let ((fmt (const-fmt fmt env))
  1216. (count (length rest)))
  1217. (catch &syntax-error
  1218. (lambda ()
  1219. (let-values (((min max)
  1220. (format-string-argument-count fmt)))
  1221. (and min max
  1222. (or (and (or (eq? min 'any) (>= count min))
  1223. (or (eq? max 'any) (<= count max)))
  1224. (warning 'format loc 'wrong-format-arg-count
  1225. fmt min max count)))))
  1226. (lambda (_ key)
  1227. (warning 'format loc 'syntax-error key fmt)))))
  1228. ((,port ,fmt . ,rest)
  1229. (if (and (const? port)
  1230. (not (boolean? (const-exp port))))
  1231. (warning 'format loc 'wrong-port (const-exp port)))
  1232. (match fmt
  1233. (($ <const> loc* (? (negate string?) fmt))
  1234. (warning 'format (or loc* loc) 'wrong-format-string fmt))
  1235. ;; Warn on non-literal format strings, unless they refer to
  1236. ;; a lexical variable named "fmt".
  1237. (($ <lexical-ref> _ fmt)
  1238. #t)
  1239. ((? (negate const?))
  1240. (warning 'format loc 'non-literal-format-string))))
  1241. (else
  1242. (warning 'format loc 'wrong-num-args (length args)))))
  1243. (define (check-simple-format-args args loc)
  1244. ;; Check the arguments to the `simple-format' procedure, which is
  1245. ;; less capable than that of (ice-9 format).
  1246. (define allowed-chars
  1247. '(#\A #\S #\a #\s #\~ #\%))
  1248. (define (format-chars fmt)
  1249. (let loop ((chars (string->list fmt))
  1250. (result '()))
  1251. (match chars
  1252. (()
  1253. (reverse result))
  1254. ((#\~ opt rest ...)
  1255. (loop rest (cons opt result)))
  1256. ((_ rest ...)
  1257. (loop rest result)))))
  1258. (match args
  1259. ((port ($ <const> _ (? string? fmt)) _ ...)
  1260. (let ((opts (format-chars fmt)))
  1261. (or (every (cut memq <> allowed-chars) opts)
  1262. (begin
  1263. (warning 'format loc 'simple-format fmt
  1264. (find (negate (cut memq <> allowed-chars)) opts))
  1265. #f))))
  1266. ((port (= (cut const-fmt <> env) (? string? fmt)) args ...)
  1267. (check-simple-format-args `(,port ,(make-const loc fmt) ,args) loc))
  1268. (_ #t)))
  1269. (define (resolve-toplevel name)
  1270. (and (module? env)
  1271. (false-if-exception (module-ref env name))))
  1272. (match x
  1273. (($ <call> src ($ <toplevel-ref> _ _ name) args)
  1274. (let ((proc (resolve-toplevel name)))
  1275. (if (or (and (eq? proc (@ (guile) simple-format))
  1276. (check-simple-format-args args
  1277. (or src (find pair? locs))))
  1278. (eq? proc (@ (ice-9 format) format)))
  1279. (check-format-args args (or src (find pair? locs))))))
  1280. (($ <call> src ($ <module-ref> _ '(ice-9 format) 'format) args)
  1281. (check-format-args args (or src (find pair? locs))))
  1282. (($ <call> src ($ <module-ref> _ '(guile)
  1283. (or 'format 'simple-format))
  1284. args)
  1285. (and (check-simple-format-args args
  1286. (or src (find pair? locs)))
  1287. (check-format-args args (or src (find pair? locs)))))
  1288. (_ #t))
  1289. #t)
  1290. (lambda (x _ env locs)
  1291. ;; Up from X.
  1292. #t)
  1293. (lambda (_ env)
  1294. ;; Post-processing.
  1295. #t)
  1296. #t))
  1297. (begin-deprecated
  1298. (define-syntax unbound-variable-analysis
  1299. (identifier-syntax
  1300. (begin
  1301. (issue-deprecation-warning
  1302. "`unbound-variable-analysis' is deprecated. "
  1303. "Use `make-use-before-definition-analysis' instead.")
  1304. (make-use-before-definition-analysis
  1305. #:enabled-warnings '(unbound-variable)))))
  1306. (define-syntax macro-use-before-definition-analysis
  1307. (identifier-syntax
  1308. (begin
  1309. (issue-deprecation-warning
  1310. "`macro-use-before-definition-analysis' is deprecated. "
  1311. "Use `make-use-before-definition-analysis' instead.")
  1312. (make-use-before-definition-analysis
  1313. #:enabled-warnings '(macro-use-before-definition)))))
  1314. (export unbound-variable-analysis
  1315. macro-use-before-definition-analysis))
  1316. (define-syntax-rule (define-analysis make-analysis
  1317. #:level level #:kind kind #:analysis analysis)
  1318. (define* (make-analysis #:key (warning-level 0) (enabled-warnings '()))
  1319. (and (or (<= level warning-level)
  1320. (memq 'kind enabled-warnings))
  1321. analysis)))
  1322. (define-analysis make-unused-variable-analysis
  1323. #:level 3 #:kind unused-variable #:analysis unused-variable-analysis)
  1324. (define-analysis make-unused-toplevel-analysis
  1325. #:level 2 #:kind unused-toplevel #:analysis unused-toplevel-analysis)
  1326. (define-analysis make-unused-module-analysis
  1327. #:level 2 #:kind unused-module #:analysis unused-module-analysis)
  1328. (define-analysis make-shadowed-toplevel-analysis
  1329. #:level 2 #:kind shadowed-toplevel #:analysis shadowed-toplevel-analysis)
  1330. (define-analysis make-arity-analysis
  1331. #:level 1 #:kind arity-mismatch #:analysis arity-analysis)
  1332. (define-analysis make-format-analysis
  1333. #:level 1 #:kind format #:analysis format-analysis)
  1334. (define (make-analyzer warning-level warnings)
  1335. (define-syntax compute-analyses
  1336. (syntax-rules ()
  1337. ((_) '())
  1338. ((_ make-analysis . make-analysis*)
  1339. (let ((tail (compute-analyses . make-analysis*)))
  1340. (match (make-analysis #:warning-level warning-level
  1341. #:enabled-warnings warnings)
  1342. (#f tail)
  1343. (analysis (cons analysis tail)))))))
  1344. (let ((analyses (compute-analyses make-unused-variable-analysis
  1345. make-unused-toplevel-analysis
  1346. make-unused-module-analysis
  1347. make-shadowed-toplevel-analysis
  1348. make-arity-analysis
  1349. make-format-analysis
  1350. make-use-before-definition-analysis)))
  1351. (lambda (exp env)
  1352. (analyze-tree analyses exp env))))