analyze.scm 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296
  1. ;;; Diagnostic warnings for Tree-IL
  2. ;; Copyright (C) 2001,2008-2014,2016,2018-2022 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-src 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-src 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. (record-case x
  108. ((<lexical-ref> gensym)
  109. (make-binding-info vars (vhash-consq gensym #t refs)))
  110. ((<lexical-set> gensym)
  111. (make-binding-info vars (vhash-consq gensym #t refs)))
  112. ((<lambda-case> req opt inits rest kw gensyms)
  113. (let ((names `(,@req
  114. ,@(or opt '())
  115. ,@(if rest (list rest) '())
  116. ,@(if kw (map cadr (cdr kw)) '()))))
  117. (make-binding-info (extend gensyms names) refs)))
  118. ((<let> gensyms names)
  119. (make-binding-info (extend gensyms names) refs))
  120. ((<letrec> gensyms names)
  121. (make-binding-info (extend gensyms names) refs))
  122. ((<fix> gensyms names)
  123. (make-binding-info (extend gensyms names) refs))
  124. (else 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. (record-case x
  153. ((<lambda-case> gensyms)
  154. (make-binding-info (shrink gensyms refs) refs))
  155. ((<let> gensyms)
  156. (make-binding-info (shrink gensyms refs) refs))
  157. ((<letrec> gensyms)
  158. (make-binding-info (shrink gensyms refs) refs))
  159. ((<fix> gensyms)
  160. (make-binding-info (shrink gensyms refs) refs))
  161. (else 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 refs defs 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 ((add-ref-from-context
  232. (lambda (graph name)
  233. ;; Add an edge CTX -> NAME in GRAPH.
  234. (let* ((refs (reference-graph-refs graph))
  235. (defs (reference-graph-defs graph))
  236. (ctx (reference-graph-toplevel-context graph))
  237. (ctx-refs (or (and=> (vhash-assq ctx refs) cdr) '())))
  238. (make-reference-graph (vhash-consq ctx (cons name ctx-refs) refs)
  239. defs ctx)))))
  240. (define (macro-variable? name env)
  241. (and (module? env)
  242. (let ((var (module-variable env name)))
  243. (and var (variable-bound? var)
  244. (macro? (variable-ref var))))))
  245. (make-tree-analysis
  246. (lambda (x graph env locs)
  247. ;; Going down into X.
  248. (let ((ctx (reference-graph-toplevel-context graph))
  249. (refs (reference-graph-refs graph))
  250. (defs (reference-graph-defs graph)))
  251. (record-case x
  252. ((<toplevel-ref> name src)
  253. (add-ref-from-context graph name))
  254. ((<toplevel-define> name src)
  255. (let ((refs refs)
  256. (defs (vhash-consq name (or src (find pair? locs))
  257. defs)))
  258. (make-reference-graph refs defs name)))
  259. ((<toplevel-set> name src)
  260. (add-ref-from-context graph name))
  261. (else graph))))
  262. (lambda (x graph env locs)
  263. ;; Leaving X's scope.
  264. (record-case x
  265. ((<toplevel-define>)
  266. (let ((refs (reference-graph-refs graph))
  267. (defs (reference-graph-defs graph)))
  268. (make-reference-graph refs defs #f)))
  269. (else graph)))
  270. (lambda (graph env)
  271. ;; Process the resulting reference graph: determine all private definitions
  272. ;; not reachable from any public definition. Macros
  273. ;; (syntax-transformers), which are globally bound, never considered
  274. ;; unused since we can't tell whether a macro is actually used; in
  275. ;; addition, macros are considered roots of the graph since they may use
  276. ;; private bindings. FIXME: The `make-syntax-transformer' calls don't
  277. ;; contain any literal `toplevel-ref' of the global bindings they use so
  278. ;; this strategy fails.
  279. (define (exported? name)
  280. (if (module? env)
  281. (module-variable (module-public-interface env) name)
  282. #t))
  283. (let-values (((public-defs private-defs)
  284. (partition* (lambda (name)
  285. (or (exported? name)
  286. (macro-variable? name env)))
  287. (reference-graph-defs graph))))
  288. (let* ((roots (vhash-consq #f #t public-defs))
  289. (refs (reference-graph-refs graph))
  290. (reachable (graph-reachable-nodes* roots refs))
  291. (unused (vlist-filter (lambda (name+src)
  292. (not (vhash-assq (car name+src)
  293. reachable)))
  294. private-defs)))
  295. (vlist-for-each (lambda (name+loc)
  296. (let ((name (car name+loc))
  297. (loc (cdr name+loc)))
  298. (if (not (gensym? name))
  299. (warning 'unused-toplevel loc name))))
  300. unused))))
  301. (make-reference-graph vlist-null vlist-null #f))))
  302. ;;;
  303. ;;; Shadowed top-level definition analysis.
  304. ;;;
  305. (define shadowed-toplevel-analysis
  306. ;; Report top-level definitions that shadow previous top-level
  307. ;; definitions from the same compilation unit.
  308. (make-tree-analysis
  309. (lambda (x defs env locs)
  310. ;; Going down into X.
  311. (record-case x
  312. ((<toplevel-define> name)
  313. (match (vhash-assq name defs)
  314. ((_ . previous-definition)
  315. (warning 'shadowed-toplevel (tree-il-src x) name
  316. (tree-il-src previous-definition))
  317. defs)
  318. (#f
  319. (vhash-consq name x defs))))
  320. (else defs)))
  321. (lambda (x defs env locs)
  322. ;; Leaving X's scope.
  323. defs)
  324. (lambda (defs env)
  325. #t)
  326. vlist-null))
  327. ;;;
  328. ;;; Use before definition analysis.
  329. ;;;
  330. ;;; This analysis collects all definitions of top-level variables, and
  331. ;;; references to top-level variables. As it visits the term, it tries
  332. ;;; to match uses to the definition that corresponds to that program
  333. ;;; point. For example, in this sample program:
  334. ;;;
  335. ;;; (define a 42)
  336. ;;; (define b a)
  337. ;;;
  338. ;;; The analysis will be able to know that the definition of "a"
  339. ;;; referred to when defining "b" is 42.
  340. ;;;
  341. ;;; In many cases this definition is conservative. For example, in this
  342. ;;; code:
  343. ;;;
  344. ;;; (define a 42)
  345. ;;; (define b (lambda () a))
  346. ;;;
  347. ;;; We don't necessarily know that the "a" in the lambda is 42, as a
  348. ;;; further top-level definition could provide a different value.
  349. ;;; However, we do know that "a" is bound, unlike in this code:
  350. ;;;
  351. ;;; (define b (lambda () a))
  352. ;;;
  353. ;;; Here we should issue a warning if no import provides an "a" binding.
  354. ;;;
  355. ;;; Use-before-def analysis also issues specialized warnings for some
  356. ;;; less common errors. One relates specifically to macro use before
  357. ;;; definition. If a compilation unit defines a macro and has some uses
  358. ;;; of the macro, usually the uses will be expanded out by the
  359. ;;; macro-expander. If there is any reference to a macro as a value,
  360. ;;; that usually indicates a bug in the user's program. Like in this
  361. ;;; program:
  362. ;;;
  363. ;;; (define (a) (b))
  364. ;;; (define-syntax-rule (b) 42)
  365. ;;;
  366. ;;; If this program is expanded one top-level expression at a time,
  367. ;;; which is Guile's default compilation mode, the expander will assume
  368. ;;; that the reference to (b) is a call to a top-level procedure, only
  369. ;;; to find out it's a macro later on. Use-before-def analysis can warn
  370. ;;; for this case.
  371. ;;;
  372. ;;; Similarly, if a compilation unit uses an imported binding, then
  373. ;;; provides a local definition for the binding, this may cause problems
  374. ;;; if the module is re-loaded. Consider:
  375. ;;;
  376. ;;; (define-module (foo))
  377. ;;; (define a +)
  378. ;;; (define + -)
  379. ;;;
  380. ;;; In this fragment, we see the intention of the programmer is to
  381. ;;; locally redefine `+', but to preserve the previous definition in
  382. ;;; `a'.
  383. ;;;
  384. ;;; However, if the module is loaded twice, `a' will be bound not to the
  385. ;;; `(guile)' binding of `+', but rather to `-'. This is because each
  386. ;;; module has a single global instance, and the first definition
  387. ;;; already bound `+' to `-'. Use-before-def analysis can detect this
  388. ;;; situation as well.
  389. ;;;
  390. ;;; <use-before-def-info> records are used during tree traversal in
  391. ;;; search of possible uses of values before they are defined. They
  392. ;;; contain a list of references to top-level variables, and a list of
  393. ;;; the top-level definitions that have been encountered. Any definition
  394. ;;; which is a macro should in theory be expanded out already; if that's
  395. ;;; not the case, the program likely has a bug.
  396. (define-record-type <use-before-def-info>
  397. (make-use-before-def-info depth uses defs)
  398. use-before-def-info?
  399. ;; LOCAL-DEF := #(MACRO? DEPTH LOCATION)
  400. ;; DEF := LOCAL-DEF ; Defined in compilation unit already at use.
  401. ;; | import ; Def provided by imported module.
  402. ;; | unknown-module ; Module at use site not known.
  403. ;; | unknown-declarative ; Defined, but def not within compilation unit.
  404. ;; | unknown-imperative ; Same as above, but in non-declarative module.
  405. ;; | unbound ; No top-level definition known at use
  406. ;; USE := #(MOD-NAME VAR-NAME DEPTH DEF LOCATION)
  407. (depth use-before-def-info-depth) ;; Zero if definitely evaluated
  408. (uses use-before-def-info-uses) ;; List of USE
  409. (defs use-before-def-info-defs)) ;; Vhash of ((MOD . NAME) . LOCAL-DEF)
  410. (define (goops-toplevel-definition proc args env)
  411. ;; If call of PROC to ARGS is a GOOPS top-level definition, return the
  412. ;; name of the variable being defined; otherwise return #f. This
  413. ;; assumes knowledge of the current implementation of `define-class'
  414. ;; et al.
  415. (match (cons proc args)
  416. ((($ <module-ref> _ '(oop goops) 'toplevel-define! #f)
  417. ($ <const> _ (? symbol? name))
  418. exp)
  419. ;; We don't know the precise module in which we are defining the
  420. ;; variable :/ Guess that it's in `env'.
  421. (vector (module-name env) name exp))
  422. ((($ <toplevel-ref> _ '(oop goops) 'toplevel-define!)
  423. ($ <const> _ (? symbol? name))
  424. exp)
  425. (vector '(oop goops) name exp))
  426. (_ #f)))
  427. (define* (make-use-before-definition-analysis #:key (warning-level 0)
  428. (enabled-warnings '()))
  429. ;; Report possibly unbound variables in the given tree.
  430. (define (enabled-for-level? level) (<= level warning-level))
  431. (define-syntax-rule (define-warning enabled
  432. #:level level #:name warning-name)
  433. (define enabled
  434. (or (enabled-for-level? level)
  435. (memq 'warning-name enabled-warnings))))
  436. (define-warning use-before-definition-enabled
  437. #:level 1 #:name use-before-definition)
  438. (define-warning unbound-variable-enabled
  439. #:level 1 #:name unbound-variable)
  440. (define-warning macro-use-before-definition-enabled
  441. #:level 1 #:name macro-use-before-definition)
  442. (define-warning non-idempotent-definition-enabled
  443. #:level 1 #:name non-idempotent-definition)
  444. (define (resolve mod name defs)
  445. (match (vhash-assoc (cons mod name) defs)
  446. ((_ . local-def)
  447. ;; Top-level def present in this compilation unit, before this
  448. ;; use.
  449. local-def)
  450. (#f
  451. (let ((mod (and mod (resolve-module mod #f #:ensure #f))))
  452. (cond
  453. ((not mod)
  454. ;; We don't know the module with respect to which this var
  455. ;; is being resolved.
  456. 'unknown-module)
  457. ((module-local-variable mod name)
  458. ;; The variable is locally bound in the module, but not by
  459. ;; any definition in the compilation unit; perhaps by load
  460. ;; or load-extension or something.
  461. (if (module-declarative? mod)
  462. 'unknown-declarative
  463. 'unknown-imperative))
  464. ((module-variable mod name)
  465. ;; The variable is an import. At the time of use, the
  466. ;; name is bound to the import.
  467. 'import)
  468. ((and=> (module-public-interface mod)
  469. (lambda (interface)
  470. (module-variable interface name)))
  471. ;; The variable is re-exported from another module.
  472. 'import)
  473. (else
  474. ;; Variable unbound in the module.
  475. 'unbound))))))
  476. (and
  477. (or use-before-definition-enabled
  478. unbound-variable-enabled
  479. macro-use-before-definition-enabled
  480. non-idempotent-definition-enabled)
  481. (make-tree-analysis
  482. (lambda (x info env locs)
  483. ;; Going down into X.
  484. (define (make-use mod name depth def src)
  485. (vector mod name depth def src))
  486. (define (make-def is-macro? depth src)
  487. (vector is-macro? depth src))
  488. (define (nearest-loc src)
  489. (or src (find pair? locs)))
  490. (define (add-use mod name src)
  491. (match info
  492. (($ <use-before-def-info> depth uses defs)
  493. (let* ((def (resolve mod name defs))
  494. (use (make-use mod name depth def src)))
  495. (make-use-before-def-info depth (cons use uses) defs)))))
  496. (define (add-def mod name src is-macro?)
  497. (match info
  498. (($ <use-before-def-info> depth uses defs)
  499. (let ((def (make-def is-macro? depth src)))
  500. (make-use-before-def-info depth uses
  501. (vhash-cons (cons mod name) def
  502. defs))))))
  503. (define (macro? x)
  504. (match x
  505. (($ <primcall> _ 'make-syntax-transformer) #t)
  506. (_ #f)))
  507. (match x
  508. (($ <toplevel-ref> src mod name)
  509. (add-use mod name (nearest-loc src)))
  510. (($ <toplevel-set> src mod name)
  511. (add-use mod name (nearest-loc src)))
  512. (($ <toplevel-define> src mod name exp)
  513. (add-def mod name (nearest-loc src) (macro? exp)))
  514. (($ <call> src proc args)
  515. ;; Check for a dynamic top-level definition, as is
  516. ;; done by code expanded from GOOPS macros.
  517. (match (goops-toplevel-definition proc args env)
  518. (#f info)
  519. (#(mod name exp) (add-def mod name (nearest-loc src) (macro? exp)))))
  520. ((or ($ <lambda>) ($ <conditional>))
  521. (match info
  522. (($ <use-before-def-info> depth uses defs)
  523. (make-use-before-def-info (1+ depth) uses defs))))
  524. (_ info)))
  525. (lambda (x info env locs)
  526. ;; Leaving X's scope.
  527. (match x
  528. ((or ($ <lambda>) ($ <conditional>))
  529. (match info
  530. (($ <use-before-def-info> depth uses defs)
  531. (make-use-before-def-info (1- depth) uses defs))))
  532. (_ info)))
  533. (lambda (info env)
  534. (define (compute-macros defs)
  535. (let ((macros (make-hash-table)))
  536. (vlist-for-each (match-lambda
  537. ((mod+name . #(is-macro? depth src))
  538. (when is-macro?
  539. (hash-set! macros mod+name src))))
  540. defs)
  541. macros))
  542. ;; Post-process the result.
  543. ;; FIXME: What to do with defs at nonzero depth?
  544. (match info
  545. (($ <use-before-def-info> 0 uses defs)
  546. ;; The way the traversal works is that we only add entries to
  547. ;; `defs' as we go, corresponding to local bindings.
  548. ;; Therefore the result of `resolve' can only go from being an
  549. ;; import, unbound, or top-level definition to being a
  550. ;; definition within the compilation unit. It can't go from
  551. ;; e.g. being an import to being a top-level definition, for
  552. ;; the purposes of our analysis, without the definition being
  553. ;; local to the compilation unit.
  554. (let ((macros (compute-macros defs))
  555. (issued-unbound-warnings (make-hash-table)))
  556. (for-each
  557. (match-lambda
  558. (#(mod name use-depth def-at-use use-loc)
  559. (cond
  560. ((and (hash-ref macros (cons mod name))
  561. macro-use-before-definition-enabled)
  562. ;; Something bound to this name is a macro, probably
  563. ;; later in the compilation unit. Probably the author
  564. ;; made a mistake somewhere!
  565. (warning 'macro-use-before-definition use-loc name))
  566. (else
  567. (let ((def-at-end (resolve mod name defs)))
  568. (match (cons def-at-use def-at-end)
  569. (('import . 'import) #t)
  570. (('import . #(is-macro? def-depth def-loc))
  571. ;; At use, the binding was an import, but later
  572. ;; had a local definition. Warn as this could
  573. ;; pose a hazard when reloading the module, as the
  574. ;; initial binding wouldn't come from the import.
  575. ;; If depth nonzero though, use might happen later
  576. ;; as it might be in a lambda, so no warning in
  577. ;; that case.
  578. (when (and non-idempotent-definition-enabled
  579. (zero? use-depth) (zero? def-depth))
  580. (warning 'non-idempotent-definition use-loc name)))
  581. (('unbound . 'unbound)
  582. ;; No binding at all; probably an error at
  583. ;; run-time, but we just warn at compile-time.
  584. (when unbound-variable-enabled
  585. (unless (hash-ref issued-unbound-warnings
  586. (cons mod name))
  587. (hash-set! issued-unbound-warnings (cons mod name) #t)
  588. (warning 'unbound-variable use-loc name))))
  589. (('unbound . _)
  590. ;; If the depth at the use is 0, then the use
  591. ;; definitely occurs before the definition.
  592. (when (and use-before-definition-enabled
  593. (zero? use-depth))
  594. (warning 'use-before-definition use-loc name)))
  595. (('unknown-module . _)
  596. ;; Could issue a warning here that for whatever
  597. ;; reason, we weren't able to reason about what
  598. ;; module was current!
  599. #t)
  600. (('unknown-declarative . 'unknown-declarative)
  601. ;; FIXME: Probably we should emit a warning as in
  602. ;; a declarative module perhaps this should not
  603. ;; happen.
  604. #t)
  605. (('unknown-declarative . _)
  606. ;; Def later in compilation unit than use; no
  607. ;; problem. Can occur when reloading declarative
  608. ;; modules.
  609. #t)
  610. (('unknown-imperative . _)
  611. ;; Def present and although not visible at the
  612. ;; use, don't warn as use module is
  613. ;; non-declarative.
  614. #t)
  615. (((? vector) . (? vector?))
  616. ;; Def locally bound at use; no problem.
  617. #t)))))))
  618. (reverse uses))))))
  619. (make-use-before-def-info 0 '() vlist-null))))
  620. ;;;
  621. ;;; Arity analysis.
  622. ;;;
  623. ;; <arity-info> records contain information about lexical definitions of
  624. ;; procedures currently in scope, top-level procedure definitions that have
  625. ;; been encountered, and calls to top-level procedures that have been
  626. ;; encountered.
  627. (define-record-type <arity-info>
  628. (make-arity-info toplevel-calls lexical-lambdas toplevel-lambdas)
  629. arity-info?
  630. (toplevel-calls toplevel-procedure-calls) ;; ((NAME . CALL) ...)
  631. (lexical-lambdas lexical-lambdas) ;; ((GENSYM . DEFINITION) ...)
  632. (toplevel-lambdas toplevel-lambdas)) ;; ((NAME . DEFINITION) ...)
  633. (define (validate-arity proc call lexical?)
  634. ;; Validate the argument count of CALL, a tree-il call of
  635. ;; PROC, emitting a warning in case of argument count mismatch.
  636. (define (filter-keyword-args keywords allow-other-keys? args)
  637. ;; Filter keyword arguments from ARGS and return the resulting list.
  638. ;; KEYWORDS is the list of allowed keywords, and ALLOW-OTHER-KEYS?
  639. ;; specified whethere keywords not listed in KEYWORDS are allowed.
  640. (let loop ((args args)
  641. (result '()))
  642. (if (null? args)
  643. (reverse result)
  644. (let ((arg (car args)))
  645. (if (and (const? arg)
  646. (or (memq (const-exp arg) keywords)
  647. (and allow-other-keys?
  648. (keyword? (const-exp arg)))))
  649. (loop (if (pair? (cdr args))
  650. (cddr args)
  651. '())
  652. result)
  653. (loop (cdr args)
  654. (cons arg result)))))))
  655. (define (arities proc)
  656. ;; Return the arities of PROC, which can be either a tree-il or a
  657. ;; procedure.
  658. (define (len x)
  659. (or (and (or (null? x) (pair? x))
  660. (length x))
  661. 0))
  662. (cond ((program? proc)
  663. (values (procedure-name proc)
  664. (map (lambda (a)
  665. (list (length (or (assq-ref a 'required) '()))
  666. (length (or (assq-ref a 'optional) '()))
  667. (and (assq-ref a 'rest) #t)
  668. (map car (or (assq-ref a 'keyword) '()))
  669. (assq-ref a 'allow-other-keys?)))
  670. (program-arguments-alists proc))))
  671. ((procedure? proc)
  672. (if (struct? proc)
  673. ;; An applicable struct.
  674. (arities (struct-ref proc 0))
  675. ;; An applicable smob.
  676. (let ((arity (procedure-minimum-arity proc)))
  677. (values (procedure-name proc)
  678. (list (list (car arity) (cadr arity) (caddr arity)
  679. #f #f))))))
  680. (else
  681. (let loop ((name #f)
  682. (proc proc)
  683. (arities '()))
  684. (if (not proc)
  685. (values name (reverse arities))
  686. (record-case proc
  687. ((<lambda-case> req opt rest kw alternate)
  688. (loop name alternate
  689. (cons (list (len req) (len opt) rest
  690. (and (pair? kw) (map car (cdr kw)))
  691. (and (pair? kw) (car kw)))
  692. arities)))
  693. ((<lambda> meta body)
  694. (loop (assoc-ref meta 'name) body arities))
  695. (else
  696. (values #f #f))))))))
  697. (let ((args (call-args call))
  698. (src (tree-il-src call)))
  699. (call-with-values (lambda () (arities proc))
  700. (lambda (name arities)
  701. (define matches?
  702. (find (lambda (arity)
  703. (pmatch arity
  704. ((,req ,opt ,rest? ,kw ,aok?)
  705. (let ((args (if (pair? kw)
  706. (filter-keyword-args kw aok? args)
  707. args)))
  708. (if (and req opt)
  709. (let ((count (length args)))
  710. (and (>= count req)
  711. (or rest?
  712. (<= count (+ req opt)))))
  713. #t)))
  714. (else #t)))
  715. arities))
  716. (if (not matches?)
  717. (warning 'arity-mismatch src
  718. (or name (with-output-to-string (lambda () (write proc))))
  719. lexical?)))))
  720. #t)
  721. (define arity-analysis
  722. ;; Report arity mismatches in the given tree.
  723. (make-tree-analysis
  724. (lambda (x info env locs)
  725. ;; Down into X.
  726. (define (extend lexical-name val info)
  727. ;; If VAL is a lambda, add NAME to the lexical-lambdas of INFO.
  728. (let ((toplevel-calls (toplevel-procedure-calls info))
  729. (lexical-lambdas (lexical-lambdas info))
  730. (toplevel-lambdas (toplevel-lambdas info)))
  731. (record-case val
  732. ((<lambda> body)
  733. (make-arity-info toplevel-calls
  734. (vhash-consq lexical-name val
  735. lexical-lambdas)
  736. toplevel-lambdas))
  737. ((<lexical-ref> gensym)
  738. ;; lexical alias
  739. (let ((val* (vhash-assq gensym lexical-lambdas)))
  740. (if (pair? val*)
  741. (extend lexical-name (cdr val*) info)
  742. info)))
  743. ((<toplevel-ref> name)
  744. ;; top-level alias
  745. (make-arity-info toplevel-calls
  746. (vhash-consq lexical-name val
  747. lexical-lambdas)
  748. toplevel-lambdas))
  749. (else info))))
  750. (let ((toplevel-calls (toplevel-procedure-calls info))
  751. (lexical-lambdas (lexical-lambdas info))
  752. (toplevel-lambdas (toplevel-lambdas info)))
  753. (record-case x
  754. ((<toplevel-define> name exp)
  755. (record-case exp
  756. ((<lambda> body)
  757. (make-arity-info toplevel-calls
  758. lexical-lambdas
  759. (vhash-consq name exp toplevel-lambdas)))
  760. ((<toplevel-ref> name)
  761. ;; alias for another toplevel
  762. (let ((proc (vhash-assq name toplevel-lambdas)))
  763. (make-arity-info toplevel-calls
  764. lexical-lambdas
  765. (vhash-consq (toplevel-define-name x)
  766. (if (pair? proc)
  767. (cdr proc)
  768. exp)
  769. toplevel-lambdas))))
  770. (else info)))
  771. ((<let> gensyms vals)
  772. (fold extend info gensyms vals))
  773. ((<letrec> gensyms vals)
  774. (fold extend info gensyms vals))
  775. ((<fix> gensyms vals)
  776. (fold extend info gensyms vals))
  777. ((<call> proc args src)
  778. (record-case proc
  779. ((<lambda> body)
  780. (validate-arity proc x #t)
  781. info)
  782. ((<toplevel-ref> name)
  783. (make-arity-info (vhash-consq name x toplevel-calls)
  784. lexical-lambdas
  785. toplevel-lambdas))
  786. ((<lexical-ref> gensym)
  787. (let ((proc (vhash-assq gensym lexical-lambdas)))
  788. (if (pair? proc)
  789. (record-case (cdr proc)
  790. ((<toplevel-ref> name)
  791. ;; alias to toplevel
  792. (make-arity-info (vhash-consq name x toplevel-calls)
  793. lexical-lambdas
  794. toplevel-lambdas))
  795. (else
  796. (validate-arity (cdr proc) x #t)
  797. info))
  798. ;; If GENSYM wasn't found, it may be because it's an
  799. ;; argument of the procedure being compiled.
  800. info)))
  801. (else info)))
  802. (else info))))
  803. (lambda (x info env locs)
  804. ;; Up from X.
  805. (define (shrink name val info)
  806. ;; Remove NAME from the lexical-lambdas of INFO.
  807. (let ((toplevel-calls (toplevel-procedure-calls info))
  808. (lexical-lambdas (lexical-lambdas info))
  809. (toplevel-lambdas (toplevel-lambdas info)))
  810. (make-arity-info toplevel-calls
  811. (if (vhash-assq name lexical-lambdas)
  812. (vlist-tail lexical-lambdas)
  813. lexical-lambdas)
  814. toplevel-lambdas)))
  815. (let ((toplevel-calls (toplevel-procedure-calls info))
  816. (lexical-lambdas (lexical-lambdas info))
  817. (toplevel-lambdas (toplevel-lambdas info)))
  818. (record-case x
  819. ((<let> gensyms vals)
  820. (fold shrink info gensyms vals))
  821. ((<letrec> gensyms vals)
  822. (fold shrink info gensyms vals))
  823. ((<fix> gensyms vals)
  824. (fold shrink info gensyms vals))
  825. (else info))))
  826. (lambda (result env)
  827. ;; Post-processing: check all top-level procedure calls that have been
  828. ;; encountered.
  829. (let ((toplevel-calls (toplevel-procedure-calls result))
  830. (toplevel-lambdas (toplevel-lambdas result)))
  831. (vlist-for-each
  832. (lambda (name+call)
  833. (let* ((name (car name+call))
  834. (call (cdr name+call))
  835. (proc
  836. (or (and=> (vhash-assq name toplevel-lambdas) cdr)
  837. (and (module? env)
  838. (false-if-exception
  839. (module-ref env name)))))
  840. (proc*
  841. ;; handle toplevel aliases
  842. (if (toplevel-ref? proc)
  843. (let ((name (toplevel-ref-name proc)))
  844. (and (module? env)
  845. (false-if-exception
  846. (module-ref env name))))
  847. proc)))
  848. (cond ((lambda? proc*)
  849. (validate-arity proc* call #t))
  850. ((procedure? proc*)
  851. (validate-arity proc* call #f)))))
  852. toplevel-calls)))
  853. (make-arity-info vlist-null vlist-null vlist-null)))
  854. ;;;
  855. ;;; `format' argument analysis.
  856. ;;;
  857. (define &syntax-error
  858. ;; The `throw' key for syntax errors.
  859. (gensym "format-string-syntax-error"))
  860. (define (format-string-argument-count fmt)
  861. ;; Return the minimum and maxium number of arguments that should
  862. ;; follow format string FMT (or, ahem, a good estimate thereof) or
  863. ;; `any' if the format string can be followed by any number of
  864. ;; arguments.
  865. (define (drop-group chars end)
  866. ;; Drop characters from CHARS until "~END" is encountered.
  867. (let loop ((chars chars)
  868. (tilde? #f))
  869. (if (null? chars)
  870. (throw &syntax-error 'unterminated-iteration)
  871. (if tilde?
  872. (if (eq? (car chars) end)
  873. (cdr chars)
  874. (loop (cdr chars) #f))
  875. (if (eq? (car chars) #\~)
  876. (loop (cdr chars) #t)
  877. (loop (cdr chars) #f))))))
  878. (define (digit? char)
  879. ;; Return true if CHAR is a digit, #f otherwise.
  880. (memq char '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)))
  881. (define (previous-number chars)
  882. ;; Return the previous series of digits found in CHARS.
  883. (let ((numbers (take-while digit? chars)))
  884. (and (not (null? numbers))
  885. (string->number (list->string (reverse numbers))))))
  886. (let loop ((chars (string->list fmt))
  887. (state 'literal)
  888. (params '())
  889. (conditions '())
  890. (end-group #f)
  891. (min-count 0)
  892. (max-count 0))
  893. (if (null? chars)
  894. (if end-group
  895. (throw &syntax-error 'unterminated-conditional)
  896. (values min-count max-count))
  897. (case state
  898. ((tilde)
  899. (case (car chars)
  900. ((#\~ #\% #\& #\t #\T #\_ #\newline #\( #\) #\! #\| #\/ #\q #\Q)
  901. (loop (cdr chars) 'literal '()
  902. conditions end-group
  903. min-count max-count))
  904. ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\, #\: #\@ #\+ #\- #\#)
  905. (loop (cdr chars)
  906. 'tilde (cons (car chars) params)
  907. conditions end-group
  908. min-count max-count))
  909. ((#\v #\V) (loop (cdr chars)
  910. 'tilde (cons (car chars) params)
  911. conditions end-group
  912. (+ 1 min-count)
  913. (+ 1 max-count)))
  914. ((#\p #\P) (let* ((colon? (memq #\: params))
  915. (min-count (if colon?
  916. (max 1 min-count)
  917. (+ 1 min-count))))
  918. (loop (cdr chars) 'literal '()
  919. conditions end-group
  920. min-count
  921. (if colon?
  922. (max max-count min-count)
  923. (+ 1 max-count)))))
  924. ((#\[)
  925. (loop chars 'literal '() '()
  926. (let ((selector (previous-number params))
  927. (at? (memq #\@ params)))
  928. (lambda (chars conds)
  929. ;; end of group
  930. (let ((mins (map car conds))
  931. (maxs (map cdr conds))
  932. (sel? (and selector
  933. (< selector (length conds)))))
  934. (if (and (every number? mins)
  935. (every number? maxs))
  936. (loop chars 'literal '() conditions end-group
  937. (+ min-count
  938. (if sel?
  939. (car (list-ref conds selector))
  940. (+ (if at? 0 1)
  941. (if (null? mins)
  942. 0
  943. (apply min mins)))))
  944. (+ max-count
  945. (if sel?
  946. (cdr (list-ref conds selector))
  947. (+ (if at? 0 1)
  948. (if (null? maxs)
  949. 0
  950. (apply max maxs))))))
  951. (values 'any 'any))))) ;; XXX: approximation
  952. 0 0))
  953. ((#\;)
  954. (if end-group
  955. (loop (cdr chars) 'literal '()
  956. (cons (cons min-count max-count) conditions)
  957. end-group
  958. 0 0)
  959. (throw &syntax-error 'unexpected-semicolon)))
  960. ((#\])
  961. (if end-group
  962. (end-group (cdr chars)
  963. (reverse (cons (cons min-count max-count)
  964. conditions)))
  965. (throw &syntax-error 'unexpected-conditional-termination)))
  966. ((#\{) (if (memq #\@ params)
  967. (values min-count 'any)
  968. (loop (drop-group (cdr chars) #\})
  969. 'literal '()
  970. conditions end-group
  971. (+ 1 min-count) (+ 1 max-count))))
  972. ((#\*) (if (memq #\@ params)
  973. (values 'any 'any) ;; it's unclear what to do here
  974. (loop (cdr chars)
  975. 'literal '()
  976. conditions end-group
  977. (+ (or (previous-number params) 1)
  978. min-count)
  979. (+ (or (previous-number params) 1)
  980. max-count))))
  981. ((#\? #\k #\K)
  982. ;; We don't have enough info to determine the exact number
  983. ;; of args, but we could determine a lower bound (TODO).
  984. (values 'any 'any))
  985. ((#\^)
  986. (values min-count 'any))
  987. ((#\h #\H)
  988. (let ((argc (if (memq #\: params) 2 1)))
  989. (loop (cdr chars) 'literal '()
  990. conditions end-group
  991. (+ argc min-count)
  992. (+ argc max-count))))
  993. ((#\')
  994. (if (null? (cdr chars))
  995. (throw &syntax-error 'unexpected-termination)
  996. (loop (cddr chars) 'tilde (cons (cadr chars) params)
  997. conditions end-group min-count max-count)))
  998. (else (loop (cdr chars) 'literal '()
  999. conditions end-group
  1000. (+ 1 min-count) (+ 1 max-count)))))
  1001. ((literal)
  1002. (case (car chars)
  1003. ((#\~) (loop (cdr chars) 'tilde '()
  1004. conditions end-group
  1005. min-count max-count))
  1006. (else (loop (cdr chars) 'literal '()
  1007. conditions end-group
  1008. min-count max-count))))
  1009. (else (error "computer bought the farm" state))))))
  1010. (define (proc-ref? exp proc special-name env)
  1011. "Return #t when EXP designates procedure PROC in ENV. As a last
  1012. resort, return #t when EXP refers to the global variable SPECIAL-NAME."
  1013. (define special?
  1014. (cut eq? <> special-name))
  1015. (match exp
  1016. (($ <toplevel-ref> _ _ (? special?))
  1017. ;; Allow top-levels like: (define G_ (cut gettext <> "my-domain")).
  1018. #t)
  1019. (($ <toplevel-ref> _ _ name)
  1020. (let ((var (module-variable env name)))
  1021. (and var (variable-bound? var)
  1022. (eq? (variable-ref var) proc))))
  1023. (($ <module-ref> _ _ (? special?))
  1024. #t)
  1025. (($ <module-ref> _ module name public?)
  1026. (let* ((mod (if public?
  1027. (false-if-exception (resolve-interface module))
  1028. (resolve-module module #:ensure #f)))
  1029. (var (and mod (module-variable mod name))))
  1030. (and var (variable-bound? var) (eq? (variable-ref var) proc))))
  1031. (($ <lexical-ref> _ (? special?))
  1032. #t)
  1033. (_ #f)))
  1034. (define gettext? (cut proc-ref? <> gettext 'G_ <>))
  1035. (define ngettext? (cut proc-ref? <> ngettext 'N_ <>))
  1036. (define (const-fmt x env)
  1037. ;; Return the literal format string for X, or #f.
  1038. (match x
  1039. (($ <const> _ (? string? exp))
  1040. exp)
  1041. (($ <call> _ (? (cut gettext? <> env))
  1042. (($ <const> _ (? string? fmt))))
  1043. ;; Gettexted literals, like `(G_ "foo")'.
  1044. fmt)
  1045. (($ <call> _ (? (cut ngettext? <> env))
  1046. (($ <const> _ (? string? fmt)) ($ <const> _ (? string?)) _ ..1))
  1047. ;; Plural gettextized literals, like `(N_ "singular" "plural" n)'.
  1048. ;; TODO: Check whether the singular and plural strings have the
  1049. ;; same format escapes.
  1050. fmt)
  1051. (_ #f)))
  1052. (define format-analysis
  1053. ;; Report arity mismatches in the given tree.
  1054. (make-tree-analysis
  1055. (lambda (x res env locs)
  1056. ;; Down into X.
  1057. (define (check-format-args args loc)
  1058. (pmatch args
  1059. ((,port ,fmt . ,rest)
  1060. (guard (const-fmt fmt env))
  1061. (if (and (const? port)
  1062. (not (boolean? (const-exp port))))
  1063. (warning 'format loc 'wrong-port (const-exp port)))
  1064. (let ((fmt (const-fmt fmt env))
  1065. (count (length rest)))
  1066. (catch &syntax-error
  1067. (lambda ()
  1068. (let-values (((min max)
  1069. (format-string-argument-count fmt)))
  1070. (and min max
  1071. (or (and (or (eq? min 'any) (>= count min))
  1072. (or (eq? max 'any) (<= count max)))
  1073. (warning 'format loc 'wrong-format-arg-count
  1074. fmt min max count)))))
  1075. (lambda (_ key)
  1076. (warning 'format loc 'syntax-error key fmt)))))
  1077. ((,port ,fmt . ,rest)
  1078. (if (and (const? port)
  1079. (not (boolean? (const-exp port))))
  1080. (warning 'format loc 'wrong-port (const-exp port)))
  1081. (match fmt
  1082. (($ <const> loc* (? (negate string?) fmt))
  1083. (warning 'format (or loc* loc) 'wrong-format-string fmt))
  1084. ;; Warn on non-literal format strings, unless they refer to
  1085. ;; a lexical variable named "fmt".
  1086. (($ <lexical-ref> _ fmt)
  1087. #t)
  1088. ((? (negate const?))
  1089. (warning 'format loc 'non-literal-format-string))))
  1090. (else
  1091. (warning 'format loc 'wrong-num-args (length args)))))
  1092. (define (check-simple-format-args args loc)
  1093. ;; Check the arguments to the `simple-format' procedure, which is
  1094. ;; less capable than that of (ice-9 format).
  1095. (define allowed-chars
  1096. '(#\A #\S #\a #\s #\~ #\%))
  1097. (define (format-chars fmt)
  1098. (let loop ((chars (string->list fmt))
  1099. (result '()))
  1100. (match chars
  1101. (()
  1102. (reverse result))
  1103. ((#\~ opt rest ...)
  1104. (loop rest (cons opt result)))
  1105. ((_ rest ...)
  1106. (loop rest result)))))
  1107. (match args
  1108. ((port ($ <const> _ (? string? fmt)) _ ...)
  1109. (let ((opts (format-chars fmt)))
  1110. (or (every (cut memq <> allowed-chars) opts)
  1111. (begin
  1112. (warning 'format loc 'simple-format fmt
  1113. (find (negate (cut memq <> allowed-chars)) opts))
  1114. #f))))
  1115. ((port (= (cut const-fmt <> env) (? string? fmt)) args ...)
  1116. (check-simple-format-args `(,port ,(make-const loc fmt) ,args) loc))
  1117. (_ #t)))
  1118. (define (resolve-toplevel name)
  1119. (and (module? env)
  1120. (false-if-exception (module-ref env name))))
  1121. (match x
  1122. (($ <call> src ($ <toplevel-ref> _ _ name) args)
  1123. (let ((proc (resolve-toplevel name)))
  1124. (if (or (and (eq? proc (@ (guile) simple-format))
  1125. (check-simple-format-args args
  1126. (or src (find pair? locs))))
  1127. (eq? proc (@ (ice-9 format) format)))
  1128. (check-format-args args (or src (find pair? locs))))))
  1129. (($ <call> src ($ <module-ref> _ '(ice-9 format) 'format) args)
  1130. (check-format-args args (or src (find pair? locs))))
  1131. (($ <call> src ($ <module-ref> _ '(guile)
  1132. (or 'format 'simple-format))
  1133. args)
  1134. (and (check-simple-format-args args
  1135. (or src (find pair? locs)))
  1136. (check-format-args args (or src (find pair? locs)))))
  1137. (_ #t))
  1138. #t)
  1139. (lambda (x _ env locs)
  1140. ;; Up from X.
  1141. #t)
  1142. (lambda (_ env)
  1143. ;; Post-processing.
  1144. #t)
  1145. #t))
  1146. (begin-deprecated
  1147. (define-syntax unbound-variable-analysis
  1148. (identifier-syntax
  1149. (begin
  1150. (issue-deprecation-warning
  1151. "`unbound-variable-analysis' is deprecated. "
  1152. "Use `make-use-before-definition-analysis' instead.")
  1153. (make-use-before-definition-analysis
  1154. #:enabled-warnings '(unbound-variable)))))
  1155. (define-syntax macro-use-before-definition-analysis
  1156. (identifier-syntax
  1157. (begin
  1158. (issue-deprecation-warning
  1159. "`macro-use-before-definition-analysis' is deprecated. "
  1160. "Use `make-use-before-definition-analysis' instead.")
  1161. (make-use-before-definition-analysis
  1162. #:enabled-warnings '(macro-use-before-definition)))))
  1163. (export unbound-variable-analysis
  1164. macro-use-before-definition-analysis))
  1165. (define-syntax-rule (define-analysis make-analysis
  1166. #:level level #:kind kind #:analysis analysis)
  1167. (define* (make-analysis #:key (warning-level 0) (enabled-warnings '()))
  1168. (and (or (<= level warning-level)
  1169. (memq 'kind enabled-warnings))
  1170. analysis)))
  1171. (define-analysis make-unused-variable-analysis
  1172. #:level 3 #:kind unused-variable #:analysis unused-variable-analysis)
  1173. (define-analysis make-unused-toplevel-analysis
  1174. #:level 2 #:kind unused-toplevel #:analysis unused-toplevel-analysis)
  1175. (define-analysis make-shadowed-toplevel-analysis
  1176. #:level 2 #:kind shadowed-toplevel #:analysis shadowed-toplevel-analysis)
  1177. (define-analysis make-arity-analysis
  1178. #:level 1 #:kind arity-mismatch #:analysis arity-analysis)
  1179. (define-analysis make-format-analysis
  1180. #:level 1 #:kind format #:analysis format-analysis)
  1181. (define (make-analyzer warning-level warnings)
  1182. (define-syntax compute-analyses
  1183. (syntax-rules ()
  1184. ((_) '())
  1185. ((_ make-analysis . make-analysis*)
  1186. (let ((tail (compute-analyses . make-analysis*)))
  1187. (match (make-analysis #:warning-level warning-level
  1188. #:enabled-warnings warnings)
  1189. (#f tail)
  1190. (analysis (cons analysis tail)))))))
  1191. (let ((analyses (compute-analyses make-unused-variable-analysis
  1192. make-unused-toplevel-analysis
  1193. make-shadowed-toplevel-analysis
  1194. make-arity-analysis
  1195. make-format-analysis
  1196. make-use-before-definition-analysis)))
  1197. (lambda (exp env)
  1198. (analyze-tree analyses exp env))))