java.el 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. ;;; semantic/java.el --- Semantic functions for Java
  2. ;;; Copyright (C) 1999-2012 Free Software Foundation, Inc.
  3. ;; Author: David Ponce <david@dponce.com>
  4. ;; This file is part of GNU Emacs.
  5. ;; GNU Emacs is free software: you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation, either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; GNU Emacs is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;
  17. ;; Common function for Java parsers.
  18. ;;; Code:
  19. (require 'semantic)
  20. (require 'semantic/ctxt)
  21. (require 'semantic/doc)
  22. (require 'semantic/format)
  23. (eval-when-compile
  24. (require 'semantic/find)
  25. (require 'semantic/dep))
  26. ;;; Lexical analysis
  27. ;;
  28. (defconst semantic-java-number-regexp
  29. (eval-when-compile
  30. (concat "\\("
  31. "\\<[0-9]+[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
  32. "\\|"
  33. "\\<[0-9]+[.][eE][-+]?[0-9]+[fFdD]?\\>"
  34. "\\|"
  35. "\\<[0-9]+[.][fFdD]\\>"
  36. "\\|"
  37. "\\<[0-9]+[.]"
  38. "\\|"
  39. "[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
  40. "\\|"
  41. "\\<[0-9]+[eE][-+]?[0-9]+[fFdD]?\\>"
  42. "\\|"
  43. "\\<0[xX][0-9a-fA-F]+[lL]?\\>"
  44. "\\|"
  45. "\\<[0-9]+[lLfFdD]?\\>"
  46. "\\)"
  47. ))
  48. "Lexer regexp to match Java number terminals.
  49. Following is the specification of Java number literals.
  50. DECIMAL_LITERAL:
  51. [1-9][0-9]*
  52. ;
  53. HEX_LITERAL:
  54. 0[xX][0-9a-fA-F]+
  55. ;
  56. OCTAL_LITERAL:
  57. 0[0-7]*
  58. ;
  59. INTEGER_LITERAL:
  60. <DECIMAL_LITERAL>[lL]?
  61. | <HEX_LITERAL>[lL]?
  62. | <OCTAL_LITERAL>[lL]?
  63. ;
  64. EXPONENT:
  65. [eE][+-]?[09]+
  66. ;
  67. FLOATING_POINT_LITERAL:
  68. [0-9]+[.][0-9]*<EXPONENT>?[fFdD]?
  69. | [.][0-9]+<EXPONENT>?[fFdD]?
  70. | [0-9]+<EXPONENT>[fFdD]?
  71. | [0-9]+<EXPONENT>?[fFdD]
  72. ;")
  73. ;;; Parsing
  74. ;;
  75. (defsubst semantic-java-dim (id)
  76. "Split ID string into a pair (NAME . DIM).
  77. NAME is ID without trailing brackets: \"[]\".
  78. DIM is the dimension of NAME deduced from the number of trailing
  79. brackets, or 0 if there is no trailing brackets."
  80. (let ((dim (string-match "\\(\\[]\\)+\\'" id)))
  81. (if dim
  82. (cons (substring id 0 dim)
  83. (/ (length (match-string 0 id)) 2))
  84. (cons id 0))))
  85. (defsubst semantic-java-type (tag)
  86. "Return the type of TAG, taking care of array notation."
  87. (let ((type (semantic-tag-type tag))
  88. (dim (semantic-tag-get-attribute tag :dereference)))
  89. (when dim
  90. (while (> dim 0)
  91. (setq type (concat type "[]")
  92. dim (1- dim))))
  93. type))
  94. (defun semantic-java-expand-tag (tag)
  95. "Expand compound declarations found in TAG into separate tags.
  96. TAG contains compound declarations when its class is `variable', and
  97. its name is a list of elements (NAME START . END), where NAME is a
  98. compound variable name, and START/END are the bounds of the
  99. corresponding compound declaration."
  100. (let* ((class (semantic-tag-class tag))
  101. (elts (semantic-tag-name tag))
  102. dim type dim0 elt clone start end xpand)
  103. (cond
  104. ((and (eq class 'function)
  105. (> (cdr (setq dim (semantic-java-dim elts))) 0))
  106. (setq clone (semantic-tag-clone tag (car dim))
  107. xpand (cons clone xpand))
  108. (semantic-tag-put-attribute clone :dereference (cdr dim)))
  109. ((eq class 'variable)
  110. (or (consp elts) (setq elts (list (list elts))))
  111. (setq dim (semantic-java-dim (semantic-tag-get-attribute tag :type))
  112. type (car dim)
  113. dim0 (cdr dim))
  114. (while elts
  115. ;; For each compound element, clone the initial tag with the
  116. ;; name and bounds of the compound variable declaration.
  117. (setq elt (car elts)
  118. elts (cdr elts)
  119. start (if elts (cadr elt) (semantic-tag-start tag))
  120. end (if xpand (cddr elt) (semantic-tag-end tag))
  121. dim (semantic-java-dim (car elt))
  122. clone (semantic-tag-clone tag (car dim))
  123. xpand (cons clone xpand))
  124. (semantic-tag-put-attribute clone :type type)
  125. (semantic-tag-put-attribute clone :dereference (+ dim0 (cdr dim)))
  126. (semantic-tag-set-bounds clone start end)))
  127. )
  128. xpand))
  129. ;;; Environment
  130. ;;
  131. (defcustom-mode-local-semantic-dependency-system-include-path
  132. java-mode semantic-java-dependency-system-include-path
  133. ;; @todo - Use JDEE to get at the include path, or something else?
  134. nil
  135. "The system include path used by Java language.")
  136. ;; Local context
  137. ;;
  138. (define-mode-local-override semantic-ctxt-scoped-types
  139. java-mode (&optional point)
  140. "Return a list of type names currently in scope at POINT."
  141. (mapcar 'semantic-tag-name
  142. (semantic-find-tags-by-class
  143. 'type (semantic-find-tag-by-overlay point))))
  144. ;; Prototype handler
  145. ;;
  146. (defun semantic-java-prototype-function (tag &optional parent color)
  147. "Return a function (method) prototype for TAG.
  148. Optional argument PARENT is a parent (containing) item.
  149. Optional argument COLOR indicates that color should be mixed in.
  150. See also `semantic-format-tag-prototype'."
  151. (let ((name (semantic-tag-name tag))
  152. (type (semantic-java-type tag))
  153. (tmpl (semantic-tag-get-attribute tag :template-specifier))
  154. (args (semantic-tag-function-arguments tag))
  155. (argp "")
  156. arg argt)
  157. (while args
  158. (setq arg (car args)
  159. args (cdr args))
  160. (if (semantic-tag-p arg)
  161. (setq argt (if color
  162. (semantic--format-colorize-text
  163. (semantic-java-type arg) 'type)
  164. (semantic-java-type arg))
  165. argp (concat argp argt (if args "," "")))))
  166. (when color
  167. (when type
  168. (setq type (semantic--format-colorize-text type 'type)))
  169. (setq name (semantic--format-colorize-text name 'function)))
  170. (concat (or tmpl "") (if tmpl " " "")
  171. (or type "") (if type " " "")
  172. name "(" argp ")")))
  173. (defun semantic-java-prototype-variable (tag &optional parent color)
  174. "Return a variable (field) prototype for TAG.
  175. Optional argument PARENT is a parent (containing) item.
  176. Optional argument COLOR indicates that color should be mixed in.
  177. See also `semantic-format-tag-prototype'."
  178. (let ((name (semantic-tag-name tag))
  179. (type (semantic-java-type tag)))
  180. (concat (if color
  181. (semantic--format-colorize-text type 'type)
  182. type)
  183. " "
  184. (if color
  185. (semantic--format-colorize-text name 'variable)
  186. name))))
  187. (defun semantic-java-prototype-type (tag &optional parent color)
  188. "Return a type (class/interface) prototype for TAG.
  189. Optional argument PARENT is a parent (containing) item.
  190. Optional argument COLOR indicates that color should be mixed in.
  191. See also `semantic-format-tag-prototype'."
  192. (let ((name (semantic-tag-name tag))
  193. (type (semantic-tag-type tag))
  194. (tmpl (semantic-tag-get-attribute tag :template-specifier)))
  195. (concat type " "
  196. (if color
  197. (semantic--format-colorize-text name 'type)
  198. name)
  199. (or tmpl ""))))
  200. (define-mode-local-override semantic-format-tag-prototype
  201. java-mode (tag &optional parent color)
  202. "Return a prototype for TOKEN.
  203. Optional argument PARENT is a parent (containing) item.
  204. Optional argument COLOR indicates that color should be mixed in."
  205. (let ((f (intern-soft (format "semantic-java-prototype-%s"
  206. (semantic-tag-class tag)))))
  207. (funcall (if (fboundp f)
  208. f
  209. 'semantic-format-tag-prototype-default)
  210. tag parent color)))
  211. (semantic-alias-obsolete 'semantic-java-prototype-nonterminal
  212. 'semantic-format-tag-prototype-java-mode "23.2")
  213. ;; Include Tag Name
  214. ;;
  215. ;; Thanks Bruce Stephens
  216. (define-mode-local-override semantic-tag-include-filename java-mode (tag)
  217. "Return a suitable path for (some) Java imports."
  218. (let ((name (semantic-tag-name tag)))
  219. (concat (mapconcat 'identity (split-string name "\\.") "/") ".java")))
  220. ;; Documentation handler
  221. ;;
  222. (defsubst semantic-java-skip-spaces-backward ()
  223. "Move point backward, skipping Java whitespaces."
  224. (skip-chars-backward " \n\r\t"))
  225. (defsubst semantic-java-skip-spaces-forward ()
  226. "Move point forward, skipping Java whitespaces."
  227. (skip-chars-forward " \n\r\t"))
  228. (define-mode-local-override semantic-documentation-for-tag
  229. java-mode (&optional tag nosnarf)
  230. "Find documentation from TAG and return it as a clean string.
  231. Java have documentation set in a comment preceding TAG's definition.
  232. Attempt to strip out comment syntactic sugar, unless optional argument
  233. NOSNARF is non-nil.
  234. If NOSNARF is 'lex, then return the semantic lex token."
  235. (when (or tag (setq tag (semantic-current-tag)))
  236. (with-current-buffer (semantic-tag-buffer tag)
  237. (save-excursion
  238. ;; Move the point at token start
  239. (goto-char (semantic-tag-start tag))
  240. (semantic-java-skip-spaces-forward)
  241. ;; If the point already at "/**" (this occurs after a doc fix)
  242. (if (looking-at "/\\*\\*")
  243. nil
  244. ;; Skip previous spaces
  245. (semantic-java-skip-spaces-backward)
  246. ;; Ensure point is after "*/" (javadoc block comment end)
  247. (condition-case nil
  248. (backward-char 2)
  249. (error nil))
  250. (when (looking-at "\\*/")
  251. ;; Move the point backward across the comment
  252. (forward-char 2) ; return just after "*/"
  253. (forward-comment -1) ; to skip the entire block
  254. ))
  255. ;; Verify the point is at "/**" (javadoc block comment start)
  256. (if (looking-at "/\\*\\*")
  257. (let ((p (point))
  258. (c (semantic-doc-snarf-comment-for-tag 'lex)))
  259. (when c
  260. ;; Verify that the token just following the doc
  261. ;; comment is the current one!
  262. (goto-char (semantic-lex-token-end c))
  263. (semantic-java-skip-spaces-forward)
  264. (when (eq tag (semantic-current-tag))
  265. (goto-char p)
  266. (semantic-doc-snarf-comment-for-tag nosnarf)))))
  267. ))))
  268. ;;; Javadoc facilities
  269. ;;
  270. ;; Javadoc elements
  271. ;;
  272. (defvar semantic-java-doc-line-tags nil
  273. "Valid javadoc line tags.
  274. Ordered following Sun's Tag Convention at
  275. <http://java.sun.com/products/jdk/javadoc/writingdoccomments/index.html>")
  276. (defvar semantic-java-doc-with-name-tags nil
  277. "Javadoc tags which have a name.")
  278. (defvar semantic-java-doc-with-ref-tags nil
  279. "Javadoc tags which have a reference.")
  280. ;; Optional javadoc tags by classes of semantic tag
  281. ;;
  282. (defvar semantic-java-doc-extra-type-tags nil
  283. "Optional tags used in class/interface documentation.
  284. Ordered following Sun's Tag Convention.")
  285. (defvar semantic-java-doc-extra-function-tags nil
  286. "Optional tags used in method/constructor documentation.
  287. Ordered following Sun's Tag Convention.")
  288. (defvar semantic-java-doc-extra-variable-tags nil
  289. "Optional tags used in field documentation.
  290. Ordered following Sun's Tag Convention.")
  291. ;; All javadoc tags by classes of semantic tag
  292. ;;
  293. (defvar semantic-java-doc-type-tags nil
  294. "Tags allowed in class/interface documentation.
  295. Ordered following Sun's Tag Convention.")
  296. (defvar semantic-java-doc-function-tags nil
  297. "Tags allowed in method/constructor documentation.
  298. Ordered following Sun's Tag Convention.")
  299. (defvar semantic-java-doc-variable-tags nil
  300. "Tags allowed in field documentation.
  301. Ordered following Sun's Tag Convention.")
  302. ;; Access to Javadoc elements
  303. ;;
  304. (defmacro semantic-java-doc-tag (name)
  305. "Return doc tag from NAME.
  306. That is @NAME."
  307. `(concat "@" ,name))
  308. (defsubst semantic-java-doc-tag-name (tag)
  309. "Return name of the doc TAG symbol.
  310. That is TAG `symbol-name' without the leading '@'."
  311. (substring (symbol-name tag) 1))
  312. (defun semantic-java-doc-keyword-before-p (k1 k2)
  313. "Return non-nil if javadoc keyword K1 is before K2."
  314. (let* ((t1 (semantic-java-doc-tag k1))
  315. (t2 (semantic-java-doc-tag k2))
  316. (seq1 (and (semantic-lex-keyword-p t1)
  317. (plist-get (semantic-lex-keyword-get t1 'javadoc)
  318. 'seq)))
  319. (seq2 (and (semantic-lex-keyword-p t2)
  320. (plist-get (semantic-lex-keyword-get t2 'javadoc)
  321. 'seq))))
  322. (if (and (numberp seq1) (numberp seq2))
  323. (<= seq1 seq2)
  324. ;; Unknown tags (probably custom ones) are always after official
  325. ;; ones and are not themselves ordered.
  326. (or (numberp seq1)
  327. (and (not seq1) (not seq2))))))
  328. (defun semantic-java-doc-keywords-map (fun &optional property)
  329. "Run function FUN for each javadoc keyword.
  330. Return the list of FUN results. If optional PROPERTY is non nil only
  331. call FUN for javadoc keywords which have a value for PROPERTY. FUN
  332. receives two arguments: the javadoc keyword and its associated
  333. 'javadoc property list. It can return any value. All nil values are
  334. removed from the result list."
  335. (delq nil
  336. (mapcar
  337. #'(lambda (k)
  338. (let* ((tag (semantic-java-doc-tag k))
  339. (plist (semantic-lex-keyword-get tag 'javadoc)))
  340. (if (or (not property) (plist-get plist property))
  341. (funcall fun k plist))))
  342. semantic-java-doc-line-tags)))
  343. ;;; Mode setup
  344. ;;
  345. (defun semantic-java-doc-setup ()
  346. "Lazy initialization of javadoc elements."
  347. (or semantic-java-doc-line-tags
  348. (setq semantic-java-doc-line-tags
  349. (sort (mapcar #'semantic-java-doc-tag-name
  350. (semantic-lex-keywords 'javadoc))
  351. #'semantic-java-doc-keyword-before-p)))
  352. (or semantic-java-doc-with-name-tags
  353. (setq semantic-java-doc-with-name-tags
  354. (semantic-java-doc-keywords-map
  355. #'(lambda (k p)
  356. k)
  357. 'with-name)))
  358. (or semantic-java-doc-with-ref-tags
  359. (setq semantic-java-doc-with-ref-tags
  360. (semantic-java-doc-keywords-map
  361. #'(lambda (k p)
  362. k)
  363. 'with-ref)))
  364. (or semantic-java-doc-extra-type-tags
  365. (setq semantic-java-doc-extra-type-tags
  366. (semantic-java-doc-keywords-map
  367. #'(lambda (k p)
  368. (if (memq 'type (plist-get p 'usage))
  369. k))
  370. 'opt)))
  371. (or semantic-java-doc-extra-function-tags
  372. (setq semantic-java-doc-extra-function-tags
  373. (semantic-java-doc-keywords-map
  374. #'(lambda (k p)
  375. (if (memq 'function (plist-get p 'usage))
  376. k))
  377. 'opt)))
  378. (or semantic-java-doc-extra-variable-tags
  379. (setq semantic-java-doc-extra-variable-tags
  380. (semantic-java-doc-keywords-map
  381. #'(lambda (k p)
  382. (if (memq 'variable (plist-get p 'usage))
  383. k))
  384. 'opt)))
  385. (or semantic-java-doc-type-tags
  386. (setq semantic-java-doc-type-tags
  387. (semantic-java-doc-keywords-map
  388. #'(lambda (k p)
  389. (if (memq 'type (plist-get p 'usage))
  390. k)))))
  391. (or semantic-java-doc-function-tags
  392. (setq semantic-java-doc-function-tags
  393. (semantic-java-doc-keywords-map
  394. #'(lambda (k p)
  395. (if (memq 'function (plist-get p 'usage))
  396. k)))))
  397. (or semantic-java-doc-variable-tags
  398. (setq semantic-java-doc-variable-tags
  399. (semantic-java-doc-keywords-map
  400. #'(lambda (k p)
  401. (if (memq 'variable (plist-get p 'usage))
  402. k)))))
  403. )
  404. (provide 'semantic/java)
  405. ;;; semantic/java.el ends here