1 ;;; jde-javadoc.el --- JDE javadoc autodoc
4 ;; Copyright (C) 1998-2004 by David Ponce
6 ;; Author: David Ponce <david@dponce.com>
7 ;; Maintainer: David Ponce <david@dponce.com>
8 ;; Paul Kinnucan <paulk@mathworks.com>
10 ;; Keywords: java, tools
12 ;; This file is not part of Emacs
14 ;; This program is free software; you can redistribute it and/or
15 ;; modify it under the terms of the GNU General Public License as
16 ;; published by the Free Software Foundation; either version 2, or (at
17 ;; your option) any later version.
19 ;; This program is distributed in the hope that it will be useful, but
20 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 ;; General Public License for more details.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with this program; see the file COPYING. If not, write to
26 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
27 ;; Boston, MA 02111-1307, USA.
31 ;; This library provides a javadoc comment checker and generator to
32 ;; help handling of Java source documentation.
36 ;; See at end of this file.
41 (require 'semantic-java)
51 (defgroup jde-javadoc nil
52 "JDE javadoc utilities"
54 :prefix "jde-javadoc-")
56 ;; IMPORTANT: This function must be defined before the following
57 ;; defcustoms because it is used in their :set clause.
58 (defun jde-javadoc-define-template (sym val)
59 "Define a template (see `tempo-define-template').
60 The template name is the `symbol-name' of SYM from which the
61 '-template' suffix has been removed, prefixed by 'tempo-template-'.
62 VAL is the template value. If VAL is a string it is converted to a
63 list of template elements."
64 (let* ((name (symbol-name sym))
66 (if (string-match "\\(.*\\)-template$" name)
68 (error "Invalid template variable name: %S" name)))
71 (car (read-from-string (format "(%s)" val)))
73 (tempo-define-template template-name template-val nil name)
74 (set-default sym val)))
76 (defcustom jde-javadoc-describe-class-template
77 "\"* Describe class \" (jde-javadoc-code name) \" here.\""
78 "*Line template used to describe a class.
79 If nil the line is not inserted.
80 The variable 'name' is set to the class name.
81 See `jde-javadoc-autodoc-at-line' for usage. Define the template
82 variable `tempo-template-jde-javadoc-describe-class'."
84 :type '(choice :tag "Template form"
85 (text :format "%t\n%v" :tag "String")
86 (repeat :tag "Lisp Expressions" (sexp :tag "")))
87 :set 'jde-javadoc-define-template)
89 (defcustom jde-javadoc-describe-interface-template
90 "\"* Describe interface \" (jde-javadoc-code name) \" here.\""
91 "*Line template used to describe an interface.
92 If nil the line is not inserted.
93 The variable 'name' is set to the interface name.
94 See `jde-javadoc-autodoc-at-line' for usage. Define the template
95 variable `tempo-template-jde-javadoc-describe-interface'."
97 :type '(choice :tag "Template form"
98 (text :format "%t\n%v" :tag "String")
99 (repeat :tag "Lisp Expressions" (sexp :tag "")))
100 :set 'jde-javadoc-define-template)
102 (defcustom jde-javadoc-describe-constructor-template
103 "\"* Creates a new \" (jde-javadoc-code name) \" instance.\""
104 "*Line template used to describe a constructor.
105 If nil the line is not inserted.
106 The variable 'name' is set to the constructor name (that is the class
107 name). See `jde-javadoc-autodoc-at-line' for usage. Define the
108 template variable `tempo-template-jde-javadoc-describe-constructor'."
110 :type '(choice :tag "Template form"
111 (text :format "%t\n%v" :tag "String")
112 (repeat :tag "Lisp Expressions" (sexp :tag "")))
113 :set 'jde-javadoc-define-template)
115 (defcustom jde-javadoc-describe-method-template
116 "\"* Describe \" (jde-javadoc-code name) \" method here.\""
117 "*Line template used to describe a method.
118 If nil the line is not inserted.
119 The variable 'name' is set to the method name.
120 See `jde-javadoc-autodoc-at-line' for usage. Define the template
121 variable `tempo-template-jde-javadoc-describe-method'."
123 :type '(choice :tag "Template form"
124 (text :format "%t\n%v" :tag "String")
125 (repeat :tag "Lisp Expressions" (sexp :tag "")))
126 :set 'jde-javadoc-define-template)
128 (defcustom jde-javadoc-describe-field-template
129 "\"* Describe \" (jde-javadoc-field-type modifiers)
130 \" \" (jde-javadoc-code name) \" here.\""
131 "*Line template used to describe a method.
132 If nil the line is not inserted.
133 The variable 'name' is set to the field name.
134 The variable 'type' is set to the field type.
135 The variable 'modifiers' is set to the field modifiers.
136 See `jde-javadoc-autodoc-at-line' for usage. Define the template
137 variable `tempo-template-jde-javadoc-describe-field'."
139 :type '(choice :tag "Template form"
140 (text :format "%t\n%v" :tag "String")
141 (repeat :tag "Lisp Expressions" (sexp :tag "")))
142 :set 'jde-javadoc-define-template)
144 (defcustom jde-javadoc-param-tag-template
145 "\"* @param \" name \" \" (jde-javadoc-a type)
146 \" \" (jde-javadoc-code type) \" value\""
147 "*Line template used to describe a parameter.
148 If nil the line is not inserted.
149 The variable 'name' is set to the parameter name.
150 The variable 'type' is set to the parameter type.
151 A line is inserted for each parameter.
152 See `jde-javadoc-autodoc-at-line' for usage. Define the template
153 variable `tempo-template-jde-javadoc-param-tag'."
155 :type '(choice :tag "Template form"
156 (text :format "%t\n%v" :tag "String")
157 (repeat :tag "Lisp Expressions" (sexp :tag "")))
158 :set 'jde-javadoc-define-template)
160 (defcustom jde-javadoc-return-tag-template
161 "\"* @return \" (jde-javadoc-a type)
162 \" \" (jde-javadoc-code type) \" value\""
163 "*Line template used to describe a returned value.
164 If nil the line is not inserted.
165 The variable 'type' is set to the returned type.
166 See `jde-javadoc-autodoc-at-line' for usage. Define the template
167 variable `tempo-template-jde-javadoc-return-tag'."
169 :type '(choice :tag "Template form"
170 (text :format "%t\n%v" :tag "String")
171 (repeat :tag "Lisp Expressions" (sexp :tag "")))
172 :set 'jde-javadoc-define-template)
174 (defcustom jde-javadoc-exception-tag-template
175 "\"* @exception \" type \" if an error occurs\""
176 "*Line template used to describe an exception.
177 If nil the line is not inserted.
178 The variable 'type' is set to the exception type.
179 A line is inserted for each exception in the 'throws' clause.
180 See `jde-javadoc-autodoc-at-line' for usage. Define the template
181 variable `tempo-template-jde-javadoc-exception-tag'."
183 :type '(choice :tag "Template form"
184 (text :format "%t\n%v" :tag "String")
185 (repeat :tag "Lisp Expressions" (sexp :tag "")))
186 :set 'jde-javadoc-define-template)
188 (defcustom jde-javadoc-author-tag-template
189 "\"* @author <a href=\\\"mailto:\" user-mail-address
190 \"\\\">\" user-full-name \"</a>\""
191 "*Line template used to give an author.
192 If nil the line is not inserted.
193 See `jde-javadoc-autodoc-at-line' for usage. Define the template
194 variable `tempo-template-jde-javadoc-author-tag'."
196 :type '(choice :tag "Template form"
197 (text :format "%t\n%v" :tag "String")
198 (repeat :tag "Lisp Expressions" (sexp :tag "")))
199 :set 'jde-javadoc-define-template)
201 (defcustom jde-javadoc-version-tag-template
203 "*Line template used to give a version.
204 If nil the line is not inserted.
205 See `jde-javadoc-autodoc-at-line' for usage. Define the template
206 variable `tempo-template-jde-javadoc-version-tag'."
208 :type '(choice :tag "Template form"
209 (text :format "%t\n%v" :tag "String")
210 (repeat :tag "Lisp Expressions" (sexp :tag "")))
211 :set 'jde-javadoc-define-template)
213 ;; (defcustom jde-javadoc-see-tag-template
215 ;; "*Line template used to give a reference.
216 ;; If nil the line is not inserted.
217 ;; The variable 'ref' is set to the class or interface name.
218 ;; A line is inserted for each name in the 'extends' then 'implements'
219 ;; clauses. See `jde-javadoc-autodoc-at-line' for usage. Define the
220 ;; template variable `tempo-template-jde-javadoc-see-tag'."
221 ;; :group 'jde-javadoc
222 ;; :type '(choice :tag "Template form"
223 ;; (text :format "%t\n%v" :tag "String")
224 ;; (repeat :tag "Lisp Expressions" (sexp :tag "")))
225 ;; :set 'jde-javadoc-define-template)
227 ;; (defcustom jde-javadoc-since-tag-template
229 ;; "*Line template used to give a since reference.
230 ;; If nil the line is not inserted.
231 ;; See `jde-javadoc-autodoc-at-line' for usage. Define the template
232 ;; variable `tempo-template-jde-javadoc-since-tag'."
233 ;; :group 'jde-javadoc
234 ;; :type '(choice :tag "Template form"
235 ;; (text :format "%t\n%v" :tag "String")
236 ;; (repeat :tag "Lisp Expressions" (sexp :tag "")))
237 ;; :set 'jde-javadoc-define-template)
239 (defcustom jde-javadoc-end-block-template
241 "*Javadoc end comment block characters.
242 If nil \"*/\" is inserted.
243 See `jde-javadoc-autodoc-at-line' for usage. Define the template
244 variable `tempo-template-jde-javadoc-end-block'."
246 :type '(choice :tag "Template form"
247 (text :format "%t\n%v" :tag "String")
248 (repeat :tag "Lisp Expressions" (sexp :tag "")))
249 :set 'jde-javadoc-define-template)
253 (defmacro jde-javadoc-status-forms (message donestr &rest forms)
254 "Wrapper for `working-status-forms'.
255 See `working-status-forms' for details on MESSAGE, DONESTR and FORMS
256 arguments. Does not override an outer `working-status-forms'
258 `(working-status-forms (or working-message ,message) ,donestr
261 (defun jde-javadoc-dynamic-status (&rest args)
262 "Wrapper for `working-dynamic-status'.
263 Does nothing if not called within the macro `working-status-forms'.
264 See `working-dynamic-status' for meaning of ARGS."
266 (apply #'working-dynamic-status args)))
268 (defalias 'jde-javadoc-skip-spaces-forward
269 'semantic-java-skip-spaces-forward)
271 (defalias 'jde-javadoc-indent-line 'c-indent-line)
273 (defun jde-javadoc-indent-region (start end)
274 "Indent region between START and END."
277 (setq end (point-marker))
279 (while (< (point) end)
280 (jde-javadoc-dynamic-status)
281 (or (and (bolp) (eolp))
282 (jde-javadoc-indent-line))
284 (move-marker end nil)))
286 (defun jde-javadoc-map (f l &rest args)
287 "Apply F to each element of L.
288 F receives optional ARGS after the current element of L."
290 (apply f (car l) args)
293 (defun jde-javadoc-window-lines ()
294 "Return the number of lines of the selected window.
295 This number may be greater than the number of actual lines in the
296 buffer if any wrap on the display due to their length."
297 (let ((start (point-min))
304 (narrow-to-region start end)
306 (vertical-motion (buffer-size)))))))
308 (defun jde-javadoc-adjust-window (window)
309 "Adjust WINDOW height to fit its buffer contents."
310 (save-selected-window
311 (select-window window)
312 (let ((height (window-height))
313 (lines (+ 3 (jde-javadoc-window-lines))))
314 ;; ensure window will not be deleted if too small
315 (if (< lines window-min-height)
316 (setq lines window-min-height))
317 (enlarge-window (- lines height)))))
319 (defsubst jde-javadoc-variable-name (name)
320 "Return canonical variable name from NAME.
321 That is strip any array brackets from NAME."
322 (if (string-match "\\`\\([^[]+\\)[[]" name)
323 (match-string 1 name)
326 (defcustom jde-javadoc-check-undeclared-exception-flag nil
327 "*non-nil means to check for undeclared exceptions.
328 When an exception is implicitly declared (inherits from
329 RuntimeException) any associated @exception/@throws tag that already
330 exists will be just kept without issuing a warning. Other extra tags
331 are automatically removed.
333 If nil extra @exception/@throws tags are never removed but warnings
334 are issued for (maybe) undeclared exceptions."
338 (defun jde-javadoc-implicit-exception-p (type)
339 "Return non-nil if TYPE is an implicitly declared exception.
340 That is if TYPE inherits from java.lang.RuntimeException or if Java
341 reflection failed to process TYPE."
344 (format "jde.util.Completion.isAncestorOf(%S,%S);"
345 "java.lang.RuntimeException"
346 (jde-parse-get-qualified-name type)))
352 (defun jde-javadoc-field-type (modifiers)
353 "Return field category.
354 That is \"constant\" if field MODIFIERS contains \"static\" and
355 \"final\" or \"variable\" otherwise. Useful to generate field
357 (if (and (member "static" modifiers) (member "final" modifiers))
361 (defun jde-javadoc-a (word)
362 "Return \"an\" if WORD begin with a vowel or \"a\" otherwise.
363 Useful to generate description like \"an int value\" or \"a long value\"."
364 (if (string-match "^[aeiouyAEIOUY]" word)
367 (defun jde-javadoc-code (text)
368 "Return \"<code>TEXT</code>\".
369 Useful to generate HTML code style."
370 (concat "<code>" text "</code>"))
372 ;;;; Javadoc comment parser
373 ;;;; ----------------------
375 ;; tags and matchers (many are provided by Semantic)
377 (defconst jde-javadoc-desc-tag
379 "Special internal tag associated to descriptions.")
381 (defconst jde-javadoc-start-tag-regexp
382 "[\r\n][ \t]*\\(/\\*\\*\\|\\*?\\)[ \t]*@"
383 "Regexp matching the beginning of a tag.")
385 (defconst jde-javadoc-end-tag-regexp
386 (concat "\\(" jde-javadoc-start-tag-regexp
387 "\\|[ \n\r\t]*\\*/\\)")
388 "Regexp matching the end of a tag or description.")
390 ;; Core comment parser
392 (defun jde-javadoc-normalize-description (desc)
393 "Ensure DESC text begins with '\\n* ' and ends with '\\n*\\n'."
394 (let ((i (string-match "[^ *\n\r\t]" desc)))
396 (setq desc (concat "\n* " (substring desc i))))
397 ;; TODO: ensure empty line at end
400 (defun jde-javadoc-normalize-ref (val)
401 "Strip any [* \\n\\r\\t] from VAL."
402 (let* ((keep "[^* \n\r\t]+")
404 (i (string-match keep val))
407 (jde-javadoc-dynamic-status)
408 (setq j (match-end 0)
409 ref (concat ref (substring val i j))
410 i (string-match keep val j)))
413 (defun jde-javadoc-parse-description (docstring)
414 "Return the description from DOCSTRING or nil if not found.
415 The returned value has the form ((DESC)). See also
416 `jde-javadoc-parse-tag-values'."
417 (let ((matcher "/\\*\\*")
420 (when (string-match matcher docstring)
421 (jde-javadoc-dynamic-status)
422 (setq j (match-end 0))
423 (setq i (string-match jde-javadoc-end-tag-regexp docstring j))
425 (substring docstring j i)
426 (substring docstring j)))
427 ;; Ensure that a valid description exists
428 (if (not (string-equal ""
429 (jde-javadoc-normalize-ref tag-val)))
430 (list (list tag-val))))))
432 (defun jde-javadoc-parse-tag-values (docstring tag &optional with-key)
433 "Return from DOCSTRING the list of TAG values or nil if not found.
434 Each value is a pair (VALUE-STRING . VALUE-KEY). If optional WITH-KEY
435 is 'name VALUE-KEY is the first word of VALUE-STRING. If optional
436 WITH-KEY is 'ref VALUE-KEY is a normalized VALUE-STRING reference (see
437 `jde-javadoc-normalize-ref'). Otherwise VALUE-KEY is nil."
438 (let ((matcher (concat jde-javadoc-start-tag-regexp tag))
440 j tag-val key tag-list)
441 (while (string-match matcher docstring i)
442 (jde-javadoc-dynamic-status)
443 (setq j (match-end 0))
444 (setq i (or (string-match
445 jde-javadoc-end-tag-regexp docstring j)
447 (setq tag-val (substring docstring j i))
448 (cond ((eq with-key 'name)
449 (setq key (and (string-match
450 "[* \n\r\t]*\\([^ \n\r\t]+\\)" tag-val)
451 (jde-javadoc-variable-name
452 (match-string 1 tag-val)))))
454 (setq key (jde-javadoc-normalize-ref tag-val))))
455 (setq tag-list (cons (cons tag-val key) tag-list)))
456 (nreverse tag-list)))
458 (defun jde-javadoc-parse-tag (tag docstring)
459 "Return the TAG documentation from DOCSTRING or nil if not found.
460 Documentation has the form (TAG VALUE-LIST). See also
461 `jde-javadoc-parse-tag-values'."
462 (cond ((string-equal tag jde-javadoc-desc-tag)
463 (jde-javadoc-parse-description docstring))
464 ((member tag semantic-java-doc-with-name-tags)
465 (jde-javadoc-parse-tag-values docstring tag 'name))
466 ((member tag semantic-java-doc-with-ref-tags)
467 (jde-javadoc-parse-tag-values docstring tag 'ref))
469 (jde-javadoc-parse-tag-values docstring tag))
472 (defun jde-javadoc-parse-tag-list (docstring)
473 "Return the list of tag found in DOCSTRING."
474 (let* ((matcher (concat jde-javadoc-start-tag-regexp
475 "\\([^ \n\r\t]+\\)"))
476 (depth (regexp-opt-depth matcher))
477 (i (string-match matcher docstring))
480 (jde-javadoc-dynamic-status)
481 (setq tag-list (cons (match-string depth docstring) tag-list))
482 (setq i (string-match matcher docstring (match-end depth))))
483 (nreverse tag-list)))
485 (defun jde-javadoc-parse-docstring (docstring)
486 "Return the parsed documentation tree from DOCSTRING.
487 Result has the following form: (DOCSTRING TAG-LIST TAG-VALUE-ALIST)."
491 throws-assoc except-assoc merged-values)
492 (jde-javadoc-status-forms "Parsing" "done"
493 (jde-javadoc-dynamic-status)
494 (setq tag-list (jde-javadoc-parse-tag-list docstring))
495 (setq l (cons jde-javadoc-desc-tag tag-list))
497 (jde-javadoc-dynamic-status)
499 (if (assoc tag tag-alist)
500 nil ; tag already processed
503 (jde-javadoc-parse-tag tag docstring))
506 ;; The 'throws' and 'exception' tags are equivalent, so
507 ;; their values are merged to allow access to 'exception'
508 ;; tag using 'throws' and vice versa.
509 (jde-javadoc-dynamic-status)
510 (setq throws-assoc (assoc "throws" tag-alist))
511 (jde-javadoc-dynamic-status)
512 (setq except-assoc (assoc "exception" tag-alist))
513 (when (or throws-assoc except-assoc)
514 (jde-javadoc-dynamic-status)
515 (setq merged-values (append (cdr throws-assoc)
517 (jde-javadoc-dynamic-status)
519 (setcdr throws-assoc merged-values)
520 (setq tag-alist (cons (cons "throws" merged-values)
522 (jde-javadoc-dynamic-status)
524 (setcdr except-assoc merged-values)
525 (setq tag-alist (cons (cons "exception" merged-values)
527 (jde-javadoc-dynamic-status t))
528 (list docstring tag-list tag-alist))))
530 ;; Handling of javadoc comment parsed tree
532 (defmacro jde-javadoc-doctree-docstring (doctree)
533 "Return the docstring part of DOCTREE."
536 (defmacro jde-javadoc-doctree-tag-list (doctree)
537 "Return the tag-list part of DOCTREE."
538 `(car (cdr ,doctree)))
540 (defmacro jde-javadoc-doctree-tag-value-alist (doctree)
541 "Return the tag-value-alist part of DOCTREE."
542 `(car (cdr (cdr ,doctree))))
544 (defun jde-javadoc-doctree-tag (doctree tag &optional name)
545 "Return from DOCTREE the list of TAG values.
546 If optional NAME is non-nil return its specific value."
550 (jde-javadoc-doctree-tag-value-alist doctree)))))
553 (setq doc (rassoc name doc))
554 (setq doc (list doc)))
557 (defun jde-javadoc-doctree-known-tag-list (doctree)
558 "Return the list of known tags in DOCTREE .
559 That is tags in `semantic-java-doc-line-tags'."
563 (and (member tag semantic-java-doc-line-tags)
565 (jde-javadoc-doctree-tag-list doctree))))
567 (defun jde-javadoc-doctree-unknown-tag-list (doctree)
568 "Return the list of unknown tags in DOCTREE .
569 That is tags not in `semantic-java-doc-line-tags'."
573 (and (not (member tag semantic-java-doc-line-tags))
575 (jde-javadoc-doctree-tag-list doctree))))
577 ;;;; semantic tags stuff
578 ;;;; ---------------------
580 (defun jde-javadoc-tag-doctree (tag)
581 "Return the parsed documentation tree from TAG."
582 (jde-javadoc-parse-docstring
583 (semantic-documentation-for-tag tag t)))
585 (defun jde-javadoc-replace-documentation (tag &optional docstring)
586 "Replace TAG documentation with DOCSTRING.
587 If DOCSTRING is nil just delete the existing documentation."
588 (let* ((comment (semantic-documentation-for-tag tag 'flex))
591 (set-buffer (semantic-tag-buffer tag))
592 (setq start (semantic-lex-token-start comment))
593 (setq end (semantic-lex-token-end comment))
597 (jde-javadoc-skip-spaces-forward)
598 (delete-region start (point))
601 (jde-javadoc-indent-documentation tag))))))
603 (defun jde-javadoc-delete-documentation (tag &optional noconfirm)
604 "Delete TAG documentation.
605 Require confirmation if optional NOCONFIRM is non-nil. Return non-nil
608 (y-or-n-p (format "Delete '%s' previous documentation? "
609 (semantic-tag-name tag))))
611 (jde-javadoc-replace-documentation tag)
614 (defun jde-javadoc-recenter-documentation (tag &optional arg)
615 "Center TAG documentation in window and redisplay frame.
616 With ARG, put point on line ARG. See also `recenter'."
617 (let ((comment (semantic-documentation-for-tag tag 'flex))
620 (setq start (semantic-tag-start tag))
621 (set-buffer (semantic-tag-buffer tag))
622 (setq start (semantic-lex-token-start comment)))
626 (defun jde-javadoc-indent-documentation (tag)
627 "Indent TAG documentation."
629 (let ((comment (semantic-documentation-for-tag tag 'flex))
632 (set-buffer (semantic-tag-buffer tag))
633 (setq start (semantic-lex-token-start comment))
634 (setq end (semantic-lex-token-end comment))
636 (jde-javadoc-skip-spaces-forward)
637 (jde-javadoc-indent-region start (point))))))
642 (defconst jde-javadoc-checker-report-buffer "*jde-javadoc-checker*"
643 "Name of the checker report buffer.")
645 (defvar jde-javadoc-checker-tag nil
646 "Current checked tag.
647 Local to checker report buffer.")
649 (defvar jde-javadoc-checker-buffer nil
650 "Current checked buffer.
651 Local to checker report buffer.")
654 (require 'jde-java-font-lock)
657 (defvar jde-javadoc-checker-report-font-lock-keywords
661 1 'font-lock-warning-face)
663 (list "\\(@[^ \n\r\t]+\\)"
664 1 (cond ((boundp 'jde-java-font-lock-doc-tag-face)
665 'jde-java-font-lock-doc-tag-face)
667 'font-lock-keyword-face)
669 'font-lock-constant-face)))
671 (list "\\[\\([fnpq]\\)\\]"
672 1 'font-lock-keyword-face)
674 "Keywords used to highlight the checker report buffer.")
676 (defvar jde-javadoc-checker-report-mode-map nil
677 "Keymap used in `jde-javadoc-checker-report-mode'.")
679 (if jde-javadoc-checker-report-mode-map
681 (let ((keymap (make-sparse-keymap)))
682 (define-key keymap "q" 'jde-javadoc-checker-quit)
683 (define-key keymap "p" 'jde-javadoc-checker-previous)
684 (define-key keymap "n" 'jde-javadoc-checker-next)
685 (setq jde-javadoc-checker-report-mode-map keymap)))
687 (defun jde-javadoc-checker-report-mode ()
688 "Mode used in checker report buffer.
689 \\{jde-javadoc-checker-report-mode-map}"
690 (kill-all-local-variables)
691 (setq major-mode 'jde-javadoc-checker-report-mode)
692 (setq mode-name "jde-javadoc-checker")
693 (set (make-local-variable 'paragraph-start)
695 (set (make-local-variable 'paragraph-separate)
697 (set (make-local-variable 'font-lock-defaults)
698 '((jde-javadoc-checker-report-font-lock-keywords)
700 (use-local-map jde-javadoc-checker-report-mode-map)
703 (defun jde-javadoc-checker-show-report (report tag)
704 "Show the `jde-javadoc-checker' REPORT for TAG."
705 (let ((buffer (semantic-tag-buffer tag)))
707 (get-buffer-create jde-javadoc-checker-report-buffer)
708 (setq buffer-read-only nil)
710 (jde-javadoc-checker-report-mode)
711 (set (make-local-variable 'jde-javadoc-checker-buffer) buffer)
712 (set (make-local-variable 'jde-javadoc-checker-tag) tag)
715 (define-key (current-local-map) "f" 'jde-javadoc-checker-fix)
716 (insert (car report))
720 (let* ((from (point))
735 (insert "[f]-try to fix ")
738 (define-key (current-local-map) "f" nil)
739 (insert "Documentation is up-to-date")
741 (insert "[p]-check previous [n]-check next [q]-quit")
742 (goto-char (point-min))
743 (setq buffer-read-only t)
744 (pop-to-buffer (current-buffer))
745 (jde-javadoc-adjust-window
746 (get-buffer-window (current-buffer)))
748 (save-selected-window
749 (let ((window (get-buffer-window buffer)))
752 (select-window window)
753 (goto-char (semantic-tag-start tag))
754 (jde-javadoc-skip-spaces-forward)
755 (when (looking-at "/\\*\\*")
757 (jde-javadoc-skip-spaces-forward))
759 (semantic-momentary-highlight-tag tag))))
761 (defun jde-javadoc-check-add-summary (report type name)
762 "Add a summary to REPORT error list, using tag TYPE and NAME."
763 (and (setq report (delq nil report)) ;; Clear empty entries
764 (let* ((count (length report))
765 (eword (if (= count 1) "error" "errors")))
766 (cons (format "%s `%s' has %d documentation %s:"
767 type name count eword)
768 (nreverse report)))))
770 ;; Basic doc checkers
772 (defun jde-javadoc-check-description (doctree)
773 "Return a message if DOCTREE does not contain a description."
774 (if (jde-javadoc-doctree-tag doctree jde-javadoc-desc-tag)
776 "Missing description"))
778 (defun jde-javadoc-check-required-tags (doctree allowed extra
780 "Return a message if DOCTREE is missing a required tag.
781 ALLOWED and EXTRA are respectively the listes of allowed tags and
782 optional ones. Optional arguments NOCHECK can be a listes of tags
783 that are not checked."
786 (setq tag (car allowed)
787 allowed (cdr allowed))
788 (or (member tag extra)
790 (let ((ignored nocheck) ignore)
791 (while (and (not ignore) ignored)
792 (setq ignore (member tag (car ignored))
793 ignored (cdr ignored)))
795 ;; (member tag semantic-java-doc-with-name-tags)
796 (jde-javadoc-doctree-tag doctree tag)
797 (setq missing (cons tag missing))))
799 (concat "Missing tag"
800 (if (> (length missing) 1) "s @" " @")
801 (mapconcat 'identity missing ", @")))))
803 (defun jde-javadoc-check-suggest-tag-order (tag-list reference)
804 "Return a list of tags in suggested order from TAG-LIST.
805 REFERENCE is the list of tags allowed."
808 (if (member (car tag-list) semantic-java-doc-line-tags)
809 (and (member (car tag-list) reference)
810 (add-to-list 'otl (car tag-list)))
811 (add-to-list 'utl (car tag-list)))
812 (setq tag-list (cdr tag-list)))
813 (append (sort otl #'semantic-java-doc-keyword-before-p)
816 (defun jde-javadoc-check-tag-ordered (doctree reference)
817 "Return a message if tags in DOCTREE are not correctly ordered.
818 REFERENCE is the list of allowed tags in correct order. See variable
819 `semantic-java-doc-line-tags'."
820 (let* ((tag-list (jde-javadoc-doctree-tag-list doctree))
825 (jde-javadoc-dynamic-status)
826 (setq ok (semantic-java-doc-keyword-before-p tag (car l))
831 (concat "Recommended tag order is @"
833 (jde-javadoc-check-suggest-tag-order
837 (defun jde-javadoc-check-tag-allowed (doctree allowed)
838 "Return a message if some tags in DOCTREE are not in ALLOWED.
839 Third party tags (not in `semantic-java-doc-line-tags') are allways
846 (jde-javadoc-dynamic-status)
847 (and (member tag semantic-java-doc-line-tags)
848 (not (member tag allowed))
850 (jde-javadoc-doctree-tag-list doctree)))))
853 (concat "Invalid tag"
854 (if (> (length invalids) 1) "s @" " @")
855 (mapconcat 'identity invalids ", @")))))
857 ;; Tag based doc checkers
859 (defun jde-javadoc-check-type (tag doctree)
860 "Check doc of 'type' (class or interface) TAG.
861 DOCTREE is the current doctree of TAG. Return a non-nil report if
863 (let ((name (semantic-tag-name tag))
864 (type (semantic-tag-type tag))
865 (main (jde-javadoc-checker-main-type-p tag))
867 ;; Check for missing description
868 (jde-javadoc-dynamic-status)
871 (jde-javadoc-check-description doctree)
873 ;; Check for missing tags
874 (jde-javadoc-dynamic-status)
877 (jde-javadoc-check-required-tags
878 doctree semantic-java-doc-type-tags
879 semantic-java-doc-extra-type-tags
882 ;; Don't check these tags if internal type.
883 '("author" "version" "since")))
885 ;; Check for incorrect tag order
886 (jde-javadoc-dynamic-status)
889 (jde-javadoc-check-tag-ordered
890 doctree semantic-java-doc-type-tags)
892 ;; Check for invalid tags
893 (jde-javadoc-dynamic-status)
896 (jde-javadoc-check-tag-allowed
897 doctree semantic-java-doc-type-tags)
899 ;; Setup the error summary
900 (jde-javadoc-dynamic-status)
901 (jde-javadoc-check-add-summary report type name)))
903 (defun jde-javadoc-check-variable (tag doctree)
904 "Check doc of 'variable' (field) TAG.
905 DOCTREE is the current doctree of TAG. Return a non-nil report if
907 (let ((name (semantic-tag-name tag))
909 ;; Check for missing description
910 (jde-javadoc-dynamic-status)
913 (jde-javadoc-check-description doctree)
915 ;; Check for missing tags
916 (jde-javadoc-dynamic-status)
919 (jde-javadoc-check-required-tags
920 doctree semantic-java-doc-variable-tags
921 semantic-java-doc-extra-variable-tags)
923 ;; Check for incorrect tag order
924 (jde-javadoc-dynamic-status)
927 (jde-javadoc-check-tag-ordered
928 doctree semantic-java-doc-variable-tags)
930 ;; Check for invalid tags
931 (jde-javadoc-dynamic-status)
934 (jde-javadoc-check-tag-allowed
935 doctree semantic-java-doc-variable-tags)
937 ;; Setup the error summary
938 (jde-javadoc-dynamic-status)
939 (jde-javadoc-check-add-summary report "variable" name)))
941 (defun jde-javadoc-check-function (tag doctree)
942 "Check doc of 'function' (method or constructor) TAG.
943 DOCTREE is the current doctree of TAG. Return a non-nil report if
945 (let ((name (semantic-tag-name tag))
946 (type (semantic-tag-type tag))
947 (args (semantic-tag-function-arguments tag))
948 (throws (semantic-tag-function-throws tag))
950 ;; Check for missing description
951 (jde-javadoc-dynamic-status)
954 (jde-javadoc-check-description doctree)
956 ;; Check for missing tags
957 (jde-javadoc-dynamic-status)
960 (jde-javadoc-check-required-tags
961 doctree semantic-java-doc-function-tags
962 semantic-java-doc-extra-function-tags
963 ;; Don't check return, param and exception/throws tags.
964 '("return") semantic-java-doc-with-name-tags)
966 ;; Check for missing @param tags
969 (jde-javadoc-dynamic-status)
970 (if (semantic-tag-p (car args))
972 (setq item (jde-javadoc-variable-name
973 (semantic-tag-name (car args))))
974 (setq items (cons item items))
975 (or (jde-javadoc-doctree-tag doctree "param" item)
978 (format "Missing @param tag for `%s'" item)
980 (setq args (cdr args)))
981 ;; Check for extra @param tags
982 (setq args (jde-javadoc-doctree-tag doctree "param"))
984 (jde-javadoc-dynamic-status)
985 (setq item (jde-javadoc-variable-name (cdr (car args))))
986 (or (member item items)
987 (setq report (cons (format "Invalid @param tag `%s'" item)
989 (setq args (cdr args)))
990 ;; Check for missing @exception tags
993 (jde-javadoc-dynamic-status)
994 (setq item (car throws))
995 (setq items (cons item items))
996 (setq throws (cdr throws))
997 (or (jde-javadoc-doctree-tag doctree "exception" item)
1000 (format "Missing @exception tag for `%s'" item)
1002 ;; Check for extra @exception tags
1003 (setq args (jde-javadoc-doctree-tag doctree "exception"))
1005 (jde-javadoc-dynamic-status)
1006 (setq item (cdr (car args)))
1007 (or (member item items)
1008 (and jde-javadoc-check-undeclared-exception-flag
1009 (jde-javadoc-implicit-exception-p item))
1013 "Extra @exception tag `%s' (maybe not an error)"
1016 (setq args (cdr args)))
1017 ;; Check for missing or extra @return tag
1018 (setq item (jde-javadoc-doctree-tag doctree "return"))
1019 (jde-javadoc-dynamic-status)
1020 (cond ((and (not type) item)
1021 (setq report (cons "Invalid @return tag for constructor"
1023 ((and type (string-equal type "void") item)
1024 (setq report (cons "Invalid @return tag for void method"
1026 ((and type (not (string-equal type "void")) (not item))
1027 (setq report (cons "Missing @return tag"
1029 ;; Check for incorrect tag order
1030 (jde-javadoc-dynamic-status)
1033 (jde-javadoc-check-tag-ordered
1034 doctree semantic-java-doc-function-tags)
1036 ;; Check for invalid tags
1037 (jde-javadoc-dynamic-status)
1040 (jde-javadoc-check-tag-allowed
1041 doctree semantic-java-doc-function-tags)
1043 ;; Setup the error summary
1044 (jde-javadoc-dynamic-status)
1045 (jde-javadoc-check-add-summary report
1046 (if type "method" "constructor")
1049 (defun jde-javadoc-checker (tag &optional noreport)
1050 "Call the javadoc checker associated to TAG.
1051 If optional NOREPORT is non-nil does not show error report. Return a
1052 non-nil report if errors were found."
1053 (let* ((type (semantic-tag-class tag))
1054 (checker (intern (format "jde-javadoc-check-%s" type))))
1055 (or (fboundp checker)
1056 (error "No checker found to process '%S' tag" type))
1057 (goto-char (semantic-tag-start tag))
1059 (let (doctree report)
1060 (jde-javadoc-status-forms "Checking" "done"
1061 (jde-javadoc-dynamic-status)
1062 (setq doctree (jde-javadoc-tag-doctree tag))
1063 (setq report (funcall checker tag doctree))
1065 (jde-javadoc-checker-show-report report tag))
1066 (jde-javadoc-dynamic-status t))
1069 (defcustom jde-javadoc-checker-level 'protected
1070 "*Accessibility level to check.
1071 Only 'type, 'function or 'variable tags with this level will be
1072 checked. The level is defined to be consistent with the javadoc show
1075 - - public - check only public classes and members.
1076 - - protected - check only protected and public classes and
1077 members. This is the default.
1078 - - package - check only package, protected, and public classes
1080 - - private - check all classes and members."
1082 :type '(choice :tag "level"
1083 (const :tag "public" public)
1084 (const :tag "protected" protected)
1085 (const :tag "package" package)
1086 (const :tag "private" private)))
1088 (defconst jde-javadoc-access-level-weights
1093 "Java access level weights.")
1095 (defun jde-javadoc-access-level-lower-p (l1 l2)
1096 "Return non-nil if access level L1 is lower than L2."
1097 (< (cdr (assq l1 jde-javadoc-access-level-weights))
1098 (cdr (assq l2 jde-javadoc-access-level-weights))))
1100 (defun jde-javadoc-tag-access-level (tag)
1101 "Return the access level of TAG.
1102 That is 'public 'package 'protected or 'private. If TAG is included
1103 in other ones its access level is the lowest one found in the
1105 (let ((deps (semantic-find-tag-by-overlay
1106 (semantic-tag-start tag)
1107 (semantic-tag-buffer tag)))
1108 last-type tag categ modifiers levels)
1110 (setq tag (car deps))
1111 (setq deps (cdr deps))
1112 (setq categ (semantic-tag-class tag))
1116 (setq last-type (semantic-tag-type tag))
1117 (semantic-tag-modifiers tag))
1118 ((eq categ 'function)
1119 (if (string-equal last-type "interface")
1120 (list "public") ;; interface members are always public
1121 (semantic-tag-modifiers tag)))
1122 ((eq categ 'variable)
1123 (if (string-equal last-type "interface")
1124 (list "public") ;; interface members are always public
1125 (semantic-tag-modifiers tag)))
1126 (t ;; must never occurs
1127 (error "Invalid %s tag" categ))))
1129 (cons (cond ((member "public" modifiers)
1131 ((member "protected" modifiers)
1133 ((member "private" modifiers)
1138 (car (sort levels 'jde-javadoc-access-level-lower-p))))
1140 (defun jde-javadoc-checker-at-level-p (tag)
1141 "Return non-nil if checking is allowed for TAG.
1142 That is TAG accessibility level is greater than or equal to the one
1143 specified by `jde-javadoc-checker-level'. TAG category must be
1144 'type, 'function or 'variable."
1145 (let ((level (or jde-javadoc-checker-level 'protected)))
1146 ;; if level is 'private check all
1147 (or (eq level 'private)
1148 ;; else check if tag access level >= checker level
1149 (not (jde-javadoc-access-level-lower-p
1150 (jde-javadoc-tag-access-level tag)
1153 (defun jde-javadoc-checker-main-type-p (&optional tag)
1154 "Return non-nil if TAG is a main type one.
1155 That is not an internal class or interface."
1156 (setq tag (or tag (semantic-current-tag)))
1157 (and (eq (semantic-tag-class tag) 'type)
1158 (memq tag (semantic-brute-find-tag-by-class
1159 'type (current-buffer)))))
1161 (defun jde-javadoc-checker-do-find-previous-tag (tags &optional
1163 "Visit TAGS and return the tag before TAG.
1164 PREV is the last tag visited or nil at start. If TAG is nil
1165 return the last tag found. Return only a 'type 'function or
1167 (let (current categ)
1169 (setq current (car tags))
1170 (setq tags (cdr tags))
1171 (setq categ (semantic-tag-class current))
1172 (if (memq categ '(type function variable))
1176 (throw 'found prev)))
1177 ((>= (semantic-tag-start current)
1178 (semantic-tag-start tag))
1179 (throw 'found prev))
1182 (if (eq categ 'type)
1183 (jde-javadoc-checker-do-find-previous-tag
1184 (semantic-tag-type-members current)
1190 (defun jde-javadoc-checker-find-previous-tag (tags
1192 "Visit TAGS and return the tag before TAG.
1193 If TAG is nil return the last tag found. Return only a 'type
1194 'function or 'variable tag."
1196 (jde-javadoc-checker-do-find-previous-tag tags tag)))
1198 (defun jde-javadoc-checker-find-next-tag (tags &optional tag)
1199 "Visit TAGS and return the tag following TAG.
1200 If TAG is nil return the first tag found. Return only a 'type
1201 'function or 'variable tag."
1202 (let (current next categ)
1203 (while (and tags (not next))
1204 (setq current (car tags))
1205 (setq categ (semantic-tag-class current))
1206 (if (memq categ '(type function variable))
1208 (> (semantic-tag-start current)
1209 (semantic-tag-start tag)))
1211 (if (eq categ 'type)
1212 (setq next (jde-javadoc-checker-find-next-tag
1213 (semantic-tag-type-members current)
1215 (setq tags (cdr tags)))
1218 (defun jde-javadoc-checker-previous-tag (buffer &optional tag)
1219 "Report the previous tag in BUFFER with documentation errors.
1220 Start checking before TAG if non-nil or at the last tag found."
1221 (pop-to-buffer buffer)
1222 (let* ((tags (semantic-fetch-tags))
1223 (prev (jde-javadoc-checker-find-previous-tag
1226 (jde-javadoc-checker-at-level-p prev)
1227 (jde-javadoc-checker prev t))))
1228 (while (and prev (not report))
1229 (setq prev (jde-javadoc-checker-find-previous-tag
1231 (setq report (and prev
1232 (jde-javadoc-checker-at-level-p prev)
1233 (jde-javadoc-checker prev t))))
1235 (jde-javadoc-checker-show-report report prev)
1237 (if (y-or-n-p "No more doc error found. Quit? ")
1238 (jde-javadoc-checker-quit)
1239 (jde-javadoc-checker tag))
1240 (message "No doc errors found")
1241 (jde-javadoc-checker-quit)))))
1243 (defun jde-javadoc-checker-next-tag (buffer &optional tag)
1244 "Report the next tag in BUFFER with documentation errors.
1245 Start checking after TAG if non-nil or at the first tag found."
1246 (pop-to-buffer buffer)
1247 (let* ((tags (semantic-fetch-tags))
1248 (next (jde-javadoc-checker-find-next-tag tags tag))
1250 (jde-javadoc-checker-at-level-p next)
1251 (jde-javadoc-checker next t))))
1252 (while (and next (not report))
1253 (setq next (jde-javadoc-checker-find-next-tag tags next))
1254 (setq report (and next
1255 (jde-javadoc-checker-at-level-p next)
1256 (jde-javadoc-checker next t))))
1258 (jde-javadoc-checker-show-report report next)
1260 (if (y-or-n-p "No more doc error found. Quit? ")
1261 (jde-javadoc-checker-quit)
1262 (jde-javadoc-checker tag))
1263 (message "No doc errors found")
1264 (jde-javadoc-checker-quit)))))
1269 (defun jde-javadoc-insert (*name* &rest *texts*)
1270 "Insert the template *NAME* or *TEXTS* and a newline.
1271 If *NAME* value is nil *TEXTS* are inserted if non-nil. If *NAME* and
1272 *TEXTS* are nil the function does nothing.
1273 The name of variables local to this function are enclosed between
1274 \"*\" to avoid conflicts with variables used in templates."
1275 (cond ((and *name* (symbolp *name*) (symbol-value *name*))
1276 (tempo-insert-template *name* nil)
1279 (apply #'insert *texts*)
1284 (defun jde-javadoc-insert-start-block ()
1285 "Insert a javadoc comment block start '/**' at point."
1286 (jde-javadoc-insert nil "/**"))
1288 (defun jde-javadoc-insert-empty-line ()
1289 "Insert an empty javadoc line '*'."
1290 (jde-javadoc-insert nil "*"))
1292 (defun jde-javadoc-insert-end-block (&optional indent)
1293 "Insert a javadoc end comment block."
1294 (jde-javadoc-insert 'tempo-template-jde-javadoc-end-block "*/")
1296 (jde-javadoc-indent-line))
1297 nil) ;; must return nil to prevent template insertion.
1299 (defun jde-javadoc-insert-previous-description (doctree)
1300 "Insert a javadoc description if it already exists in DOCTREE."
1301 (let ((previous (jde-javadoc-doctree-tag
1302 doctree jde-javadoc-desc-tag)))
1307 (jde-javadoc-normalize-description (car (car previous)))))
1310 (defun jde-javadoc-insert-previous-tag (doctree tag &optional key)
1311 "If it already exists in DOCTREE, insert javadoc TAG value(s).
1312 If optional KEY is non-nil insert its specific value."
1313 (let ((previous (jde-javadoc-doctree-tag doctree tag key)))
1318 (jde-javadoc-dynamic-status)
1319 (jde-javadoc-insert nil "* @" tag (car item))))
1323 (defun jde-javadoc-insert-unknown-tags (doctree)
1324 "Insert unknown tags found in DOCTREE.
1325 See `jde-javadoc-doctree-unknown-tag-list'."
1329 (jde-javadoc-dynamic-status)
1330 (jde-javadoc-insert-previous-tag doctree tag)))
1331 (jde-javadoc-doctree-unknown-tag-list doctree)))
1333 (defun jde-javadoc-insert-author-tag (doctree)
1334 "Insert javadoc @author tags.
1335 If tags already exist in DOCTREE keep them, else insert a new default
1337 (or (jde-javadoc-insert-previous-tag doctree "author")
1338 (jde-javadoc-insert 'tempo-template-jde-javadoc-author-tag)))
1340 ;; (defun jde-javadoc-insert-since-tag (doctree)
1341 ;; "Insert a javadoc @since tag.
1342 ;; If tag already exists in DOCTREE keep it, else insert a new default
1344 ;; (or (jde-javadoc-insert-previous-tag doctree "since")
1345 ;; (jde-javadoc-insert 'tempo-template-jde-javadoc-since-tag)))
1347 (defun jde-javadoc-insert-version-tag (doctree)
1348 "Insert a javadoc @version tag.
1349 If tag already exists in DOCTREE keep it, else insert a new default
1351 (or (jde-javadoc-insert-previous-tag doctree "version")
1352 (jde-javadoc-insert 'tempo-template-jde-javadoc-version-tag)))
1354 ;; (defun jde-javadoc-insert-see-tag (doctree refs)
1355 ;; "Insert javadoc @see tags.
1356 ;; If tags already exist in DOCTREE keep them, else insert a new
1357 ;; default one for each item in REFS."
1358 ;; (or (jde-javadoc-insert-previous-tag doctree "see")
1362 ;; (and ref (not (string= ref ""))
1363 ;; (jde-javadoc-insert
1364 ;; 'tempo-template-jde-javadoc-see-tag))))
1367 (defun jde-javadoc-insert-param-tag (doctree type name)
1368 "Insert a javadoc @param tag.
1369 If tag already exists in DOCTREE keep it, else insert a new default
1370 one using parameter TYPE and NAME."
1371 (or (jde-javadoc-insert-previous-tag doctree "param" name)
1372 (and type (not (string= type ""))
1373 name (not (string= name ""))
1375 'tempo-template-jde-javadoc-param-tag))))
1377 (defun jde-javadoc-insert-exception-tag (doctree types)
1378 "Insert javadoc @exception tags.
1379 If tags already exist in DOCTREE keep them, else insert a new default
1380 one for each exception in TYPES."
1384 (jde-javadoc-dynamic-status)
1385 (or (jde-javadoc-insert-previous-tag doctree "exception" type)
1386 (and type (not (string= type ""))
1388 'tempo-template-jde-javadoc-exception-tag)))))
1390 ;; Keep extra exception tags (maybe not invalid tags)
1394 (jde-javadoc-dynamic-status)
1395 (setq type (cdr type))
1396 (or (member type types)
1397 (if (or (not jde-javadoc-check-undeclared-exception-flag)
1398 (jde-javadoc-implicit-exception-p type))
1399 (jde-javadoc-insert-previous-tag
1400 doctree "exception" type)))))
1401 (jde-javadoc-doctree-tag doctree "exception")))
1403 (defun jde-javadoc-insert-return-tag (doctree type)
1404 "Insert a javadoc @return tag.
1405 If tag already exists in DOCTREE keep it, else insert a new default
1406 one using return TYPE."
1407 (and type (not (string= type "void"))
1408 (or (jde-javadoc-insert-previous-tag doctree "return")
1410 'tempo-template-jde-javadoc-return-tag))))
1412 (defun jde-javadoc-insert-field-desc (doctree modifiers type name)
1413 "Insert a field description.
1414 If a description already exists in DOCTREE keep it, else insert a
1415 default one using field MODIFIERS TYPE and NAME."
1416 (if (jde-javadoc-insert-previous-description doctree)
1418 (jde-javadoc-insert-start-block)
1419 (jde-javadoc-insert 'tempo-template-jde-javadoc-describe-field)
1420 (jde-javadoc-insert-empty-line)))
1422 (defun jde-javadoc-insert-function-desc (doctree type name)
1423 "Insert a method or constructor description.
1424 If a description already exists in DOCTREE keep it, else insert a
1425 default one using method TYPE and NAME. If TYPE is nil insert a
1426 default constructor description."
1427 (if (jde-javadoc-insert-previous-description doctree)
1429 (jde-javadoc-insert-start-block)
1430 (if (and name (not (string= name "")))
1432 (if (and type (not (string= type "")))
1433 'tempo-template-jde-javadoc-describe-method
1434 'tempo-template-jde-javadoc-describe-constructor)))
1435 (jde-javadoc-insert-empty-line)))
1437 (defun jde-javadoc-insert-class-desc (doctree name)
1438 "Insert a class description.
1439 If a description already exists in DOCTREE keep it, else insert a
1440 default one using class NAME."
1441 (if (jde-javadoc-insert-previous-description doctree)
1443 (jde-javadoc-insert-start-block)
1444 (jde-javadoc-insert 'tempo-template-jde-javadoc-describe-class)
1445 (jde-javadoc-insert-empty-line)))
1447 (defun jde-javadoc-insert-interface-desc (doctree name)
1448 "Insert an interface description.
1449 If a description already exists in DOCTREE keep it, else insert a
1450 default one using interface NAME."
1451 (if (jde-javadoc-insert-previous-description doctree)
1453 (jde-javadoc-insert-start-block)
1455 'tempo-template-jde-javadoc-describe-interface)
1456 (jde-javadoc-insert-empty-line)))
1460 (defun jde-javadoc-type-doc (modifiers type name parents main
1462 "Document a class or interface using MODIFIERS TYPE NAME PARENTS.
1463 If MAIN is non-nil this is a main class or interface (not internal).
1464 If description and tags already exist in DOCTREE keep them."
1466 (jde-javadoc-dynamic-status)
1467 (if (string-equal type "interface")
1468 (jde-javadoc-insert-interface-desc doctree name)
1469 (jde-javadoc-insert-class-desc doctree name))
1472 (jde-javadoc-dynamic-status)
1473 (jde-javadoc-insert-author-tag doctree)
1475 (jde-javadoc-dynamic-status)
1476 (jde-javadoc-insert-version-tag doctree))
1477 ;; Keep extra optional tags if they already exist
1478 (jde-javadoc-dynamic-status)
1479 (jde-javadoc-map (function
1481 (jde-javadoc-insert-previous-tag doctree tag)))
1482 semantic-java-doc-extra-type-tags)
1483 ;; Keep unknown (not Sun's) tags
1484 (jde-javadoc-insert-unknown-tags doctree)
1485 ;; The end of comment block
1486 (jde-javadoc-dynamic-status)
1487 (jde-javadoc-insert-end-block t))
1489 (defun jde-javadoc-variable-doc (modifiers type name
1491 "Document a field using MODIFIERS TYPE NAME.
1492 If description and tags already exist in DOCTREE keep them."
1494 (jde-javadoc-insert-field-desc doctree modifiers type name)
1495 ;; Keep extra optional tags if they already exist
1496 (jde-javadoc-map (function
1498 (jde-javadoc-insert-previous-tag doctree tag)))
1499 semantic-java-doc-extra-variable-tags)
1500 ;; Keep unknown (not Sun's) tags
1501 (jde-javadoc-insert-unknown-tags doctree)
1502 ;; The end of comment block
1503 (jde-javadoc-insert-end-block t))
1505 (defun jde-javadoc-function-args-doc (tags &optional doctree)
1506 "Document function arguments in TAGS.
1507 If tags already exist in DOCTREE keep them."
1511 (if (semantic-tag-p tag) ; because TAGS can be (nil)
1512 (let ((modifiers (semantic-tag-modifiers tag))
1513 (type (semantic-tag-type tag))
1514 (name (semantic-tag-name tag)))
1515 (jde-javadoc-insert-param-tag doctree type name)))))
1518 (defun jde-javadoc-function-doc (modifiers type name args throws
1520 "Document a function using MODIFIERS TYPE NAME ARGS THROWS.
1521 If description and tags already exist in DOCTREE keep them."
1523 (jde-javadoc-insert-function-desc doctree type name)
1525 (jde-javadoc-function-args-doc args doctree)
1527 (jde-javadoc-insert-return-tag doctree type)
1529 (jde-javadoc-insert-exception-tag doctree throws)
1530 ;; Keep extra optional tags if they already exist
1531 (jde-javadoc-map (function
1533 (jde-javadoc-insert-previous-tag doctree tag)))
1534 semantic-java-doc-extra-function-tags)
1535 ;; Keep unknown (not Sun's) tags
1536 (jde-javadoc-insert-unknown-tags doctree)
1537 ;; The end of comment block
1538 (jde-javadoc-insert-end-block t))
1540 ;; Main tag based generators
1542 (defun jde-javadoc-type (tag doctree)
1543 "Document a 'type' (class or interface) TAG.
1544 DOCTREE is the current doctree of TAG."
1545 (let ((modifiers (semantic-tag-modifiers tag))
1546 (type (semantic-tag-type tag))
1547 (name (semantic-tag-name tag))
1548 (parents (semantic-tag-type-superclasses tag))
1549 (main (jde-javadoc-checker-main-type-p tag)))
1550 (jde-javadoc-dynamic-status)
1551 (jde-javadoc-type-doc modifiers type name parents main doctree)))
1553 (defun jde-javadoc-variable (tag doctree)
1554 "Document a 'variable' (field) TAG.
1555 DOCTREE is the current doctree of TAG."
1556 (let ((modifiers (semantic-tag-modifiers tag))
1557 (type (semantic-tag-type tag))
1558 (name (semantic-tag-name tag)))
1559 (jde-javadoc-dynamic-status)
1560 (jde-javadoc-variable-doc modifiers type name doctree)))
1562 (defun jde-javadoc-function (tag doctree)
1563 "Document a 'function' (method or constructor) TAG.
1564 DOCTREE is the current doctree of TAG."
1565 (let ((modifiers (semantic-tag-modifiers tag))
1566 (type (semantic-tag-type tag))
1567 (name (semantic-tag-name tag))
1568 (args (semantic-tag-function-arguments tag))
1569 (throws (semantic-tag-function-throws tag)))
1570 (jde-javadoc-dynamic-status)
1571 (jde-javadoc-function-doc
1572 modifiers type name args throws doctree)))
1574 (defun jde-javadoc-generator (tag &optional noconfirm)
1575 "Call the javadoc generator associated to TAG.
1576 Require confirmation to delete existing documentation if optional
1577 NOCONFIRM is non-nil."
1578 (let* ((type (semantic-tag-class tag))
1579 (generator (intern (format "jde-javadoc-%s" type)))
1580 (checker (intern (format "jde-javadoc-check-%s" type))))
1581 (or (fboundp generator)
1582 (error "No generator found to process '%S' tag" type))
1583 (goto-char (semantic-tag-start tag))
1584 (let ((report t) doctree)
1585 (jde-javadoc-status-forms "Updating" "done"
1586 (jde-javadoc-dynamic-status)
1587 (setq doctree (jde-javadoc-tag-doctree tag))
1588 (if (and (fboundp checker)
1589 (not (funcall checker tag doctree)))
1591 (let ((seas semantic-edits-are-safe))
1592 (make-local-variable 'semantic-edits-are-safe)
1595 (setq semantic-edits-are-safe t)
1596 (when (or (not doctree)
1597 (jde-javadoc-delete-documentation
1599 (funcall generator tag doctree)
1600 (jde-javadoc-indent-documentation tag)))
1601 (setq semantic-edits-are-safe seas))))
1602 (jde-javadoc-dynamic-status t))
1604 (message "Documentation is up-to-date")))))
1606 ;;;; Misc command auxiliaries
1607 ;;;; ------------------------
1609 (defun jde-javadoc-nonterminal-at-line ()
1610 "Search the bovine table for the tag at the current line."
1612 ;; Preserve current tags when the lexer fails (when there is an
1613 ;; unclosed block or an unterminated string for example).
1614 (let ((semantic-flex-unterminated-syntax-end-function
1615 #'(lambda (syntax &rest ignore)
1616 (throw 'jde-javadoc-flex-error syntax))))
1617 (catch 'jde-javadoc-flex-error
1618 (semantic-fetch-tags))))
1620 ;; Move the point to the first non-blank character found. Skip
1621 ;; spaces, tabs and newlines.
1623 ;; (jde-javadoc-skip-spaces-forward)
1624 (forward-comment (point-max))
1625 (semantic-current-tag)))
1627 (defvar jde-javadoc-checkdoc-excursion nil
1628 "Window configuration and point before running doc checker.")
1629 ;; Maybe `jde-javadoc-checkdoc-excursion' could be made buffer local?
1630 ;;(make-variable-buffer-local 'jde-javadoc-checkdoc-excursion)
1632 (defun jde-javadoc-checkdoc-clear-excursion ()
1633 "Clear saved window configuration and point.
1634 See also variable `jde-javadoc-checkdoc-excursion'."
1635 (setq jde-javadoc-checkdoc-excursion nil))
1637 (defun jde-javadoc-checkdoc-save-excursion ()
1638 "Save window configuration and point.
1639 See also function `jde-javadoc-checkdoc-restore-excursion'."
1640 (setq jde-javadoc-checkdoc-excursion
1641 (vector (current-window-configuration)
1644 (defun jde-javadoc-checkdoc-restore-excursion ()
1645 "Restore window configuration and point.
1646 See also function `jde-javadoc-checkdoc-save-excursion'."
1647 (let ((ex jde-javadoc-checkdoc-excursion))
1649 (window-configuration-p (aref ex 0))
1650 (integer-or-marker-p (aref ex 1))
1653 (set-window-configuration (aref ex 0))
1654 (goto-char (aref ex 1)))
1656 (jde-javadoc-checkdoc-clear-excursion)))
1662 (defun jde-javadoc-checker-previous ()
1663 "Go to the previous tag with doc errors."
1665 (and (eq major-mode 'jde-javadoc-checker-report-mode)
1666 (jde-javadoc-checker-previous-tag
1667 jde-javadoc-checker-buffer jde-javadoc-checker-tag)))
1670 (defun jde-javadoc-checker-next ()
1671 "Goto the next tag with doc errors."
1673 (and (eq major-mode 'jde-javadoc-checker-report-mode)
1674 (jde-javadoc-checker-next-tag jde-javadoc-checker-buffer
1675 jde-javadoc-checker-tag)))
1677 (defun jde-javadoc-checker-fix ()
1678 "Fix documentation of checked tag.
1679 Used in `jde-javadoc-checker-report-mode'."
1681 (and (eq major-mode 'jde-javadoc-checker-report-mode)
1682 (let ((tag jde-javadoc-checker-tag)
1683 (buffer jde-javadoc-checker-buffer))
1684 (when (and tag buffer)
1685 (pop-to-buffer buffer)
1686 (goto-char (semantic-tag-start tag))
1687 ;; do the fix (THE POINT STAY AT TAG START POSITION)
1688 (jde-javadoc-generator tag t)
1690 (jde-javadoc-checker tag)))))
1693 (defun jde-javadoc-checker-quit ()
1694 "Quit the `jde-javadoc-checker' report buffer.
1695 Used in `jde-javadoc-checker-report-mode'."
1697 (let ((buffer (get-buffer jde-javadoc-checker-report-buffer)))
1698 (if (bufferp buffer)
1699 (kill-buffer buffer))
1700 (jde-javadoc-checkdoc-restore-excursion)))
1703 (defun jde-javadoc-customize ()
1704 "Show the jde-javadoc options panel."
1706 (customize-group "jde-javadoc"))
1709 (defun jde-javadoc-autodoc-at-line ()
1710 "Update javadoc comment block for declaration at current line.
1712 Uses the semantic bovinator parser table to find declarations (see
1713 `jde-javadoc-nonterminal-at-line').
1715 BEFORE EXECUTING THE COMMAND, THE POINT MUST BE LOCATED AT THE FIRST
1716 LINE OF THE CLASS OR METHOD DECLARATION. IF NOT RESULT IS UNCERTAIN.
1718 In the following examples, point is located at the beginning of the
1719 line, before the word 'public' (but it could be anywhere on this
1725 -|- public class MyClass
1726 extends MySuperClass implements Runnable, java.io.Serializable
1730 \\[jde-javadoc-autodoc-at-line] inserts:
1733 + * Describe class <code>MyClass</code> here.
1735 + * @author \"David Ponce\" <david.ponce@wanadoo.fr>
1738 + * @see MySuperClass
1740 + * @see java.io.Serializable
1742 public class MyClass
1743 extends MySuperClass implements Runnable, java.io.Serializable
1751 void myMethod( int x, int y )
1756 \\[jde-javadoc-autodoc-at-line] inserts:
1759 + * Describe <code>myMethod</code> method here.
1761 + * @param x an <code>int</code> value
1762 + * @param y a <code>long</code> value
1763 + * @exception Exception if an error occurs
1766 void myMethod( int x, long y )
1774 -|- private static final int SIZE = 10;
1776 \\[jde-javadoc-autodoc-at-line] inserts:
1779 + * Describe constant <code>SIZE</code> here.
1781 private static final int SIZE = 10;
1784 `tempo' templates are used for each category of javadoc line. The
1785 following templates are currently defined and fully customizable (see
1786 `tempo-define-template' for the different items that can be used in a
1789 - - `jde-javadoc-author-tag-template'
1790 - - `jde-javadoc-describe-class-template'
1791 - - `jde-javadoc-describe-constructor-template'
1792 - - `jde-javadoc-describe-interface-template'
1793 - - `jde-javadoc-describe-method-template'
1794 - - `jde-javadoc-describe-field-template'
1795 - - `jde-javadoc-exception-tag-template'
1796 - - `jde-javadoc-param-tag-template'
1797 - - `jde-javadoc-return-tag-template'
1798 - - `jde-javadoc-version-tag-template'
1800 For example if you customize `jde-javadoc-describe-class-template'
1801 with the following value:
1803 '(\"* \" (P \"Class description: \"))
1805 you will be asked to enter the class description in the minibuffer.
1806 See also the `jde-javadoc-field-type', `jde-javadoc-a' and
1807 `jde-javadoc-code' helper functions."
1809 (or (eq major-mode 'jde-mode)
1810 (error "Major mode must be 'jde-mode'"))
1811 (let ((found (jde-javadoc-nonterminal-at-line)))
1813 (jde-javadoc-generator found)
1814 (error "No tag found at point"))))
1817 (defun jde-javadoc-remdoc-at-line (&optional noconfirm)
1818 "Remove javadoc comment block for declaration at current line.
1819 Require confirmation if optional NOCONFIRM is non-nil.
1820 Return non-nil if done.
1821 This uses `jde-javadoc-nonterminal-at-line' to find declarations."
1823 (jde-assert-source-buffer)
1824 (let ((found (jde-javadoc-nonterminal-at-line)))
1826 (error "No tag found at point")
1827 (jde-javadoc-delete-documentation found current-prefix-arg))))
1830 (defun jde-javadoc-checkdoc-at-line ()
1831 "Check javadoc comment block of declaration at current line.
1833 Uses the semantic bovinator parser table to find declarations (see
1834 `jde-javadoc-nonterminal-at-line').
1836 BEFORE EXECUTING THE COMMAND, THE POINT MUST BE LOCATED AT THE FIRST
1837 LINE OF THE CLASS OR METHOD DECLARATION. IF NOT RESULT IS UNCERTAIN."
1839 (jde-assert-source-buffer)
1840 (let ((found (jde-javadoc-nonterminal-at-line)))
1842 (error "No tag found at point")
1843 (jde-javadoc-checkdoc-save-excursion)
1844 (jde-javadoc-checker found))))
1847 (defun jde-javadoc-checkdoc ()
1848 "Check doc comments of tags in the current buffer.
1849 Report the next tag with documentation errors."
1851 (jde-assert-source-buffer)
1852 (semantic-fetch-tags)
1853 (jde-javadoc-checkdoc-save-excursion)
1854 (jde-javadoc-checker-next-tag (current-buffer)))
1856 (defalias 'jde-javadoc-autodoc 'jde-javadoc-checkdoc)
1860 (defalias 'jde-javadoc-generate-javadoc-template
1861 'jde-javadoc-autodoc-at-line)
1863 ;; Load the javadoc builder
1864 (require 'jde-javadoc-gen)
1867 (defun jde-javadoc-enable-menu-p ()
1868 "Return non-nil if corresponding doc menu item is enabled.
1869 That is point is on the first line of a class, method, or field
1871 (let ((p (save-excursion (beginning-of-line) (point)))
1872 (tag-at-line (jde-javadoc-nonterminal-at-line))
1875 (memq (semantic-tag-class tag-at-line)
1876 '(function type variable))
1880 (goto-char (semantic-tag-start tag-at-line))
1883 (setq end (or (re-search-forward "[;={]")
1888 (and (>= p start) (<= p end))))))
1890 ;; Register and initialize the customization variables defined
1892 (jde-update-autoloaded-symbols)
1894 (provide 'jde-javadoc)
1898 ;; $Log: jde-javadoc.el,v $
1899 ;; Revision 1.31 2004/07/08 12:17:00 paulk
1900 ;; Update to reflect semantic 2.0 tag (previously token) nomenclature. This is necessary to eliminate byte-compilation warnings.
1902 ;; Revision 1.30 2004/06/03 02:38:04 paulk
1903 ;; Add jde-javadoc-remdoc-at-line command. Thanks to David Ponce.
1905 ;; Revision 1.29 2004/05/04 04:40:36 paulk
1906 ;; Force reparsing with semantic 1.4.
1908 ;; Revision 1.28 2004/03/22 06:17:24 paulk
1909 ;; Committed for Martin Schwamberger. Make jde-javadoc-insert-end-block
1910 ;; ready for use in templates.
1912 ;; Revision 1.27 2003/09/21 03:33:20 paulk
1913 ;; - (jde-javadoc-checker-show-report): Better interaction with
1914 ;; libraries that use the header-line in GNU Emacs 21.
1916 ;; - (jde-javadoc-nonterminal-at-line): Use `forward-comment' to skip
1917 ;; comment at beginning of line.
1919 ;; Submitted by David Ponce.
1921 ;; Revision 1.26 2002/11/21 04:18:41 paulk
1922 ;; These packages, when autoloaded, now register and initialize the customization variables
1923 ;; that they define to the values specified in the current project file.
1925 ;; Revision 1.25 2002/10/11 05:53:22 paulk
1926 ;; Added more packages to the list of packages that are demand loaded. This is intended to reduce the startup time for the JDEE.
1928 ;; Revision 1.24 2002/09/30 04:54:09 paulk
1929 ;; Made all javadoc commands autoloadable.
1931 ;; Revision 1.23 2002/09/16 04:42:52 paulk
1932 ;; XEmacs compatibility fix: added require statement for regexp-opt package.
1934 ;; Revision 1.22 2002/06/23 17:37:36 jslopez
1935 ;; Removes carriage returns.
1937 ;; Revision 1.21 2002/06/22 06:25:26 paulk
1938 ;; Adds jde-javadoc-check-undeclared-exception-flag option. Thanks to David Ponce.
1940 ;; Revision 1.20 2001/12/14 03:17:50 paulk
1941 ;; jde-javadoc-nonterminal-at-line preserves current tokens when the
1942 ;; lexer fails (when there is an unclosed block or an unterminated
1943 ;; string for example). This enhancement works only with semantic 1.4
1944 ;; beta 13 (and above). With older versions
1945 ;; jde-javadoc-nonterminal-at-line continues to work as previously.
1946 ;; Thanks to David Ponce.
1948 ;; Revision 1.19 2001/08/06 05:25:21 paulk
1949 ;; jde-javadoc-parse-tag-values now removes the brackets from
1950 ;; VALUE-STRING when VALUE-KEY is 'name. This fixes checker error when
1951 ;; it tries to match an array name in javadoc comments and in argument
1952 ;; list. Thanks to David Ponce.
1954 ;; Revision 1.18 2001/05/19 02:36:00 paulk
1955 ;; Updated to support semantic 1.4. Thanks to David Ponce.
1957 ;; Revision 1.17 2001/01/27 05:42:07 paulk
1958 ;; Enhancements from David Ponce:
1960 ;; - Improved `jde-javadoc-start-tag-regexp' and
1961 ;; `jde-javadoc-end-tag-regexp' regular expressions which fix little
1962 ;; problems when parsing javadoc tags. These regexps enforce the
1963 ;; following rule (from JDK 1.3 documentation "javadoc - The Java
1964 ;; API Documentation Generator" - Chapter "DOCUMENTATION COMMENTS" -
1965 ;; "Standard and in-line tags":
1968 ;; "[...] a standard tag must appear at the beginning of a line,
1969 ;; ignoring leading asterisks, white space and comment separator
1970 ;; (/**). This means you can use the @ character elsewhere in the
1971 ;; text and it will not be interpreted as the start of a tag. If you
1972 ;; want to start a line with the @ character and not have it be
1973 ;; interpreted, use the HTML entity @. [...]"
1976 ;; - `jde-javadoc-checker-report-mode' now turns on `font-lock-mode'.
1977 ;; This is useful in XEmacs which don't have a
1978 ;; `global-font-lock-mode'.
1981 ;; - Filling of messages in `jde-javadoc-checker-show-report' now
1982 ;; works with XEmacs too.
1984 ;; Revision 1.16 2000/12/18 05:22:45 paulk
1985 ;; *** empty log message ***
1987 ;; Revision 1.15 2000/11/27 06:18:40 paulk
1988 ;; Miscellaneous bug fixes and minor enhancements.
1990 ;; Revision 1.14 2000/10/25 03:11:57 paulk
1991 ;; Enhancements from David Ponce:
1993 ;; * It is now possible to check javadoc comments only for tokens with
1994 ;; a specified access level. The new `jde-javadoc-checker-level'
1995 ;; option defines the accessibility level to check.
1997 ;; Only 'type, 'function or 'variable tokens with this level will be
1998 ;; checked. The level is defined to be consistent with the javadoc
1999 ;; show options. That is:
2001 ;; - - public - check only public classes and members.
2002 ;; - - protected - check only protected and public classes and
2003 ;; members. This is the default.
2004 ;; - - package - check only package, protected, and public classes
2006 ;; - - private - check all classes and members.
2008 ;; If a token is included in other ones its access level is the
2009 ;; lowest one found in the hierarchy.
2011 ;; Using `jde-javadoc-checkdoc-at-line' it is always possible to
2012 ;; check any token regardless of its access level.
2014 ;; * Changed '[u]-update' action by more appropriate '[f]-try to fix'
2015 ;; in the checker report dialog.
2017 ;; * Changed message "Invalid tag order, must be ..." by
2018 ;; "Recommended tag order is ...".
2020 ;; Revision 1.13 2000/10/22 07:54:04 paulk
2021 ;; Add menu enabler for javadoc commands.
2023 ;; Revision 1.12 2000/10/20 04:07:44 paulk
2024 ;; Enhancements from David Ponce.
2026 ;; Revision 1.11 2000/10/08 12:55:39 paulk
2027 ;; *** empty log message ***
2029 ;; Revision 1.10 2000/09/23 04:26:13 paulk Adds
2030 ;; jde-javadoc-command-path and jde-javadoc-display-doc
2031 ;; variables. Thanks to "Jason Stell" <Jason.Stell@globalone.net> for
2032 ;; providing the initial version of these changes.
2034 ;; Revision 1.9 2000/08/19 06:44:02 paulk
2035 ;; Don't quote class names in javadoc command.
2037 ;; Revision 1.8 2000/08/08 04:49:32 paulk
2038 ;; Fixed the doc for jde-javadoc-make.
2040 ;; Revision 1.7 2000/08/07 06:09:57 paulk jde-javadoc-make now uses
2041 ;; jde-db-source-directories as the sourcepath for generating doc.
2043 ;; Revision 1.6 2000/08/07 05:16:10 paulk Adds jde-javadoc-make
2044 ;; command. Thanks to Sergey A Klibanov <sakliban@cs.wustl.edu>.
2046 ;; Revision 1.5 2000/07/13 05:22:48 paulk
2047 ;; *** empty log message ***
2049 ;; Revision 1.4 2000/07/08 07:15:41 paulk
2050 ;; Latest updates from David.
2052 ;; Revision 1.2 2000/06/22 03:36:40 paulk
2053 ;; Fix submitted by David Ponce.
2055 ;; Revision 1.1 2000/06/12 08:19:03 paulk
2056 ;; Initial revision.
2060 ;;; jde-javadoc.el ends here