1 ;;; semantic/java.el --- Semantic functions for Java
3 ;;; Copyright (C) 1999-2011 Free Software Foundation, Inc.
5 ;; Author: David Ponce <david@dponce.com>
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24 ;; Common function for Java parsers.
28 (require 'semantic/ctxt)
29 (require 'semantic/doc)
30 (require 'semantic/format)
33 (require 'semantic/find)
34 (require 'semantic/dep))
39 (defconst semantic-java-number-regexp
42 "\\<[0-9]+[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
44 "\\<[0-9]+[.][eE][-+]?[0-9]+[fFdD]?\\>"
46 "\\<[0-9]+[.][fFdD]\\>"
50 "[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
52 "\\<[0-9]+[eE][-+]?[0-9]+[fFdD]?\\>"
54 "\\<0[xX][0-9a-fA-F]+[lL]?\\>"
56 "\\<[0-9]+[lLfFdD]?\\>"
59 "Lexer regexp to match Java number terminals.
60 Following is the specification of Java number literals.
72 <DECIMAL_LITERAL>[lL]?
74 | <OCTAL_LITERAL>[lL]?
79 FLOATING_POINT_LITERAL:
80 [0-9]+[.][0-9]*<EXPONENT>?[fFdD]?
81 | [.][0-9]+<EXPONENT>?[fFdD]?
82 | [0-9]+<EXPONENT>[fFdD]?
83 | [0-9]+<EXPONENT>?[fFdD]
88 (defsubst semantic-java-dim (id)
89 "Split ID string into a pair (NAME . DIM).
90 NAME is ID without trailing brackets: \"[]\".
91 DIM is the dimension of NAME deduced from the number of trailing
92 brackets, or 0 if there is no trailing brackets."
93 (let ((dim (string-match "\\(\\[]\\)+\\'" id)))
95 (cons (substring id 0 dim)
96 (/ (length (match-string 0 id)) 2))
99 (defsubst semantic-java-type (tag)
100 "Return the type of TAG, taking care of array notation."
101 (let ((type (semantic-tag-type tag))
102 (dim (semantic-tag-get-attribute tag :dereference)))
105 (setq type (concat type "[]")
109 (defun semantic-java-expand-tag (tag)
110 "Expand compound declarations found in TAG into separate tags.
111 TAG contains compound declarations when its class is `variable', and
112 its name is a list of elements (NAME START . END), where NAME is a
113 compound variable name, and START/END are the bounds of the
114 corresponding compound declaration."
115 (let* ((class (semantic-tag-class tag))
116 (elts (semantic-tag-name tag))
117 dim type dim0 elt clone start end xpand)
119 ((and (eq class 'function)
120 (> (cdr (setq dim (semantic-java-dim elts))) 0))
121 (setq clone (semantic-tag-clone tag (car dim))
122 xpand (cons clone xpand))
123 (semantic-tag-put-attribute clone :dereference (cdr dim)))
124 ((eq class 'variable)
125 (or (consp elts) (setq elts (list (list elts))))
126 (setq dim (semantic-java-dim (semantic-tag-get-attribute tag :type))
130 ;; For each compound element, clone the initial tag with the
131 ;; name and bounds of the compound variable declaration.
134 start (if elts (cadr elt) (semantic-tag-start tag))
135 end (if xpand (cddr elt) (semantic-tag-end tag))
136 dim (semantic-java-dim (car elt))
137 clone (semantic-tag-clone tag (car dim))
138 xpand (cons clone xpand))
139 (semantic-tag-put-attribute clone :type type)
140 (semantic-tag-put-attribute clone :dereference (+ dim0 (cdr dim)))
141 (semantic-tag-set-bounds clone start end)))
147 (defcustom-mode-local-semantic-dependency-system-include-path
148 java-mode semantic-java-dependency-system-include-path
149 ;; @todo - Use JDEE to get at the include path, or something else?
151 "The system include path used by Java language.")
155 (define-mode-local-override semantic-ctxt-scoped-types
156 java-mode (&optional point)
157 "Return a list of type names currently in scope at POINT."
158 (mapcar 'semantic-tag-name
159 (semantic-find-tags-by-class
160 'type (semantic-find-tag-by-overlay point))))
164 (defun semantic-java-prototype-function (tag &optional parent color)
165 "Return a function (method) prototype for TAG.
166 Optional argument PARENT is a parent (containing) item.
167 Optional argument COLOR indicates that color should be mixed in.
168 See also `semantic-format-tag-prototype'."
169 (let ((name (semantic-tag-name tag))
170 (type (semantic-java-type tag))
171 (tmpl (semantic-tag-get-attribute tag :template-specifier))
172 (args (semantic-tag-function-arguments tag))
178 (if (semantic-tag-p arg)
180 (semantic--format-colorize-text
181 (semantic-java-type arg) 'type)
182 (semantic-java-type arg))
183 argp (concat argp argt (if args "," "")))))
186 (setq type (semantic--format-colorize-text type 'type)))
187 (setq name (semantic--format-colorize-text name 'function)))
188 (concat (or tmpl "") (if tmpl " " "")
189 (or type "") (if type " " "")
192 (defun semantic-java-prototype-variable (tag &optional parent color)
193 "Return a variable (field) prototype for TAG.
194 Optional argument PARENT is a parent (containing) item.
195 Optional argument COLOR indicates that color should be mixed in.
196 See also `semantic-format-tag-prototype'."
197 (let ((name (semantic-tag-name tag))
198 (type (semantic-java-type tag)))
200 (semantic--format-colorize-text type 'type)
204 (semantic--format-colorize-text name 'variable)
207 (defun semantic-java-prototype-type (tag &optional parent color)
208 "Return a type (class/interface) prototype for TAG.
209 Optional argument PARENT is a parent (containing) item.
210 Optional argument COLOR indicates that color should be mixed in.
211 See also `semantic-format-tag-prototype'."
212 (let ((name (semantic-tag-name tag))
213 (type (semantic-tag-type tag))
214 (tmpl (semantic-tag-get-attribute tag :template-specifier)))
217 (semantic--format-colorize-text name 'type)
221 (define-mode-local-override semantic-format-tag-prototype
222 java-mode (tag &optional parent color)
223 "Return a prototype for TOKEN.
224 Optional argument PARENT is a parent (containing) item.
225 Optional argument COLOR indicates that color should be mixed in."
226 (let ((f (intern-soft (format "semantic-java-prototype-%s"
227 (semantic-tag-class tag)))))
228 (funcall (if (fboundp f)
230 'semantic-format-tag-prototype-default)
233 (semantic-alias-obsolete 'semantic-java-prototype-nonterminal
234 'semantic-format-tag-prototype-java-mode "23.2")
239 ;; Thanks Bruce Stephens
240 (define-mode-local-override semantic-tag-include-filename java-mode (tag)
241 "Return a suitable path for (some) Java imports."
242 (let ((name (semantic-tag-name tag)))
243 (concat (mapconcat 'identity (split-string name "\\.") "/") ".java")))
246 ;; Documentation handler
248 (defsubst semantic-java-skip-spaces-backward ()
249 "Move point backward, skipping Java whitespaces."
250 (skip-chars-backward " \n\r\t"))
252 (defsubst semantic-java-skip-spaces-forward ()
253 "Move point forward, skipping Java whitespaces."
254 (skip-chars-forward " \n\r\t"))
256 (define-mode-local-override semantic-documentation-for-tag
257 java-mode (&optional tag nosnarf)
258 "Find documentation from TAG and return it as a clean string.
259 Java has documentation set in a comment preceding TAG's definition.
260 Attempt to strip out comment syntactic sugar, unless optional argument
262 If NOSNARF is 'lex, then return the semantic lex token."
263 (when (or tag (setq tag (semantic-current-tag)))
264 (with-current-buffer (semantic-tag-buffer tag)
266 ;; Move the point at token start
267 (goto-char (semantic-tag-start tag))
268 (semantic-java-skip-spaces-forward)
269 ;; If the point already at "/**" (this occurs after a doc fix)
270 (if (looking-at "/\\*\\*")
272 ;; Skip previous spaces
273 (semantic-java-skip-spaces-backward)
274 ;; Ensure point is after "*/" (javadoc block comment end)
278 (when (looking-at "\\*/")
279 ;; Move the point backward across the comment
280 (forward-char 2) ; return just after "*/"
281 (forward-comment -1) ; to skip the entire block
283 ;; Verify the point is at "/**" (javadoc block comment start)
284 (if (looking-at "/\\*\\*")
286 (c (semantic-doc-snarf-comment-for-tag 'lex)))
288 ;; Verify that the token just following the doc
289 ;; comment is the current one!
290 (goto-char (semantic-lex-token-end c))
291 (semantic-java-skip-spaces-forward)
292 (when (eq tag (semantic-current-tag))
294 (semantic-doc-snarf-comment-for-tag nosnarf)))))
297 ;;; Javadoc facilities
302 (defvar semantic-java-doc-line-tags nil
303 "Valid javadoc line tags.
304 Ordered following Sun's Tag Convention at
305 <http://java.sun.com/products/jdk/javadoc/writingdoccomments/index.html>")
307 (defvar semantic-java-doc-with-name-tags nil
308 "Javadoc tags which have a name.")
310 (defvar semantic-java-doc-with-ref-tags nil
311 "Javadoc tags which have a reference.")
313 ;; Optional javadoc tags by classes of semantic tag
315 (defvar semantic-java-doc-extra-type-tags nil
316 "Optional tags used in class/interface documentation.
317 Ordered following Sun's Tag Convention.")
319 (defvar semantic-java-doc-extra-function-tags nil
320 "Optional tags used in method/constructor documentation.
321 Ordered following Sun's Tag Convention.")
323 (defvar semantic-java-doc-extra-variable-tags nil
324 "Optional tags used in field documentation.
325 Ordered following Sun's Tag Convention.")
327 ;; All javadoc tags by classes of semantic tag
329 (defvar semantic-java-doc-type-tags nil
330 "Tags allowed in class/interface documentation.
331 Ordered following Sun's Tag Convention.")
333 (defvar semantic-java-doc-function-tags nil
334 "Tags allowed in method/constructor documentation.
335 Ordered following Sun's Tag Convention.")
337 (defvar semantic-java-doc-variable-tags nil
338 "Tags allowed in field documentation.
339 Ordered following Sun's Tag Convention.")
341 ;; Access to Javadoc elements
343 (defmacro semantic-java-doc-tag (name)
344 "Return doc tag from NAME.
348 (defsubst semantic-java-doc-tag-name (tag)
349 "Return name of the doc TAG symbol.
350 That is TAG `symbol-name' without the leading '@'."
351 (substring (symbol-name tag) 1))
353 (defun semantic-java-doc-keyword-before-p (k1 k2)
354 "Return non-nil if javadoc keyword K1 is before K2."
355 (let* ((t1 (semantic-java-doc-tag k1))
356 (t2 (semantic-java-doc-tag k2))
357 (seq1 (and (semantic-lex-keyword-p t1)
358 (plist-get (semantic-lex-keyword-get t1 'javadoc)
360 (seq2 (and (semantic-lex-keyword-p t2)
361 (plist-get (semantic-lex-keyword-get t2 'javadoc)
363 (if (and (numberp seq1) (numberp seq2))
365 ;; Unknown tags (probably custom ones) are always after official
366 ;; ones and are not themselves ordered.
368 (and (not seq1) (not seq2))))))
370 (defun semantic-java-doc-keywords-map (fun &optional property)
371 "Run function FUN for each javadoc keyword.
372 Return the list of FUN results. If optional PROPERTY is non nil only
373 call FUN for javadoc keywords which have a value for PROPERTY. FUN
374 receives two arguments: the javadoc keyword and its associated
375 'javadoc property list. It can return any value. All nil values are
376 removed from the result list."
380 (let* ((tag (semantic-java-doc-tag k))
381 (plist (semantic-lex-keyword-get tag 'javadoc)))
382 (if (or (not property) (plist-get plist property))
383 (funcall fun k plist))))
384 semantic-java-doc-line-tags)))
390 (defun semantic-java-doc-setup ()
391 "Lazy initialization of javadoc elements."
392 (or semantic-java-doc-line-tags
393 (setq semantic-java-doc-line-tags
394 (sort (mapcar #'semantic-java-doc-tag-name
395 (semantic-lex-keywords 'javadoc))
396 #'semantic-java-doc-keyword-before-p)))
398 (or semantic-java-doc-with-name-tags
399 (setq semantic-java-doc-with-name-tags
400 (semantic-java-doc-keywords-map
405 (or semantic-java-doc-with-ref-tags
406 (setq semantic-java-doc-with-ref-tags
407 (semantic-java-doc-keywords-map
412 (or semantic-java-doc-extra-type-tags
413 (setq semantic-java-doc-extra-type-tags
414 (semantic-java-doc-keywords-map
416 (if (memq 'type (plist-get p 'usage))
420 (or semantic-java-doc-extra-function-tags
421 (setq semantic-java-doc-extra-function-tags
422 (semantic-java-doc-keywords-map
424 (if (memq 'function (plist-get p 'usage))
428 (or semantic-java-doc-extra-variable-tags
429 (setq semantic-java-doc-extra-variable-tags
430 (semantic-java-doc-keywords-map
432 (if (memq 'variable (plist-get p 'usage))
436 (or semantic-java-doc-type-tags
437 (setq semantic-java-doc-type-tags
438 (semantic-java-doc-keywords-map
440 (if (memq 'type (plist-get p 'usage))
443 (or semantic-java-doc-function-tags
444 (setq semantic-java-doc-function-tags
445 (semantic-java-doc-keywords-map
447 (if (memq 'function (plist-get p 'usage))
450 (or semantic-java-doc-variable-tags
451 (setq semantic-java-doc-variable-tags
452 (semantic-java-doc-keywords-map
454 (if (memq 'variable (plist-get p 'usage))
459 (provide 'semantic/java)
461 ;;; semantic/java.el ends here