mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-28 08:11:05 -08:00
cedet/semantic/adebug.el, cedet/semantic/chart.el,
cedet/semantic/db-debug.el, cedet/semantic/db-ebrowse.el, cedet/semantic/db-el.el, cedet/semantic/db-file.el, cedet/semantic/db-javascript.el, cedet/semantic/db-search.el, cedet/semantic/db-typecache.el, cedet/semantic/dep.el, cedet/semantic/ia.el, cedet/semantic/tag-file.el, cedet/semantic/tag-ls.el: New files.
This commit is contained in:
parent
9573e58b23
commit
f273dfc6ff
13 changed files with 4676 additions and 0 deletions
423
lisp/cedet/semantic/adebug.el
Normal file
423
lisp/cedet/semantic/adebug.el
Normal file
|
|
@ -0,0 +1,423 @@
|
|||
;;; adebug.el --- Semantic Application Debugger
|
||||
|
||||
;;; Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Semantic datastructure debugger for semantic applications.
|
||||
;; Uses data-debug for core implementation.
|
||||
;;
|
||||
;; Goals:
|
||||
;;
|
||||
;; Inspect all known details of a TAG in a buffer.
|
||||
;;
|
||||
;; Analyze the list of active semantic databases, and the tags therin.
|
||||
;;
|
||||
;; Allow interactive navigation of the analysis process, tags, etc.
|
||||
|
||||
(require 'data-debug)
|
||||
(require 'eieio-datadebug)
|
||||
(require 'semantic/analyze)
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;; SEMANTIC TAG STUFF
|
||||
;;
|
||||
(defun data-debug-insert-tag-parts (tag prefix &optional parent)
|
||||
"Insert all the parts of TAG.
|
||||
PREFIX specifies what to insert at the start of each line.
|
||||
PARENT specifires any parent tag."
|
||||
(data-debug-insert-thing (semantic-tag-name tag)
|
||||
prefix
|
||||
"Name: "
|
||||
parent)
|
||||
(insert prefix "Class: '" (format "%S" (semantic-tag-class tag)) "\n")
|
||||
(when (semantic-tag-with-position-p tag)
|
||||
(let ((ol (semantic-tag-overlay tag))
|
||||
(file (semantic-tag-file-name tag))
|
||||
(start (semantic-tag-start tag))
|
||||
(end (semantic-tag-end tag))
|
||||
)
|
||||
(insert prefix "Position: "
|
||||
(if (and (numberp start) (numberp end))
|
||||
(format "%d -> %d in " start end)
|
||||
"")
|
||||
(if file (file-name-nondirectory file) "unknown-file")
|
||||
(if (semantic-overlay-p ol)
|
||||
" <live tag>"
|
||||
"")
|
||||
"\n")
|
||||
(data-debug-insert-thing ol prefix
|
||||
"Position Data: "
|
||||
parent)
|
||||
))
|
||||
(let ((attrprefix (concat (make-string (length prefix) ? ) "# ")))
|
||||
(insert prefix "Attributes:\n")
|
||||
(data-debug-insert-property-list
|
||||
(semantic-tag-attributes tag) attrprefix tag)
|
||||
(insert prefix "Properties:\n")
|
||||
(data-debug-insert-property-list
|
||||
(semantic-tag-properties tag) attrprefix tag)
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
(defun data-debug-insert-tag-parts-from-point (point)
|
||||
"Call `data-debug-insert-tag-parts' based on text properties at POINT."
|
||||
(let ((tag (get-text-property point 'ddebug))
|
||||
(parent (get-text-property point 'ddebug-parent))
|
||||
(indent (get-text-property point 'ddebug-indent))
|
||||
start
|
||||
)
|
||||
(end-of-line)
|
||||
(setq start (point))
|
||||
(forward-char 1)
|
||||
(data-debug-insert-tag-parts tag
|
||||
(concat (make-string indent ? )
|
||||
"| ")
|
||||
parent)
|
||||
(goto-char start)
|
||||
))
|
||||
|
||||
(defun data-debug-insert-tag (tag prefix prebuttontext &optional parent)
|
||||
"Insert TAG into the current buffer at the current point.
|
||||
PREFIX specifies text to insert in front of TAG.
|
||||
PREBUTTONTEXT is text appearing btewen the prefix and TAG.
|
||||
Optional PARENT is the parent tag containing TAG.
|
||||
Add text properties needed to allow tag expansion later."
|
||||
(let ((start (point))
|
||||
(end nil)
|
||||
(str (semantic-format-tag-uml-abbreviate tag parent t))
|
||||
(tip (semantic-format-tag-prototype tag parent t))
|
||||
)
|
||||
(insert prefix prebuttontext str "\n")
|
||||
(setq end (point))
|
||||
(put-text-property start end 'ddebug tag)
|
||||
(put-text-property start end 'ddebug-parent parent)
|
||||
(put-text-property start end 'ddebug-indent(length prefix))
|
||||
(put-text-property start end 'ddebug-prefix prefix)
|
||||
(put-text-property start end 'help-echo tip)
|
||||
(put-text-property start end 'ddebug-function
|
||||
'data-debug-insert-tag-parts-from-point)
|
||||
|
||||
))
|
||||
|
||||
;;; TAG LISTS
|
||||
;;
|
||||
(defun data-debug-insert-tag-list (taglist prefix &optional parent)
|
||||
"Insert the tag list TAGLIST with PREFIX.
|
||||
Optional argument PARENT specifies the part of TAGLIST."
|
||||
(condition-case nil
|
||||
(while taglist
|
||||
(cond ((and (consp taglist) (semantic-tag-p (car taglist)))
|
||||
(data-debug-insert-tag (car taglist) prefix "" parent))
|
||||
((consp taglist)
|
||||
(data-debug-insert-thing (car taglist) prefix "" parent))
|
||||
(t (data-debug-insert-thing taglist prefix "" parent)))
|
||||
(setq taglist (cdr taglist)))
|
||||
(error nil)))
|
||||
|
||||
(defun data-debug-insert-taglist-from-point (point)
|
||||
"Insert the taglist found at the taglist button at POINT."
|
||||
(let ((taglist (get-text-property point 'ddebug))
|
||||
(parent (get-text-property point 'ddebug-parent))
|
||||
(indent (get-text-property point 'ddebug-indent))
|
||||
start
|
||||
)
|
||||
(end-of-line)
|
||||
(setq start (point))
|
||||
(forward-char 1)
|
||||
(data-debug-insert-tag-list taglist
|
||||
(concat (make-string indent ? )
|
||||
"* ")
|
||||
parent)
|
||||
(goto-char start)
|
||||
|
||||
))
|
||||
|
||||
(defun data-debug-insert-tag-list-button (taglist prefix prebuttontext &optional parent)
|
||||
"Insert a single summary of a TAGLIST.
|
||||
PREFIX is the text that preceeds the button.
|
||||
PREBUTTONTEXT is some text between PREFIX and the taglist button.
|
||||
PARENT is the tag that represents the parent of all the tags."
|
||||
(let ((start (point))
|
||||
(end nil)
|
||||
(str (format "#<TAG LIST: %d entries>" (safe-length taglist)))
|
||||
(tip nil))
|
||||
(insert prefix prebuttontext str)
|
||||
(setq end (point))
|
||||
(put-text-property (- end (length str)) end 'face 'font-lock-function-name-face)
|
||||
(put-text-property start end 'ddebug taglist)
|
||||
(put-text-property start end 'ddebug-parent parent)
|
||||
(put-text-property start end 'ddebug-indent(length prefix))
|
||||
(put-text-property start end 'ddebug-prefix prefix)
|
||||
(put-text-property start end 'help-echo tip)
|
||||
(put-text-property start end 'ddebug-function
|
||||
'data-debug-insert-taglist-from-point)
|
||||
(insert "\n")
|
||||
))
|
||||
|
||||
;;; SEMANTICDB FIND RESULTS
|
||||
;;
|
||||
(defun data-debug-insert-find-results (findres prefix)
|
||||
"Insert the find results FINDRES with PREFIX."
|
||||
;; ( (DBOBJ TAG TAG TAG) (DBOBJ TAG TAG TAG) ... )
|
||||
(let ((cnt 1))
|
||||
(while findres
|
||||
(let* ((dbhit (car findres))
|
||||
(db (car dbhit))
|
||||
(tags (cdr dbhit)))
|
||||
(data-debug-insert-thing db prefix (format "DB %d: " cnt))
|
||||
(data-debug-insert-thing tags prefix (format "HITS %d: " cnt))
|
||||
)
|
||||
(setq findres (cdr findres)
|
||||
cnt (1+ cnt)))))
|
||||
|
||||
(defun data-debug-insert-find-results-from-point (point)
|
||||
"Insert the find results found at the find results button at POINT."
|
||||
(let ((findres (get-text-property point 'ddebug))
|
||||
(indent (get-text-property point 'ddebug-indent))
|
||||
start
|
||||
)
|
||||
(end-of-line)
|
||||
(setq start (point))
|
||||
(forward-char 1)
|
||||
(data-debug-insert-find-results findres
|
||||
(concat (make-string indent ? )
|
||||
"!* ")
|
||||
)
|
||||
(goto-char start)
|
||||
))
|
||||
|
||||
(defun data-debug-insert-find-results-button (findres prefix prebuttontext)
|
||||
"Insert a single summary of a find results FINDRES.
|
||||
PREFIX is the text that preceeds the button.
|
||||
PREBUTTONTEXT is some text between prefix and the find results button."
|
||||
(let ((start (point))
|
||||
(end nil)
|
||||
(str (semanticdb-find-result-prin1-to-string findres))
|
||||
(tip nil))
|
||||
(insert prefix prebuttontext str)
|
||||
(setq end (point))
|
||||
(put-text-property (- end (length str)) end 'face 'font-lock-function-name-face)
|
||||
(put-text-property start end 'ddebug findres)
|
||||
(put-text-property start end 'ddebug-indent(length prefix))
|
||||
(put-text-property start end 'ddebug-prefix prefix)
|
||||
(put-text-property start end 'help-echo tip)
|
||||
(put-text-property start end 'ddebug-function
|
||||
'data-debug-insert-find-results-from-point)
|
||||
(insert "\n")
|
||||
))
|
||||
|
||||
(defun data-debug-insert-db-and-tag-button (dbtag prefix prebuttontext)
|
||||
"Insert a single summary of short list DBTAG of format (DB . TAG).
|
||||
PREFIX is the text that preceeds the button.
|
||||
PREBUTTONTEXT is some text between prefix and the find results button."
|
||||
(let ((start (point))
|
||||
(end nil)
|
||||
(str (concat "(#<db/tag "
|
||||
(object-name-string (car dbtag))
|
||||
" / "
|
||||
(semantic-format-tag-name (cdr dbtag) nil t)
|
||||
")"))
|
||||
(tip nil))
|
||||
(insert prefix prebuttontext str)
|
||||
(setq end (point))
|
||||
(put-text-property (- end (length str)) end 'face 'font-lock-function-name-face)
|
||||
(put-text-property start end 'ddebug dbtag)
|
||||
(put-text-property start end 'ddebug-indent(length prefix))
|
||||
(put-text-property start end 'ddebug-prefix prefix)
|
||||
(put-text-property start end 'help-echo tip)
|
||||
(put-text-property start end 'ddebug-function
|
||||
'data-debug-insert-db-and-tag-from-point)
|
||||
(insert "\n")
|
||||
))
|
||||
|
||||
(defun data-debug-insert-db-and-tag-from-point (point)
|
||||
"Insert the find results found at the find results button at POINT."
|
||||
(let ((dbtag (get-text-property point 'ddebug))
|
||||
(indent (get-text-property point 'ddebug-indent))
|
||||
start
|
||||
)
|
||||
(end-of-line)
|
||||
(setq start (point))
|
||||
(forward-char 1)
|
||||
(data-debug-insert-thing (car dbtag) (make-string indent ? )
|
||||
"| DB ")
|
||||
(data-debug-insert-tag (cdr dbtag) (concat (make-string indent ? )
|
||||
"| ")
|
||||
"TAG ")
|
||||
(goto-char start)
|
||||
))
|
||||
|
||||
;;; DEBUG COMMANDS
|
||||
;;
|
||||
;; Various commands to output aspects of the current semantic environment.
|
||||
(defun semantic-adebug-bovinate ()
|
||||
"The same as `bovinate'. Display the results in a debug buffer."
|
||||
(interactive)
|
||||
(let* ((start (current-time))
|
||||
(out (semantic-fetch-tags))
|
||||
(end (current-time)))
|
||||
|
||||
(message "Retrieving tags took %.2f seconds."
|
||||
(semantic-elapsed-time start end))
|
||||
|
||||
(data-debug-new-buffer (concat "*" (buffer-name) " ADEBUG*"))
|
||||
(data-debug-insert-tag-list out "* "))
|
||||
)
|
||||
|
||||
(defun semantic-adebug-searchdb (regex)
|
||||
"Search the semanticdb for REGEX for the current buffer.
|
||||
Display the results as a debug list."
|
||||
(interactive "sSymbol Regex: ")
|
||||
(let ((start (current-time))
|
||||
(fr (semanticdb-find-tags-by-name-regexp regex))
|
||||
(end (current-time)))
|
||||
|
||||
(data-debug-new-buffer (concat "*SEMANTICDB SEARCH: "
|
||||
regex
|
||||
" ADEBUG*"))
|
||||
(message "Search of tags took %.2f seconds."
|
||||
(semantic-elapsed-time start end))
|
||||
|
||||
(data-debug-insert-find-results fr "*")))
|
||||
|
||||
(defun semantic-adebug-analyze (&optional ctxt)
|
||||
"Perform `semantic-analyze-current-context'.
|
||||
Display the results as a debug list.
|
||||
Optional argument CTXT is the context to show."
|
||||
(interactive)
|
||||
(let ((start (current-time))
|
||||
(ctxt (or ctxt (semantic-analyze-current-context)))
|
||||
(end (current-time)))
|
||||
(if (not ctxt)
|
||||
(message "No Analyzer Results")
|
||||
(message "Analysis took %.2f seconds."
|
||||
(semantic-elapsed-time start end))
|
||||
(semantic-analyze-pulse ctxt)
|
||||
(if ctxt
|
||||
(progn
|
||||
(data-debug-new-buffer "*Analyzer ADEBUG*")
|
||||
(data-debug-insert-object-slots ctxt "]"))
|
||||
(message "No Context to analyze here.")))))
|
||||
|
||||
(defun semantic-adebug-edebug-expr (expr)
|
||||
"Dump out the contets of some expression EXPR in edebug with adebug."
|
||||
(interactive "sExpression: ")
|
||||
(let ((v (eval (read expr))))
|
||||
(if (not v)
|
||||
(message "Expression %s is nil." expr)
|
||||
(data-debug-new-buffer "*expression ADEBUG*")
|
||||
(data-debug-insert-thing v "?" "")
|
||||
)))
|
||||
|
||||
(defun semanticdb-debug-file-tag-check (startfile)
|
||||
"Report debug info for checking STARTFILE for up-to-date tags."
|
||||
(interactive "FFile to Check (default = current-buffer): ")
|
||||
(let* ((file (file-truename startfile))
|
||||
(default-directory (file-name-directory file))
|
||||
(db (or
|
||||
;; This line will pick up system databases.
|
||||
(semanticdb-directory-loaded-p default-directory)
|
||||
;; this line will make a new one if needed.
|
||||
(semanticdb-get-database default-directory)))
|
||||
(tab (semanticdb-file-table db file))
|
||||
)
|
||||
(with-output-to-temp-buffer "*DEBUG STUFF*"
|
||||
(princ "Starting file is: ")
|
||||
(princ startfile)
|
||||
(princ "\nTrueName is: ")
|
||||
(princ file)
|
||||
(when (not (file-exists-p file))
|
||||
(princ "\nFile does not exist!"))
|
||||
(princ "\nDirectory Part is: ")
|
||||
(princ default-directory)
|
||||
(princ "\nFound Database is: ")
|
||||
(princ (object-print db))
|
||||
(princ "\nFound Table is: ")
|
||||
(if tab (princ (object-print tab)) (princ "nil"))
|
||||
(princ "\n\nAction Summary: ")
|
||||
(cond
|
||||
((and tab
|
||||
;; Is this in a buffer?
|
||||
(find-buffer-visiting (semanticdb-full-filename tab))
|
||||
)
|
||||
(princ "Found Buffer: ")
|
||||
(prin1 (find-buffer-visiting (semanticdb-full-filename tab)))
|
||||
)
|
||||
((and tab
|
||||
;; Is table fully loaded, or just a proxy?
|
||||
(number-or-marker-p (oref tab pointmax))
|
||||
;; Is this table up to date with the file?
|
||||
(not (semanticdb-needs-refresh-p tab)))
|
||||
(princ "Found table, no refresh needed.\n Pointmax is: ")
|
||||
(prin1 (oref tab pointmax))
|
||||
)
|
||||
(t
|
||||
(princ "Found table that needs refresh.")
|
||||
(if (not tab)
|
||||
(princ "\n No Saved Point.")
|
||||
(princ "\n Saved pointmax: ")
|
||||
(prin1 (oref tab pointmax))
|
||||
(princ " Needs Refresh: ")
|
||||
(prin1 (semanticdb-needs-refresh-p tab))
|
||||
)
|
||||
))
|
||||
;; Buffer isn't loaded. The only clue we have is if the file
|
||||
;; is somehow different from our mark in the semanticdb table.
|
||||
(let* ((stats (file-attributes file))
|
||||
(actualsize (nth 7 stats))
|
||||
(actualmod (nth 5 stats))
|
||||
)
|
||||
|
||||
(if (or (not tab)
|
||||
(not (slot-boundp tab 'tags))
|
||||
(not (oref tab tags)))
|
||||
(princ "\n No tags in table.")
|
||||
(princ "\n Number of known tags: ")
|
||||
(prin1 (length (oref tab tags))))
|
||||
|
||||
(princ "\n File Size is: ")
|
||||
(prin1 actualsize)
|
||||
(princ "\n File Mod Time is: ")
|
||||
(princ (format-time-string "%Y-%m-%d %T" actualmod))
|
||||
(when tab
|
||||
(princ "\n Saved file size is: ")
|
||||
(prin1 (oref tab fsize))
|
||||
(princ "\n Saved Mod time is: ")
|
||||
(princ (format-time-string "%Y-%m-%d %T"
|
||||
(oref tab lastmodtime)))
|
||||
)
|
||||
)
|
||||
)
|
||||
;; Force load
|
||||
(semanticdb-file-table-object file)
|
||||
nil
|
||||
))
|
||||
|
||||
;; (semanticdb-debug-file-tag-check "/usr/lib/gcc/i486-linux-gnu/4.2/include/stddef.h")
|
||||
;; (semanticdb-debug-file-tag-check "/usr/include/stdlib.h")
|
||||
|
||||
|
||||
|
||||
(provide 'semantic/adebug)
|
||||
|
||||
;;; semantic-adebug.el ends here
|
||||
167
lisp/cedet/semantic/chart.el
Normal file
167
lisp/cedet/semantic/chart.el
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
;;; chart.el --- Utilities for use with semantic tag tables
|
||||
|
||||
;;; Copyright (C) 1999, 2000, 2001, 2003, 2005, 2008, 2009
|
||||
;;; Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; A set of simple functions for charting details about a file based on
|
||||
;; the output of the semantic parser.
|
||||
;;
|
||||
|
||||
(require 'semantic)
|
||||
(require 'chart)
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defun semantic-chart-tags-by-class (&optional tagtable)
|
||||
"Create a bar chart representing the number of tags for a given tag class.
|
||||
Each bar represents how many toplevel tags in TAGTABLE
|
||||
exist with a given class. See `semantic-symbol->name-assoc-list'
|
||||
for tokens which will be charted.
|
||||
TAGTABLE is passedto `semantic-something-to-tag-table'."
|
||||
(interactive)
|
||||
(let* ((stream (semantic-something-to-tag-table
|
||||
(or tagtable (current-buffer))))
|
||||
(names (mapcar 'cdr semantic-symbol->name-assoc-list))
|
||||
(nums (mapcar
|
||||
(lambda (symname)
|
||||
(length
|
||||
(semantic-brute-find-tag-by-class (car symname)
|
||||
stream)
|
||||
))
|
||||
semantic-symbol->name-assoc-list)))
|
||||
(chart-bar-quickie 'vertical
|
||||
"Semantic Toplevel Tag Volume"
|
||||
names "Tag Class"
|
||||
nums "Volume")
|
||||
))
|
||||
|
||||
(defun semantic-chart-database-size (&optional tagtable)
|
||||
"Create a bar chart representing the size of each file in semanticdb.
|
||||
Each bar represents how many toplevel tags in TAGTABLE
|
||||
exist in each database entry.
|
||||
TAGTABLE is passed to `semantic-something-to-tag-table'."
|
||||
(interactive)
|
||||
(if (or (not (fboundp 'semanticdb-minor-mode-p))
|
||||
(not (semanticdb-minor-mode-p)))
|
||||
(error "Semanticdb is not enabled"))
|
||||
(let* ((db semanticdb-current-database)
|
||||
(dbt (semanticdb-get-database-tables db))
|
||||
(names (mapcar 'car
|
||||
(object-assoc-list
|
||||
'file
|
||||
dbt)))
|
||||
(numnuts (mapcar (lambda (dba)
|
||||
(prog1
|
||||
(cons
|
||||
(if (slot-boundp dba 'tags)
|
||||
(length (oref dba tags))
|
||||
1)
|
||||
(car names))
|
||||
(setq names (cdr names))))
|
||||
dbt))
|
||||
(nums nil)
|
||||
(fh (/ (- (frame-height) 7) 4)))
|
||||
(setq numnuts (sort numnuts (lambda (a b) (> (car a) (car b)))))
|
||||
(setq names (mapcar 'cdr numnuts)
|
||||
nums (mapcar 'car numnuts))
|
||||
(if (> (length names) fh)
|
||||
(progn
|
||||
(setcdr (nthcdr fh names) nil)
|
||||
(setcdr (nthcdr fh nums) nil)))
|
||||
(chart-bar-quickie 'horizontal
|
||||
"Semantic DB Toplevel Tag Volume"
|
||||
names "File"
|
||||
nums "Volume")
|
||||
))
|
||||
|
||||
(defun semantic-chart-token-complexity (tok)
|
||||
"Calculate the `complexity' of token TOK."
|
||||
(count-lines
|
||||
(semantic-tag-end tok)
|
||||
(semantic-tag-start tok)))
|
||||
|
||||
(defun semantic-chart-tag-complexity
|
||||
(&optional class tagtable)
|
||||
"Create a bar chart representing the complexity of some tags.
|
||||
Complexity is calculated for tags of CLASS. Each bar represents
|
||||
the complexity of some tag in TAGTABLE. Only the most complex
|
||||
items are charted. TAGTABLE is passedto
|
||||
`semantic-something-to-tag-table'."
|
||||
(interactive)
|
||||
(let* ((sym (if (not class) 'function))
|
||||
(stream
|
||||
(semantic-find-tags-by-class
|
||||
sym (semantic-something-to-tag-table (or tagtable
|
||||
(current-buffer)))
|
||||
))
|
||||
(name (cond ((semantic-tag-with-position-p (car stream))
|
||||
(buffer-name (semantic-tag-buffer (car stream))))
|
||||
(t "")))
|
||||
(cplx (mapcar (lambda (tok)
|
||||
(cons tok (semantic-chart-token-complexity tok)))
|
||||
stream))
|
||||
(namelabel (cdr (assoc 'function semantic-symbol->name-assoc-list)))
|
||||
(names nil)
|
||||
(nums nil))
|
||||
(setq cplx (sort cplx (lambda (a b) (> (cdr a) (cdr b)))))
|
||||
(while (and cplx (<= (length names) (/ (- (frame-height) 7) 4)))
|
||||
(setq names (cons (semantic-tag-name (car (car cplx)))
|
||||
names)
|
||||
nums (cons (cdr (car cplx)) nums)
|
||||
cplx (cdr cplx)))
|
||||
;; ;; (setq names (mapcar (lambda (str)
|
||||
;; ;; (substring str (- (length str) 10)))
|
||||
;; ;; names))
|
||||
(chart-bar-quickie 'horizontal
|
||||
(format "%s Complexity in %s"
|
||||
(capitalize (symbol-name sym))
|
||||
name)
|
||||
names namelabel
|
||||
nums "Complexity (Lines of code)")
|
||||
))
|
||||
|
||||
(defun semantic-chart-analyzer ()
|
||||
"Chart the extent of the context analysis."
|
||||
(interactive)
|
||||
(let* ((p (semanticdb-find-translate-path nil nil))
|
||||
(plen (length p))
|
||||
(tab semanticdb-current-table)
|
||||
(tc (semanticdb-get-typecache tab))
|
||||
(tclen (+ (length (oref tc filestream))
|
||||
(length (oref tc includestream))))
|
||||
(scope (semantic-calculate-scope))
|
||||
(fslen (length (oref scope fullscope)))
|
||||
(lvarlen (length (oref scope localvar)))
|
||||
)
|
||||
(chart-bar-quickie 'vertical
|
||||
(format "Analyzer Overhead in %s" (buffer-name))
|
||||
'("includes" "typecache" "scopelen" "localvar")
|
||||
"Overhead Entries"
|
||||
(list plen tclen fslen lvarlen)
|
||||
"Number of tags")
|
||||
))
|
||||
|
||||
|
||||
|
||||
(provide 'semantic/chart)
|
||||
|
||||
;;; semantic-chart.el ends here
|
||||
108
lisp/cedet/semantic/db-debug.el
Normal file
108
lisp/cedet/semantic/db-debug.el
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
;;; db-debug.el --- Extra level debugging routines for Semantic
|
||||
|
||||
;;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Various routines for debugging SemanticDB issues, or viewing
|
||||
;; semanticdb state.
|
||||
|
||||
(require 'semantic/db)
|
||||
|
||||
;;; Code:
|
||||
;;
|
||||
(defun semanticdb-dump-all-table-summary ()
|
||||
"Dump a list of all databases in Emacs memory."
|
||||
(interactive)
|
||||
(require 'data-debug)
|
||||
(let ((db semanticdb-database-list))
|
||||
(data-debug-new-buffer "*SEMANTICDB*")
|
||||
(data-debug-insert-stuff-list db "*")))
|
||||
|
||||
(defalias 'semanticdb-adebug-database-list 'semanticdb-dump-all-table-summary)
|
||||
|
||||
(defun semanticdb-adebug-current-database ()
|
||||
"Run ADEBUG on the current database."
|
||||
(interactive)
|
||||
(require 'data-debug)
|
||||
(let ((p semanticdb-current-database)
|
||||
)
|
||||
(data-debug-new-buffer "*SEMANTICDB ADEBUG*")
|
||||
(data-debug-insert-stuff-list p "*")))
|
||||
|
||||
(defun semanticdb-adebug-current-table ()
|
||||
"Run ADEBUG on the current database."
|
||||
(interactive)
|
||||
(require 'data-debug)
|
||||
(let ((p semanticdb-current-table))
|
||||
(data-debug-new-buffer "*SEMANTICDB ADEBUG*")
|
||||
(data-debug-insert-stuff-list p "*")))
|
||||
|
||||
|
||||
(defun semanticdb-adebug-project-database-list ()
|
||||
"Run ADEBUG on the current database."
|
||||
(interactive)
|
||||
(require 'data-debug)
|
||||
(let ((p (semanticdb-current-database-list)))
|
||||
(data-debug-new-buffer "*SEMANTICDB ADEBUG*")
|
||||
(data-debug-insert-stuff-list p "*")))
|
||||
|
||||
|
||||
|
||||
;;; Sanity Checks
|
||||
;;
|
||||
|
||||
(defun semanticdb-table-oob-sanity-check (cache)
|
||||
"Validate that CACHE tags do not have any overlays in them."
|
||||
(while cache
|
||||
(when (semantic-overlay-p (semantic-tag-overlay cache))
|
||||
(message "Tag %s has an erroneous overlay!"
|
||||
(semantic-format-tag-summarize (car cache))))
|
||||
(semanticdb-table-oob-sanity-check
|
||||
(semantic-tag-components-with-overlays (car cache)))
|
||||
(setq cache (cdr cache))))
|
||||
|
||||
(defun semanticdb-table-sanity-check (&optional table)
|
||||
"Validate the current semanticdb TABLE."
|
||||
(interactive)
|
||||
(if (not table) (setq table semanticdb-current-table))
|
||||
(let* ((full-filename (semanticdb-full-filename table))
|
||||
(buff (find-buffer-visiting full-filename)))
|
||||
(if buff
|
||||
(save-excursion
|
||||
(set-buffer buff)
|
||||
(semantic-sanity-check))
|
||||
;; We can't use the usual semantic validity check, so hack our own.
|
||||
(semanticdb-table-oob-sanity-check (semanticdb-get-tags table)))))
|
||||
|
||||
(defun semanticdb-database-sanity-check ()
|
||||
"Validate the current semantic database."
|
||||
(interactive)
|
||||
(let ((tables (semanticdb-get-database-tables
|
||||
semanticdb-current-database)))
|
||||
(while tables
|
||||
(semanticdb-table-sanity-check (car tables))
|
||||
(setq tables (cdr tables)))
|
||||
))
|
||||
|
||||
|
||||
|
||||
(provide 'semantic/db-debug)
|
||||
;;; semanticdb-debug.el ends here
|
||||
706
lisp/cedet/semantic/db-ebrowse.el
Normal file
706
lisp/cedet/semantic/db-ebrowse.el
Normal file
|
|
@ -0,0 +1,706 @@
|
|||
;;; db-ebrowse.el --- Semanticdb backend using ebrowse.
|
||||
|
||||
;;; Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Authors: Eric M. Ludlam <zappo@gnu.org>, Joakim Verona
|
||||
;; Keywords: tags
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This program was started by Eric Ludlam, and Joakim Verona finished
|
||||
;; the implementation by adding searches and fixing bugs.
|
||||
;;
|
||||
;; Read in custom-created ebrowse BROWSE files into a semanticdb back
|
||||
;; end.
|
||||
;;
|
||||
;; Add these databases to the 'system' search.
|
||||
;; Possibly use ebrowse for local parsing too.
|
||||
;;
|
||||
;; When real details are needed out of the tag system from ebrowse,
|
||||
;; we will need to delve into the originating source and parse those
|
||||
;; files the usual way.
|
||||
;;
|
||||
;; COMMANDS:
|
||||
;; `semanticdb-create-ebrowse-database' - Call EBROWSE to create a
|
||||
;; system database for some directory. In general, use this for
|
||||
;; system libraries, such as /usr/include, or include directories
|
||||
;; large software projects.
|
||||
;; Customize `semanticdb-ebrowse-file-match' to make sure the correct
|
||||
;; file extensions are matched.
|
||||
;;
|
||||
;; `semanticdb-load-ebrowse-caches' - Load all the EBROWSE caches from
|
||||
;; your semanticdb system database directory. Once they are
|
||||
;; loaded, they become searchable as omnipotent databases for
|
||||
;; all C++ files. This is called automatically by semantic-load.
|
||||
;; Call it a second time to refresh the Emacs DB with the file.
|
||||
;;
|
||||
|
||||
(eval-when-compile
|
||||
;; For generic function searching.
|
||||
(require 'eieio)
|
||||
(require 'eieio-opt)
|
||||
)
|
||||
(require 'semantic/db-file)
|
||||
|
||||
(eval-and-compile
|
||||
;; Hopefully, this will allow semanticdb-ebrowse to compile under
|
||||
;; XEmacs, it just won't run if a user attempts to use it.
|
||||
(condition-case nil
|
||||
(require 'ebrowse)
|
||||
(error nil)))
|
||||
|
||||
;;; Code:
|
||||
(defvar semanticdb-ebrowse-default-file-name "BROWSE"
|
||||
"The EBROWSE file name used for system caches.")
|
||||
|
||||
(defcustom semanticdb-ebrowse-file-match "\\.\\(hh?\\|HH?\\|hpp\\)"
|
||||
"Regular expression matching file names for ebrowse to parse.
|
||||
This expression should exclude C++ headers that have no extension.
|
||||
By default, include only headers since the semantic use of EBrowse
|
||||
is only for searching via semanticdb, and thus only headers would
|
||||
be searched."
|
||||
:group 'semanticdb
|
||||
:type 'string)
|
||||
|
||||
(defun semanticdb-ebrowse-C-file-p (file)
|
||||
"Is FILE a C or C++ file?"
|
||||
(or (string-match semanticdb-ebrowse-file-match file)
|
||||
(and (string-match "/\\w+$" file)
|
||||
(not (file-directory-p file))
|
||||
(let ((tmp (get-buffer-create "*semanticdb-ebrowse-tmp*")))
|
||||
(save-excursion
|
||||
(set-buffer tmp)
|
||||
(condition-case nil
|
||||
(insert-file-contents file nil 0 100 t)
|
||||
(error (insert-file-contents file nil nil nil t)))
|
||||
(goto-char (point-min))
|
||||
(looking-at "\\s-*/\\(\\*\\|/\\)")
|
||||
))
|
||||
)))
|
||||
|
||||
(defun semanticdb-create-ebrowse-database (dir)
|
||||
"Create an EBROSE database for directory DIR.
|
||||
The database file is stored in ~/.semanticdb, or whichever directory
|
||||
is specified by `semanticdb-default-save-directory'."
|
||||
(interactive "DDirectory: ")
|
||||
(setq dir (file-name-as-directory dir)) ;; for / on end
|
||||
(let* ((savein (semanticdb-ebrowse-file-for-directory dir))
|
||||
(filebuff (get-buffer-create "*SEMANTICDB EBROWSE TMP*"))
|
||||
(files (directory-files (expand-file-name dir) t))
|
||||
(mma auto-mode-alist)
|
||||
(regexp nil)
|
||||
)
|
||||
;; Create the input to the ebrowse command
|
||||
(save-excursion
|
||||
(set-buffer filebuff)
|
||||
(buffer-disable-undo filebuff)
|
||||
(setq default-directory (expand-file-name dir))
|
||||
|
||||
;;; @TODO - convert to use semanticdb-collect-matching-filenames
|
||||
;; to get the file names.
|
||||
|
||||
|
||||
(mapcar (lambda (f)
|
||||
(when (semanticdb-ebrowse-C-file-p f)
|
||||
(insert f)
|
||||
(insert "\n")))
|
||||
files)
|
||||
;; Cleanup the ebrowse output buffer.
|
||||
(save-excursion
|
||||
(set-buffer (get-buffer-create "*EBROWSE OUTPUT*"))
|
||||
(erase-buffer))
|
||||
;; Call the EBROWSE command.
|
||||
(message "Creating ebrowse file: %s ..." savein)
|
||||
(call-process-region (point-min) (point-max)
|
||||
"ebrowse" nil "*EBROWSE OUTPUT*" nil
|
||||
(concat "--output-file=" savein)
|
||||
"--very-verbose")
|
||||
)
|
||||
;; Create a short LOADER program for loading in this database.
|
||||
(let* ((lfn (concat savein "-load.el"))
|
||||
(lf (find-file-noselect lfn)))
|
||||
(save-excursion
|
||||
(set-buffer lf)
|
||||
(erase-buffer)
|
||||
(insert "(semanticdb-ebrowse-load-helper \""
|
||||
(expand-file-name dir)
|
||||
"\")\n")
|
||||
(save-buffer)
|
||||
(kill-buffer (current-buffer)))
|
||||
(message "Creating ebrowse file: %s ... done" savein)
|
||||
;; Reload that database
|
||||
(load lfn nil t)
|
||||
)))
|
||||
|
||||
(defun semanticdb-load-ebrowse-caches ()
|
||||
"Load all semanticdb controlled EBROWSE caches."
|
||||
(interactive)
|
||||
(let ((f (directory-files semanticdb-default-save-directory
|
||||
t (concat semanticdb-ebrowse-default-file-name "-load.el$") t)))
|
||||
(while f
|
||||
(load (car f) nil t)
|
||||
(setq f (cdr f)))
|
||||
))
|
||||
|
||||
(defun semanticdb-ebrowse-load-helper (directory)
|
||||
"Create the semanticdb database via ebrowse for directory.
|
||||
If DIRECTORY is found to be defunct, it won't load the DB, and will
|
||||
warn instead."
|
||||
(if (file-directory-p directory)
|
||||
(semanticdb-create-database semanticdb-project-database-ebrowse
|
||||
directory)
|
||||
(let* ((BF (semanticdb-ebrowse-file-for-directory directory))
|
||||
(BFL (concat BF "-load.el"))
|
||||
(BFLB (concat BF "-load.el~")))
|
||||
(save-window-excursion
|
||||
(with-output-to-temp-buffer "*FILES TO DELETE*"
|
||||
(princ "The following BROWSE files are obsolete.\n\n")
|
||||
(princ BF)
|
||||
(princ "\n")
|
||||
(princ BFL)
|
||||
(princ "\n")
|
||||
(when (file-exists-p BFLB)
|
||||
(princ BFLB)
|
||||
(princ "\n"))
|
||||
)
|
||||
(when (y-or-n-p (format
|
||||
"Warning: Obsolete BROWSE file for: %s\nDelete? "
|
||||
directory))
|
||||
(delete-file BF)
|
||||
(delete-file BFL)
|
||||
(when (file-exists-p BFLB)
|
||||
(delete-file BFLB))
|
||||
)))))
|
||||
|
||||
;;; SEMANTIC Database related Code
|
||||
;;; Classes:
|
||||
(defclass semanticdb-table-ebrowse (semanticdb-table)
|
||||
((major-mode :initform c++-mode)
|
||||
(ebrowse-tree :initform nil
|
||||
:initarg :ebrowse-tree
|
||||
:documentation
|
||||
"The raw ebrowse tree for this file."
|
||||
)
|
||||
(global-extract :initform nil
|
||||
:initarg :global-extract
|
||||
:documentation
|
||||
"Table of ebrowse tags specific to this file.
|
||||
This table is compisited from the ebrowse *Globals* section.")
|
||||
)
|
||||
"A table for returning search results from ebrowse.")
|
||||
|
||||
(defclass semanticdb-project-database-ebrowse
|
||||
(semanticdb-project-database)
|
||||
((new-table-class :initform semanticdb-table-ebrowse
|
||||
:type class
|
||||
:documentation
|
||||
"New tables created for this database are of this class.")
|
||||
(system-include-p :initform nil
|
||||
:initarg :system-include
|
||||
:documentation
|
||||
"Flag indicating this database represents a system include directory.")
|
||||
(ebrowse-struct :initform nil
|
||||
:initarg :ebrowse-struct
|
||||
)
|
||||
)
|
||||
"Semantic Database deriving tags using the EBROWSE tool.
|
||||
EBROWSE is a C/C++ parser for use with `ebrowse' Emacs program.")
|
||||
|
||||
;JAVE this just instantiates a default empty ebrowse struct?
|
||||
; how would new instances wind up here?
|
||||
; the ebrowse class isnt singleton, unlike the emacs lisp one
|
||||
(defvar-mode-local c++-mode semanticdb-project-system-databases
|
||||
()
|
||||
"Search Ebrowse for symbols.")
|
||||
|
||||
(defmethod semanticdb-needs-refresh-p ((table semanticdb-table-ebrowse))
|
||||
"EBROWSE database do not need to be refreshed.
|
||||
|
||||
JAVE: stub for needs-refresh, because, how do we know if BROWSE files
|
||||
are out of date?
|
||||
|
||||
EML: Our database should probably remember the timestamp/checksum of
|
||||
the most recently read EBROWSE file, and use that."
|
||||
nil
|
||||
)
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
|
||||
;;; EBROWSE code
|
||||
;;
|
||||
;; These routines deal with part of the ebrowse interface.
|
||||
(defun semanticdb-ebrowse-file-for-directory (dir)
|
||||
"Return the file name for DIR where the ebrowse BROWSE file is.
|
||||
This file should reside in `semanticdb-default-save-directory'."
|
||||
(let* ((semanticdb-default-save-directory
|
||||
semanticdb-default-save-directory)
|
||||
(B (semanticdb-file-name-directory
|
||||
'semanticdb-project-database-file
|
||||
(concat (expand-file-name dir)
|
||||
semanticdb-ebrowse-default-file-name)))
|
||||
)
|
||||
B))
|
||||
|
||||
(defun semanticdb-ebrowse-get-ebrowse-structure (dir)
|
||||
"Return the ebrowse structure for directory DIR.
|
||||
This assumes semantic manages the BROWSE files, so they are assumed to live
|
||||
where semantic cache files live, depending on your settings.
|
||||
|
||||
For instance: /home/<username>/.semanticdb/!usr!include!BROWSE"
|
||||
(let* ((B (semanticdb-ebrowse-file-for-directory dir))
|
||||
(buf (get-buffer-create "*semanticdb ebrowse*")))
|
||||
(message "semanticdb-ebrowse %s" B)
|
||||
(when (file-exists-p B)
|
||||
(set-buffer buf)
|
||||
(buffer-disable-undo buf)
|
||||
(erase-buffer)
|
||||
(insert-file-contents B)
|
||||
(let ((ans nil)
|
||||
(efcn (symbol-function 'ebrowse-show-progress)))
|
||||
(fset 'ebrowse-show-progress #'(lambda (&rest junk) nil))
|
||||
(unwind-protect ;; Protect against errors w/ ebrowse
|
||||
(setq ans (list B (ebrowse-read)))
|
||||
;; These items must always happen
|
||||
(erase-buffer)
|
||||
(fset 'ebrowse-show-fcn efcn)
|
||||
)
|
||||
ans))))
|
||||
|
||||
;;; Methods for creating a database or tables
|
||||
;;
|
||||
(defmethod semanticdb-create-database :STATIC ((dbeC semanticdb-project-database-ebrowse)
|
||||
directory)
|
||||
"Create a new semantic database for DIRECTORY based on ebrowse.
|
||||
If there is no database for DIRECTORY available, then
|
||||
{not implemented yet} create one. Return nil if that is not possible."
|
||||
;; MAKE SURE THAT THE FILE LOADED DOESN'T ALREADY EXIST.
|
||||
(let ((dbs semanticdb-database-list)
|
||||
(found nil))
|
||||
(while (and (not found) dbs)
|
||||
(when (semanticdb-project-database-ebrowse-p (car dbs))
|
||||
(when (string= (oref (car dbs) reference-directory) directory)
|
||||
(setq found (car dbs))))
|
||||
(setq dbs (cdr dbs)))
|
||||
;;STATIC means DBE cant be used as object, only as a class
|
||||
(let* ((ebrowse-data (semanticdb-ebrowse-get-ebrowse-structure directory))
|
||||
(dat (car (cdr ebrowse-data)))
|
||||
(ebd (car dat))
|
||||
(db nil)
|
||||
(default-directory directory)
|
||||
)
|
||||
(if found
|
||||
(setq db found)
|
||||
(setq db (make-instance
|
||||
dbeC
|
||||
directory
|
||||
:ebrowse-struct ebd
|
||||
))
|
||||
(oset db reference-directory directory))
|
||||
|
||||
;; Once we recycle or make a new DB, refresh the
|
||||
;; contents from the BROWSE file.
|
||||
(oset db tables nil)
|
||||
;; only possible after object creation, tables inited to nil.
|
||||
(semanticdb-ebrowse-strip-trees db dat)
|
||||
|
||||
;; Once our database is loaded, if we are a system DB, we
|
||||
;; add ourselves to the include list for C++.
|
||||
(semantic-add-system-include directory 'c++-mode)
|
||||
(semantic-add-system-include directory 'c-mode)
|
||||
|
||||
db)))
|
||||
|
||||
(defmethod semanticdb-ebrowse-strip-trees ((dbe semanticdb-project-database-ebrowse)
|
||||
data)
|
||||
"For the ebrowse database DBE, strip all tables from DATA."
|
||||
;JAVE what it actually seems to do is split the original tree in "tables" associated with files
|
||||
; im not sure it actually works:
|
||||
; the filename slot sometimes gets to be nil,
|
||||
; apparently for classes which definition cant be found, yet needs to be included in the tree
|
||||
; like library baseclasses
|
||||
; a file can define several classes
|
||||
(let ((T (car (cdr data))));1st comes a header, then the tree
|
||||
(while T
|
||||
|
||||
(let* ((tree (car T))
|
||||
(class (ebrowse-ts-class tree)); root class of tree
|
||||
;; Something funny going on with this file thing...
|
||||
(filename (or (ebrowse-cs-source-file class)
|
||||
(ebrowse-cs-file class)))
|
||||
)
|
||||
(cond
|
||||
((ebrowse-globals-tree-p tree)
|
||||
;; We have the globals tree.. save this special.
|
||||
(semanticdb-ebrowse-add-globals-to-table dbe tree)
|
||||
)
|
||||
(t
|
||||
;; ebrowse will collect all the info from multiple files
|
||||
;; into one tree. Semantic wants all the bits to be tied
|
||||
;; into different files. We need to do a full dissociation
|
||||
;; into semantic parsable tables.
|
||||
(semanticdb-ebrowse-add-tree-to-table dbe tree)
|
||||
))
|
||||
(setq T (cdr T))))
|
||||
))
|
||||
|
||||
;;; Filename based methods
|
||||
;;
|
||||
(defun semanticdb-ebrowse-add-globals-to-table (dbe tree)
|
||||
"For database DBE, add the ebrowse TREE into the table."
|
||||
(if (or (not (ebrowse-ts-p tree))
|
||||
(not (ebrowse-globals-tree-p tree)))
|
||||
(signal 'wrong-type-argument (list 'ebrowse-ts-p tree)))
|
||||
|
||||
(let* ((class (ebrowse-ts-class tree))
|
||||
(fname (or (ebrowse-cs-source-file class)
|
||||
(ebrowse-cs-file class)
|
||||
;; Not def'd here, assume our current
|
||||
;; file
|
||||
(concat default-directory "/unknown-proxy.hh")))
|
||||
(vars (ebrowse-ts-member-functions tree))
|
||||
(fns (ebrowse-ts-member-variables tree))
|
||||
(toks nil)
|
||||
)
|
||||
(while vars
|
||||
(let ((nt (semantic-tag (ebrowse-ms-name (car vars))
|
||||
'variable))
|
||||
(defpoint (ebrowse-bs-point class)))
|
||||
(when defpoint
|
||||
(semantic--tag-set-overlay nt
|
||||
(vector defpoint defpoint)))
|
||||
(setq toks (cons nt toks)))
|
||||
(setq vars (cdr vars)))
|
||||
(while fns
|
||||
(let ((nt (semantic-tag (ebrowse-ms-name (car fns))
|
||||
'function))
|
||||
(defpoint (ebrowse-bs-point class)))
|
||||
(when defpoint
|
||||
(semantic--tag-set-overlay nt
|
||||
(vector defpoint defpoint)))
|
||||
(setq toks (cons nt toks)))
|
||||
(setq fns (cdr fns)))
|
||||
|
||||
))
|
||||
|
||||
(defun semanticdb-ebrowse-add-tree-to-table (dbe tree &optional fname baseclasses)
|
||||
"For database DBE, add the ebrowse TREE into the table for FNAME.
|
||||
Optional argument BASECLASSES specifyies a baseclass to the tree being provided."
|
||||
(if (not (ebrowse-ts-p tree))
|
||||
(signal 'wrong-type-argument (list 'ebrowse-ts-p tree)))
|
||||
|
||||
;; Strategy overview:
|
||||
;; 1) Calculate the filename for this tree.
|
||||
;; 2) Find a matching namespace in TAB, or create a new one.
|
||||
;; 3) Fabricate a tag proxy for CLASS
|
||||
;; 4) Add it to the namespace
|
||||
;; 5) Add subclasses
|
||||
|
||||
;; 1 - Find the filename
|
||||
(if (not fname)
|
||||
(setq fname (or (ebrowse-cs-source-file (ebrowse-ts-class tree))
|
||||
(ebrowse-cs-file (ebrowse-ts-class tree))
|
||||
;; Not def'd here, assume our current
|
||||
;; file
|
||||
(concat default-directory "/unknown-proxy.hh"))))
|
||||
|
||||
(let* ((tab (or (semanticdb-file-table dbe fname)
|
||||
(semanticdb-create-table dbe fname)))
|
||||
(class (ebrowse-ts-class tree))
|
||||
(scope (ebrowse-cs-scope class))
|
||||
(ns (when scope (cedet-split-string scope ":" t)))
|
||||
(nst nil)
|
||||
(cls nil)
|
||||
)
|
||||
|
||||
;; 2 - Get the namespace tag
|
||||
(when ns
|
||||
(let ((taglst (if (slot-boundp tab 'tags) (oref tab tags) nil)))
|
||||
(setq nst (semantic-find-first-tag-by-name (car ns) taglst))
|
||||
(when (not nst)
|
||||
(setq nst (semantic-tag (car ns) 'type :type "namespace"))
|
||||
(oset tab tags (cons nst taglst))
|
||||
)))
|
||||
|
||||
;; 3 - Create a proxy tg.
|
||||
(setq cls (semantic-tag (ebrowse-cs-name class)
|
||||
'type
|
||||
:type "class"
|
||||
:superclasses baseclasses
|
||||
:faux t
|
||||
:filename fname
|
||||
))
|
||||
(let ((defpoint (ebrowse-bs-point class)))
|
||||
(when defpoint
|
||||
(semantic--tag-set-overlay cls
|
||||
(vector defpoint defpoint))))
|
||||
|
||||
;; 4 - add to namespace
|
||||
(if nst
|
||||
(semantic-tag-put-attribute
|
||||
nst :members (cons cls (semantic-tag-get-attribute nst :members)))
|
||||
(oset tab tags (cons cls (when (slot-boundp tab 'tags)
|
||||
(oref tab tags)))))
|
||||
|
||||
;; 5 - Subclasses
|
||||
(let* ((subclass (ebrowse-ts-subclasses tree))
|
||||
(pname (ebrowse-cs-name class)))
|
||||
(when (ebrowse-cs-scope class)
|
||||
(setq pname (concat (mapconcat (lambda (a) a) (cdr ns) "::") "::" pname)))
|
||||
|
||||
(while subclass
|
||||
(let* ((scc (ebrowse-ts-class (car subclass)))
|
||||
(fname (or (ebrowse-cs-source-file scc)
|
||||
(ebrowse-cs-file scc)
|
||||
;; Not def'd here, assume our current
|
||||
;; file
|
||||
fname
|
||||
)))
|
||||
(when fname
|
||||
(semanticdb-ebrowse-add-tree-to-table
|
||||
dbe (car subclass) fname pname)))
|
||||
(setq subclass (cdr subclass))))
|
||||
))
|
||||
|
||||
;;;
|
||||
;; Overload for converting the simple faux tag into something better.
|
||||
;;
|
||||
(defmethod semanticdb-normalize-tags ((obj semanticdb-table-ebrowse) tags)
|
||||
"Convert in Ebrowse database OBJ a list of TAGS into a complete tag.
|
||||
The default tag provided by searches exclude many features of a
|
||||
semantic parsed tag. Look up the file for OBJ, and match TAGS
|
||||
against a semantic parsed tag that has all the info needed, and
|
||||
return that."
|
||||
(let ((tagret nil)
|
||||
)
|
||||
;; SemanticDB will automatically create a regular database
|
||||
;; on top of the file just loaded by ebrowse during the set
|
||||
;; buffer. Fetch that table, and use it's tag list to look
|
||||
;; up the tag we just got, and thus turn it into a full semantic
|
||||
;; tag.
|
||||
(while tags
|
||||
(let ((tag (car tags)))
|
||||
(save-excursion
|
||||
(semanticdb-set-buffer obj)
|
||||
(let ((ans nil))
|
||||
;; Gee, it would be nice to do this, but ebrowse LIES. Oi.
|
||||
(when (semantic-tag-with-position-p tag)
|
||||
(goto-char (semantic-tag-start tag))
|
||||
(let ((foundtag (semantic-current-tag)))
|
||||
;; Make sure the discovered tag is the same as what we started with.
|
||||
(when (string= (semantic-tag-name tag)
|
||||
(semantic-tag-name foundtag))
|
||||
;; We have a winner!
|
||||
(setq ans foundtag))))
|
||||
;; Sometimes ebrowse lies. Do a generic search
|
||||
;; to find it within this file.
|
||||
(when (not ans)
|
||||
;; We might find multiple hits for this tag, and we have no way
|
||||
;; of knowing which one the user wanted. Return the first one.
|
||||
(setq ans (semantic-deep-find-tags-by-name
|
||||
(semantic-tag-name tag)
|
||||
(semantic-fetch-tags))))
|
||||
(if (semantic-tag-p ans)
|
||||
(setq tagret (cons ans tagret))
|
||||
(setq tagret (append ans tagret)))
|
||||
))
|
||||
(setq tags (cdr tags))))
|
||||
tagret))
|
||||
|
||||
(defmethod semanticdb-normalize-one-tag ((obj semanticdb-table-ebrowse) tag)
|
||||
"Convert in Ebrowse database OBJ one TAG into a complete tag.
|
||||
The default tag provided by searches exclude many features of a
|
||||
semantic parsed tag. Look up the file for OBJ, and match TAG
|
||||
against a semantic parsed tag that has all the info needed, and
|
||||
return that."
|
||||
(let ((tagret nil)
|
||||
(objret nil))
|
||||
;; SemanticDB will automatically create a regular database
|
||||
;; on top of the file just loaded by ebrowse during the set
|
||||
;; buffer. Fetch that table, and use it's tag list to look
|
||||
;; up the tag we just got, and thus turn it into a full semantic
|
||||
;; tag.
|
||||
(save-excursion
|
||||
(semanticdb-set-buffer obj)
|
||||
(setq objret semanticdb-current-table)
|
||||
(when (not objret)
|
||||
;; What to do??
|
||||
(debug))
|
||||
(let ((ans nil))
|
||||
;; Gee, it would be nice to do this, but ebrowse LIES. Oi.
|
||||
(when (semantic-tag-with-position-p tag)
|
||||
(goto-char (semantic-tag-start tag))
|
||||
(let ((foundtag (semantic-current-tag)))
|
||||
;; Make sure the discovered tag is the same as what we started with.
|
||||
(when (string= (semantic-tag-name tag)
|
||||
(semantic-tag-name foundtag))
|
||||
;; We have a winner!
|
||||
(setq ans foundtag))))
|
||||
;; Sometimes ebrowse lies. Do a generic search
|
||||
;; to find it within this file.
|
||||
(when (not ans)
|
||||
;; We might find multiple hits for this tag, and we have no way
|
||||
;; of knowing which one the user wanted. Return the first one.
|
||||
(setq ans (semantic-deep-find-tags-by-name
|
||||
(semantic-tag-name tag)
|
||||
(semantic-fetch-tags))))
|
||||
(if (semantic-tag-p ans)
|
||||
(setq tagret ans)
|
||||
(setq tagret (car ans)))
|
||||
))
|
||||
(cons objret tagret)))
|
||||
|
||||
;;; Search Overrides
|
||||
;;
|
||||
;; NOTE WHEN IMPLEMENTING: Be sure to add doc-string updates explaining
|
||||
;; how your new search routines are implemented.
|
||||
;;
|
||||
(defmethod semanticdb-find-tags-by-name-method
|
||||
((table semanticdb-table-ebrowse) name &optional tags)
|
||||
"Find all tags named NAME in TABLE.
|
||||
Return a list of tags."
|
||||
;;(message "semanticdb-find-tags-by-name-method name -- %s" name)
|
||||
(if tags
|
||||
;; If TAGS are passed in, then we don't need to do work here.
|
||||
(call-next-method)
|
||||
;; If we ever need to do something special, add here.
|
||||
;; Since ebrowse tags are converted into semantic tags, we can
|
||||
;; get away with this sort of thing.
|
||||
(call-next-method)
|
||||
)
|
||||
)
|
||||
|
||||
(defmethod semanticdb-find-tags-by-name-regexp-method
|
||||
((table semanticdb-table-ebrowse) regex &optional tags)
|
||||
"Find all tags with name matching REGEX in TABLE.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Return a list of tags."
|
||||
(if tags (call-next-method)
|
||||
;; YOUR IMPLEMENTATION HERE
|
||||
(call-next-method)
|
||||
))
|
||||
|
||||
(defmethod semanticdb-find-tags-for-completion-method
|
||||
((table semanticdb-table-ebrowse) prefix &optional tags)
|
||||
"In TABLE, find all occurances of tags matching PREFIX.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Returns a table of all matching tags."
|
||||
(if tags (call-next-method)
|
||||
;; YOUR IMPLEMENTATION HERE
|
||||
(call-next-method)
|
||||
))
|
||||
|
||||
(defmethod semanticdb-find-tags-by-class-method
|
||||
((table semanticdb-table-ebrowse) class &optional tags)
|
||||
"In TABLE, find all occurances of tags of CLASS.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Returns a table of all matching tags."
|
||||
(if tags (call-next-method)
|
||||
(call-next-method)))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; Deep Searches
|
||||
;;
|
||||
;; If your language does not have a `deep' concept, these can be left
|
||||
;; alone, otherwise replace with implementations similar to those
|
||||
;; above.
|
||||
;;
|
||||
|
||||
(defmethod semanticdb-deep-find-tags-by-name-method
|
||||
((table semanticdb-table-ebrowse) name &optional tags)
|
||||
"Find all tags name NAME in TABLE.
|
||||
Optional argument TAGS is a list of tags t
|
||||
Like `semanticdb-find-tags-by-name-method' for ebrowse."
|
||||
;;(semanticdb-find-tags-by-name-method table name tags)
|
||||
(call-next-method))
|
||||
|
||||
(defmethod semanticdb-deep-find-tags-by-name-regexp-method
|
||||
((table semanticdb-table-ebrowse) regex &optional tags)
|
||||
"Find all tags with name matching REGEX in TABLE.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Like `semanticdb-find-tags-by-name-method' for ebrowse."
|
||||
;;(semanticdb-find-tags-by-name-regexp-method table regex tags)
|
||||
(call-next-method))
|
||||
|
||||
(defmethod semanticdb-deep-find-tags-for-completion-method
|
||||
((table semanticdb-table-ebrowse) prefix &optional tags)
|
||||
"In TABLE, find all occurances of tags matching PREFIX.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Like `semanticdb-find-tags-for-completion-method' for ebrowse."
|
||||
;;(semanticdb-find-tags-for-completion-method table prefix tags)
|
||||
(call-next-method))
|
||||
|
||||
;;; Advanced Searches
|
||||
;;
|
||||
(defmethod semanticdb-find-tags-external-children-of-type-method
|
||||
((table semanticdb-table-ebrowse) type &optional tags)
|
||||
"Find all nonterminals which are child elements of TYPE
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Return a list of tags."
|
||||
(if tags (call-next-method)
|
||||
;; Ebrowse collects all this type of stuff together for us.
|
||||
;; but we can't use it.... yet.
|
||||
nil
|
||||
))
|
||||
|
||||
;;; TESTING
|
||||
;;
|
||||
;; This is a complex bit of stuff. Here are some tests for the
|
||||
;; system.
|
||||
|
||||
(defun semanticdb-ebrowse-run-tests ()
|
||||
"Run some tests of the semanticdb-ebrowse system.
|
||||
All systems are different. Ask questions along the way."
|
||||
(interactive)
|
||||
(let ((doload nil))
|
||||
(when (y-or-n-p "Create a system database to test with? ")
|
||||
(call-interactively 'semanticdb-create-ebrowse-database)
|
||||
(setq doload t))
|
||||
;; Should we load in caches
|
||||
(when (if doload
|
||||
(y-or-n-p "New database created. Reload system databases? ")
|
||||
(y-or-n-p "Load in all system databases? "))
|
||||
(semanticdb-load-ebrowse-caches)))
|
||||
;; Ok, databases were creatd. Lets try some searching.
|
||||
(when (not (or (eq major-mode 'c-mode)
|
||||
(eq major-mode 'c++-mode)))
|
||||
(error "Please make your default buffer be a C or C++ file, then
|
||||
run the test again..")
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
(defun semanticdb-ebrowse-dump ()
|
||||
"Find the first loaded ebrowse table, and dump out the contents."
|
||||
(interactive)
|
||||
(let ((db semanticdb-database-list)
|
||||
(ab nil))
|
||||
(while db
|
||||
(when (semanticdb-project-database-ebrowse-p (car db))
|
||||
(setq ab (data-debug-new-buffer "*EBROWSE Database*"))
|
||||
(data-debug-insert-thing (car db) "*" "")
|
||||
(setq db nil)
|
||||
)
|
||||
(setq db (cdr db)))))
|
||||
|
||||
(provide 'semantic/db-ebrowse)
|
||||
|
||||
;;; semanticdb-ebrowse.el ends here
|
||||
343
lisp/cedet/semantic/db-el.el
Normal file
343
lisp/cedet/semantic/db-el.el
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
;;; db-el.el --- Semantic database extensions for Emacs Lisp
|
||||
|
||||
;;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
|
||||
;;; Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
;; Keywords: tags
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; There are a lot of Emacs Lisp functions and variables available for
|
||||
;; the asking. This adds on to the semanticdb programming interface to
|
||||
;; allow all loaded Emacs Lisp functions to be queried via semanticdb.
|
||||
;;
|
||||
;; This allows you to use programs written for Semantic using the database
|
||||
;; to also work in Emacs Lisp with no compromises.
|
||||
;;
|
||||
|
||||
(require 'semantic/db-search)
|
||||
(eval-when-compile
|
||||
;; For generic function searching.
|
||||
(require 'eieio)
|
||||
(require 'eieio-opt)
|
||||
(require 'eieio-base)
|
||||
)
|
||||
;;; Code:
|
||||
|
||||
;;; Classes:
|
||||
(defclass semanticdb-table-emacs-lisp (semanticdb-abstract-table)
|
||||
((major-mode :initform emacs-lisp-mode)
|
||||
)
|
||||
"A table for returning search results from Emacs.")
|
||||
|
||||
(defmethod semanticdb-refresh-table ((obj semanticdb-table-emacs-lisp) &optional force)
|
||||
"Do not refresh Emacs Lisp table.
|
||||
It does not need refreshing."
|
||||
nil)
|
||||
|
||||
(defmethod semanticdb-needs-refresh-p ((obj semanticdb-table-emacs-lisp))
|
||||
"Return nil, we never need a refresh."
|
||||
nil)
|
||||
|
||||
(defclass semanticdb-project-database-emacs-lisp
|
||||
(semanticdb-project-database eieio-singleton)
|
||||
((new-table-class :initform semanticdb-table-emacs-lisp
|
||||
:type class
|
||||
:documentation
|
||||
"New tables created for this database are of this class.")
|
||||
)
|
||||
"Database representing Emacs core.")
|
||||
|
||||
;; Create the database, and add it to searchable databases for Emacs Lisp mode.
|
||||
(defvar-mode-local emacs-lisp-mode semanticdb-project-system-databases
|
||||
(list
|
||||
(semanticdb-project-database-emacs-lisp "Emacs"))
|
||||
"Search Emacs core for symbols.")
|
||||
|
||||
(defvar-mode-local emacs-lisp-mode semanticdb-find-default-throttle
|
||||
'(project omniscience)
|
||||
"Search project files, then search this omniscience database.
|
||||
It is not necessary to to system or recursive searching because of
|
||||
the omniscience database.")
|
||||
|
||||
;;; Filename based methods
|
||||
;;
|
||||
(defmethod semanticdb-get-database-tables ((obj semanticdb-project-database-emacs-lisp))
|
||||
"For an Emacs Lisp database, there are no explicit tables.
|
||||
Create one of our special tables that can act as an intermediary."
|
||||
;; We need to return something since there is always the "master table"
|
||||
;; The table can then answer file name type questions.
|
||||
(when (not (slot-boundp obj 'tables))
|
||||
(let ((newtable (semanticdb-table-emacs-lisp "Emacs System Table")))
|
||||
(oset obj tables (list newtable))
|
||||
(oset newtable parent-db obj)
|
||||
(oset newtable tags nil)
|
||||
))
|
||||
(call-next-method))
|
||||
|
||||
(defmethod semanticdb-file-table ((obj semanticdb-project-database-emacs-lisp) filename)
|
||||
"From OBJ, return FILENAME's associated table object.
|
||||
For Emacs Lisp, creates a specialized table."
|
||||
(car (semanticdb-get-database-tables obj))
|
||||
)
|
||||
|
||||
(defmethod semanticdb-get-tags ((table semanticdb-table-emacs-lisp ))
|
||||
"Return the list of tags belonging to TABLE."
|
||||
;; specialty table ? Probably derive tags at request time.
|
||||
nil)
|
||||
|
||||
(defmethod semanticdb-equivalent-mode ((table semanticdb-table-emacs-lisp) &optional buffer)
|
||||
"Return non-nil if TABLE's mode is equivalent to BUFFER.
|
||||
Equivalent modes are specified by by `semantic-equivalent-major-modes'
|
||||
local variable."
|
||||
(save-excursion
|
||||
(set-buffer buffer)
|
||||
(eq (or mode-local-active-mode major-mode) 'emacs-lisp-mode)))
|
||||
|
||||
(defmethod semanticdb-full-filename ((obj semanticdb-table-emacs-lisp))
|
||||
"Fetch the full filename that OBJ refers to.
|
||||
For Emacs Lisp system DB, there isn't one."
|
||||
nil)
|
||||
|
||||
;;; Conversion
|
||||
;;
|
||||
(defmethod semanticdb-normalize-tags ((obj semanticdb-table-emacs-lisp) tags)
|
||||
"Convert tags, originating from Emacs OBJ, into standardized form."
|
||||
(let ((newtags nil))
|
||||
(dolist (T tags)
|
||||
(let* ((ot (semanticdb-normalize-one-tag obj T))
|
||||
(tag (cdr ot)))
|
||||
(setq newtags (cons tag newtags))))
|
||||
;; There is no promise to have files associated.
|
||||
(nreverse newtags)))
|
||||
|
||||
(defmethod semanticdb-normalize-one-tag ((obj semanticdb-table-emacs-lisp) tag)
|
||||
"Convert one TAG, originating from Emacs OBJ, into standardized form.
|
||||
If Emacs cannot resolve this symbol to a particular file, then return nil."
|
||||
;; Here's the idea. For each tag, get the name, then use
|
||||
;; Emacs' `symbol-file' to get the source. Once we have that,
|
||||
;; we can use more typical semantic searching techniques to
|
||||
;; get a regularly parsed tag.
|
||||
(let* ((type (cond ((semantic-tag-of-class-p tag 'function)
|
||||
'defun)
|
||||
((semantic-tag-of-class-p tag 'variable)
|
||||
'defvar)
|
||||
))
|
||||
(sym (intern (semantic-tag-name tag)))
|
||||
(file (condition-case err
|
||||
(symbol-file sym type)
|
||||
;; Older [X]Emacs don't have a 2nd argument.
|
||||
(error (symbol-file sym))))
|
||||
)
|
||||
(if (or (not file) (not (file-exists-p file)))
|
||||
;; The file didn't exist. Return nil.
|
||||
;; We can't normalize this tag. Fake it out.
|
||||
(cons obj tag)
|
||||
(when (string-match "\\.elc" file)
|
||||
(setq file (concat (file-name-sans-extension file)
|
||||
".el"))
|
||||
(when (and (not (file-exists-p file))
|
||||
(file-exists-p (concat file ".gz")))
|
||||
;; Is it a .gz file?
|
||||
(setq file (concat file ".gz"))))
|
||||
|
||||
(let* ((tab (semanticdb-file-table-object file))
|
||||
(alltags (semanticdb-get-tags tab))
|
||||
(newtags (semanticdb-find-tags-by-name-method
|
||||
tab (semantic-tag-name tag)))
|
||||
(match nil))
|
||||
;; Find the best match.
|
||||
(dolist (T newtags)
|
||||
(when (semantic-tag-similar-p T tag)
|
||||
(setq match T)))
|
||||
;; Backup system.
|
||||
(when (not match)
|
||||
(setq match (car newtags)))
|
||||
;; Return it.
|
||||
(cons tab match)))))
|
||||
|
||||
(defun semanticdb-elisp-sym-function-arglist (sym)
|
||||
"Get the argument list for SYM.
|
||||
Deal with all different forms of function.
|
||||
This was snarfed out of eldoc."
|
||||
(let* ((prelim-def
|
||||
(let ((sd (and (fboundp sym)
|
||||
(symbol-function sym))))
|
||||
(and (symbolp sd)
|
||||
(condition-case err
|
||||
(setq sd (indirect-function sym))
|
||||
(error (setq sd nil))))
|
||||
sd))
|
||||
(def (if (eq (car-safe prelim-def) 'macro)
|
||||
(cdr prelim-def)
|
||||
prelim-def))
|
||||
(arglist (cond ((null def) nil)
|
||||
((byte-code-function-p def)
|
||||
;; This is an eieio compatibility function.
|
||||
;; We depend on EIEIO, so use this.
|
||||
(eieio-compiled-function-arglist def))
|
||||
((eq (car-safe def) 'lambda)
|
||||
(nth 1 def))
|
||||
(t nil))))
|
||||
arglist))
|
||||
|
||||
(defun semanticdb-elisp-sym->tag (sym &optional toktype)
|
||||
"Convert SYM into a semantic tag.
|
||||
TOKTYPE is a hint to the type of tag desired."
|
||||
(if (stringp sym)
|
||||
(setq sym (intern-soft sym)))
|
||||
(when sym
|
||||
(cond ((and (eq toktype 'function) (fboundp sym))
|
||||
(semantic-tag-new-function
|
||||
(symbol-name sym)
|
||||
nil ;; return type
|
||||
(semantic-elisp-desymbolify
|
||||
(semanticdb-elisp-sym-function-arglist sym)) ;; arg-list
|
||||
:user-visible-flag (condition-case nil
|
||||
(interactive-form sym)
|
||||
(error nil))
|
||||
))
|
||||
((and (eq toktype 'variable) (boundp sym))
|
||||
(semantic-tag-new-variable
|
||||
(symbol-name sym)
|
||||
nil ;; type
|
||||
nil ;; value - ignore for now
|
||||
))
|
||||
((and (eq toktype 'type) (class-p sym))
|
||||
(semantic-tag-new-type
|
||||
(symbol-name sym)
|
||||
"class"
|
||||
(semantic-elisp-desymbolify
|
||||
(aref (class-v semanticdb-project-database)
|
||||
class-public-a)) ;; slots
|
||||
(semantic-elisp-desymbolify (class-parents sym)) ;; parents
|
||||
))
|
||||
((not toktype)
|
||||
;; Figure it out on our own.
|
||||
(cond ((class-p sym)
|
||||
(semanticdb-elisp-sym->tag sym 'type))
|
||||
((fboundp sym)
|
||||
(semanticdb-elisp-sym->tag sym 'function))
|
||||
((boundp sym)
|
||||
(semanticdb-elisp-sym->tag sym 'variable))
|
||||
(t nil))
|
||||
)
|
||||
(t nil))))
|
||||
|
||||
;;; Search Overrides
|
||||
;;
|
||||
(defvar semanticdb-elisp-mapatom-collector nil
|
||||
"Variable used to collect mapatoms output.")
|
||||
|
||||
(defmethod semanticdb-find-tags-by-name-method
|
||||
((table semanticdb-table-emacs-lisp) name &optional tags)
|
||||
"Find all tags name NAME in TABLE.
|
||||
Uses `inter-soft' to match NAME to emacs symbols.
|
||||
Return a list of tags."
|
||||
(if tags (call-next-method)
|
||||
;; No need to search. Use `intern-soft' which does the same thing for us.
|
||||
(let* ((sym (intern-soft name))
|
||||
(fun (semanticdb-elisp-sym->tag sym 'function))
|
||||
(var (semanticdb-elisp-sym->tag sym 'variable))
|
||||
(typ (semanticdb-elisp-sym->tag sym 'type))
|
||||
(taglst nil)
|
||||
)
|
||||
(when (or fun var typ)
|
||||
;; If the symbol is any of these things, build the search table.
|
||||
(when var (setq taglst (cons var taglst)))
|
||||
(when typ (setq taglst (cons typ taglst)))
|
||||
(when fun (setq taglst (cons fun taglst)))
|
||||
taglst
|
||||
))))
|
||||
|
||||
(defmethod semanticdb-find-tags-by-name-regexp-method
|
||||
((table semanticdb-table-emacs-lisp) regex &optional tags)
|
||||
"Find all tags with name matching REGEX in TABLE.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Uses `apropos-internal' to find matches.
|
||||
Return a list of tags."
|
||||
(if tags (call-next-method)
|
||||
(delq nil (mapcar 'semanticdb-elisp-sym->tag
|
||||
(apropos-internal regex)))))
|
||||
|
||||
(defmethod semanticdb-find-tags-for-completion-method
|
||||
((table semanticdb-table-emacs-lisp) prefix &optional tags)
|
||||
"In TABLE, find all occurances of tags matching PREFIX.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Returns a table of all matching tags."
|
||||
(if tags (call-next-method)
|
||||
(delq nil (mapcar 'semanticdb-elisp-sym->tag
|
||||
(all-completions prefix obarray)))))
|
||||
|
||||
(defmethod semanticdb-find-tags-by-class-method
|
||||
((table semanticdb-table-emacs-lisp) class &optional tags)
|
||||
"In TABLE, find all occurances of tags of CLASS.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Returns a table of all matching tags."
|
||||
(if tags (call-next-method)
|
||||
;; We could implement this, but it could be messy.
|
||||
nil))
|
||||
|
||||
;;; Deep Searches
|
||||
;;
|
||||
;; For Emacs Lisp deep searches are like top level searches.
|
||||
(defmethod semanticdb-deep-find-tags-by-name-method
|
||||
((table semanticdb-table-emacs-lisp) name &optional tags)
|
||||
"Find all tags name NAME in TABLE.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Like `semanticdb-find-tags-by-name-method' for Emacs Lisp."
|
||||
(semanticdb-find-tags-by-name-method table name tags))
|
||||
|
||||
(defmethod semanticdb-deep-find-tags-by-name-regexp-method
|
||||
((table semanticdb-table-emacs-lisp) regex &optional tags)
|
||||
"Find all tags with name matching REGEX in TABLE.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Like `semanticdb-find-tags-by-name-method' for Emacs Lisp."
|
||||
(semanticdb-find-tags-by-name-regexp-method table regex tags))
|
||||
|
||||
(defmethod semanticdb-deep-find-tags-for-completion-method
|
||||
((table semanticdb-table-emacs-lisp) prefix &optional tags)
|
||||
"In TABLE, find all occurances of tags matching PREFIX.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Like `semanticdb-find-tags-for-completion-method' for Emacs Lisp."
|
||||
(semanticdb-find-tags-for-completion-method table prefix tags))
|
||||
|
||||
;;; Advanced Searches
|
||||
;;
|
||||
(defmethod semanticdb-find-tags-external-children-of-type-method
|
||||
((table semanticdb-table-emacs-lisp) type &optional tags)
|
||||
"Find all nonterminals which are child elements of TYPE
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Return a list of tags."
|
||||
(if tags (call-next-method)
|
||||
;; EIEIO is the only time this matters
|
||||
(when (featurep 'eieio)
|
||||
(let* ((class (intern-soft type))
|
||||
(taglst (when class
|
||||
(delq nil
|
||||
(mapcar 'semanticdb-elisp-sym->tag
|
||||
;; Fancy eieio function that knows all about
|
||||
;; built in methods belonging to CLASS.
|
||||
(eieio-all-generic-functions class)))))
|
||||
)
|
||||
taglst))))
|
||||
|
||||
(provide 'semantic/db-el)
|
||||
|
||||
;;; semanticdb-el.el ends here
|
||||
438
lisp/cedet/semantic/db-file.el
Normal file
438
lisp/cedet/semantic/db-file.el
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
;;; db-file.el --- Save a semanticdb to a cache file.
|
||||
|
||||
;;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
|
||||
;;; Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
;; Keywords: tags
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; A set of semanticdb classes for persistently saving caches on disk.
|
||||
;;
|
||||
|
||||
(require 'semantic)
|
||||
(require 'semantic/db)
|
||||
(require 'cedet-files)
|
||||
|
||||
(defvar semanticdb-file-version semantic-version
|
||||
"Version of semanticdb we are writing files to disk with.")
|
||||
(defvar semanticdb-file-incompatible-version "1.4"
|
||||
"Version of semanticdb we are not reverse compatible with.")
|
||||
|
||||
;;; Settings
|
||||
;;
|
||||
(defcustom semanticdb-default-file-name "semantic.cache"
|
||||
"*File name of the semantic tag cache."
|
||||
:group 'semanticdb
|
||||
:type 'string)
|
||||
|
||||
(defcustom semanticdb-default-save-directory (expand-file-name "~/.semanticdb")
|
||||
"*Directory name where semantic cache files are stored.
|
||||
If this value is nil, files are saved in the current directory. If the value
|
||||
is a valid directory, then it overrides `semanticdb-default-file-name' and
|
||||
stores caches in a coded file name in this directory."
|
||||
:group 'semanticdb
|
||||
:type '(choice :tag "Default-Directory"
|
||||
:menu-tag "Default-Directory"
|
||||
(const :tag "Use current directory" :value nil)
|
||||
(directory)))
|
||||
|
||||
(defcustom semanticdb-persistent-path '(always)
|
||||
"*List of valid paths that semanticdb will cache tags to.
|
||||
When `global-semanticdb-minor-mode' is active, tag lists will
|
||||
be saved to disk when Emacs exits. Not all directories will have
|
||||
tags that should be saved.
|
||||
The value should be a list of valid paths. A path can be a string,
|
||||
indicating a directory in which to save a variable. An element in the
|
||||
list can also be a symbol. Valid symbols are `never', which will
|
||||
disable any saving anywhere, `always', which enables saving
|
||||
everywhere, or `project', which enables saving in any directory that
|
||||
passes a list of predicates in `semanticdb-project-predicate-functions'."
|
||||
:group 'semanticdb
|
||||
:type nil)
|
||||
|
||||
(defcustom semanticdb-save-database-hooks nil
|
||||
"*Hooks run after a database is saved.
|
||||
Each function is called with one argument, the object representing
|
||||
the database recently written."
|
||||
:group 'semanticdb
|
||||
:type 'hook)
|
||||
|
||||
(defvar semanticdb-dir-sep-char (if (boundp 'directory-sep-char)
|
||||
(symbol-value 'directory-sep-char)
|
||||
?/)
|
||||
"Character used for directory separation.
|
||||
Obsoleted in some versions of Emacs. Needed in others.
|
||||
NOTE: This should get deleted from semantic soon.")
|
||||
|
||||
(defun semanticdb-fix-pathname (dir)
|
||||
"If DIR is broken, fix it.
|
||||
Force DIR to end with a /.
|
||||
Note: Same as `file-name-as-directory'.
|
||||
NOTE: This should get deleted from semantic soon."
|
||||
(file-name-as-directory dir))
|
||||
;; I didn't initially know about the above fcn. Keep the below as a
|
||||
;; reference. Delete it someday once I've proven everything is the same.
|
||||
;; (if (not (= semanticdb-dir-sep-char (aref path (1- (length path)))))
|
||||
;; (concat path (list semanticdb-dir-sep-char))
|
||||
;; path))
|
||||
|
||||
;;; Classes
|
||||
;;
|
||||
(defclass semanticdb-project-database-file (semanticdb-project-database
|
||||
eieio-persistent)
|
||||
((file-header-line :initform ";; SEMANTICDB Tags save file")
|
||||
(do-backups :initform nil)
|
||||
(semantic-tag-version :initarg :semantic-tag-version
|
||||
:initform "1.4"
|
||||
:documentation
|
||||
"The version of the tags saved.
|
||||
The default value is 1.4. In semantic 1.4 there was no versioning, so
|
||||
when those files are loaded, this becomes the version number.
|
||||
To save the version number, we must hand-set this version string.")
|
||||
(semanticdb-version :initarg :semanticdb-version
|
||||
:initform "1.4"
|
||||
:documentation
|
||||
"The version of the object system saved.
|
||||
The default value is 1.4. In semantic 1.4, there was no versioning,
|
||||
so when those files are loaded, this becomes the version number.
|
||||
To save the version number, we must hand-set this version string.")
|
||||
)
|
||||
"Database of file tables saved to disk.")
|
||||
|
||||
;;; Code:
|
||||
;;
|
||||
(defmethod semanticdb-create-database :STATIC ((dbc semanticdb-project-database-file)
|
||||
directory)
|
||||
"Create a new semantic database for DIRECTORY and return it.
|
||||
If a database for DIRECTORY has already been loaded, return it.
|
||||
If a database for DIRECTORY exists, then load that database, and return it.
|
||||
If DIRECTORY doesn't exist, create a new one."
|
||||
;; Make sure this is fully expanded so we don't get duplicates.
|
||||
(setq directory (file-truename directory))
|
||||
(let* ((fn (semanticdb-cache-filename dbc directory))
|
||||
(db (or (semanticdb-file-loaded-p fn)
|
||||
(if (file-exists-p fn)
|
||||
(progn
|
||||
(semanticdb-load-database fn))))))
|
||||
(unless db
|
||||
(setq db (make-instance
|
||||
dbc ; Create the database requested. Perhaps
|
||||
(concat (file-name-nondirectory
|
||||
(directory-file-name
|
||||
directory))
|
||||
"/")
|
||||
:file fn :tables nil
|
||||
:semantic-tag-version semantic-version
|
||||
:semanticdb-version semanticdb-file-version)))
|
||||
;; Set this up here. We can't put it in the constructor because it
|
||||
;; would be saved, and we want DB files to be portable.
|
||||
(oset db reference-directory directory)
|
||||
db))
|
||||
|
||||
;;; File IO
|
||||
(defun semanticdb-load-database (filename)
|
||||
"Load the database FILENAME."
|
||||
(require 'inversion)
|
||||
(condition-case foo
|
||||
(let* ((r (eieio-persistent-read filename))
|
||||
(c (semanticdb-get-database-tables r))
|
||||
(tv (oref r semantic-tag-version))
|
||||
(fv (oref r semanticdb-version))
|
||||
)
|
||||
;; Restore the parent-db connection
|
||||
(while c
|
||||
(oset (car c) parent-db r)
|
||||
(setq c (cdr c)))
|
||||
(if (not (inversion-test 'semanticdb-file fv))
|
||||
(when (inversion-test 'semantic-tag tv)
|
||||
;; Incompatible version. Flush tables.
|
||||
(semanticdb-flush-database-tables r)
|
||||
;; Reset the version to new version.
|
||||
(oset r semantic-tag-version semantic-tag-version)
|
||||
;; Warn user
|
||||
(message "Semanticdb file is old. Starting over for %s"
|
||||
filename)
|
||||
)
|
||||
;; Version is not ok. Flush whole system
|
||||
(message "semanticdb file is old. Starting over for %s"
|
||||
filename)
|
||||
;; This database is so old, we need to replace it.
|
||||
;; We also need to delete it from the instance tracker.
|
||||
(delete-instance r)
|
||||
(setq r nil))
|
||||
r)
|
||||
(error (message "Cache Error: [%s] %s, Restart"
|
||||
filename foo)
|
||||
nil)))
|
||||
|
||||
(defun semanticdb-file-loaded-p (filename)
|
||||
"Return the project belonging to FILENAME if it was already loaded."
|
||||
(eieio-instance-tracker-find filename 'file 'semanticdb-database-list))
|
||||
|
||||
(defmethod semanticdb-file-directory-exists-p ((DB semanticdb-project-database-file)
|
||||
&optional supress-questions)
|
||||
"Does the directory the database DB needs to write to exist?
|
||||
If SUPRESS-QUESTIONS, then do not ask to create the directory."
|
||||
(let ((dest (file-name-directory (oref DB file)))
|
||||
)
|
||||
(cond ((null dest)
|
||||
;; @TODO - If it was never set up... what should we do ?
|
||||
nil)
|
||||
((file-exists-p dest) t)
|
||||
(supress-questions nil)
|
||||
((y-or-n-p (format "Create directory %s for SemanticDB? "
|
||||
dest))
|
||||
(make-directory dest t)
|
||||
t)
|
||||
(t nil))
|
||||
))
|
||||
|
||||
(defmethod semanticdb-save-db ((DB semanticdb-project-database-file)
|
||||
&optional
|
||||
supress-questions)
|
||||
"Write out the database DB to its file.
|
||||
If DB is not specified, then use the current database."
|
||||
(let ((objname (oref DB file)))
|
||||
(when (and (semanticdb-dirty-p DB)
|
||||
(semanticdb-live-p DB)
|
||||
(semanticdb-file-directory-exists-p DB supress-questions)
|
||||
(semanticdb-write-directory-p DB)
|
||||
)
|
||||
;;(message "Saving tag summary for %s..." objname)
|
||||
(condition-case foo
|
||||
(eieio-persistent-save (or DB semanticdb-current-database))
|
||||
(file-error ; System error saving? Ignore it.
|
||||
(message "%S: %s" foo objname))
|
||||
(error
|
||||
(cond
|
||||
((and (listp foo)
|
||||
(stringp (nth 1 foo))
|
||||
(string-match "write[- ]protected" (nth 1 foo)))
|
||||
(message (nth 1 foo)))
|
||||
((and (listp foo)
|
||||
(stringp (nth 1 foo))
|
||||
(string-match "no such directory" (nth 1 foo)))
|
||||
(message (nth 1 foo)))
|
||||
(t
|
||||
;; @todo - It should ask if we are not called from a hook.
|
||||
;; How?
|
||||
(if (or supress-questions
|
||||
(y-or-n-p (format "Skip Error: %S ?" (car (cdr foo)))))
|
||||
(message "Save Error: %S: %s" (car (cdr foo))
|
||||
objname)
|
||||
(error "%S" (car (cdr foo))))))))
|
||||
(run-hook-with-args 'semanticdb-save-database-hooks
|
||||
(or DB semanticdb-current-database))
|
||||
;;(message "Saving tag summary for %s...done" objname)
|
||||
)
|
||||
))
|
||||
|
||||
(defmethod semanticdb-live-p ((obj semanticdb-project-database))
|
||||
"Return non-nil if the file associated with OBJ is live.
|
||||
Live databases are objects associated with existing directories."
|
||||
(and (slot-boundp obj 'reference-directory)
|
||||
(file-exists-p (oref obj reference-directory))))
|
||||
|
||||
(defmethod semanticdb-live-p ((obj semanticdb-table))
|
||||
"Return non-nil if the file associated with OBJ is live.
|
||||
Live files are either buffers in Emacs, or files existing on the filesystem."
|
||||
(let ((full-filename (semanticdb-full-filename obj)))
|
||||
(or (find-buffer-visiting full-filename)
|
||||
(file-exists-p full-filename))))
|
||||
|
||||
(defvar semanticdb-data-debug-on-write-error nil
|
||||
"Run the data debugger on tables that issue errors.
|
||||
This variable is set to nil after the first error is encountered
|
||||
to prevent overload.")
|
||||
|
||||
(defmethod object-write ((obj semanticdb-table))
|
||||
"When writing a table, we have to make sure we deoverlay it first.
|
||||
Restore the overlays after writting.
|
||||
Argument OBJ is the object to write."
|
||||
(when (semanticdb-live-p obj)
|
||||
(when (semanticdb-in-buffer-p obj)
|
||||
(save-excursion
|
||||
(set-buffer (semanticdb-in-buffer-p obj))
|
||||
|
||||
;; Make sure all our tag lists are up to date.
|
||||
(semantic-fetch-tags)
|
||||
|
||||
;; Try to get an accurate unmatched syntax table.
|
||||
(when (and (boundp semantic-show-unmatched-syntax-mode)
|
||||
semantic-show-unmatched-syntax-mode)
|
||||
;; Only do this if the user runs unmatched syntax
|
||||
;; mode display enties.
|
||||
(oset obj unmatched-syntax
|
||||
(semantic-show-unmatched-lex-tokens-fetch))
|
||||
)
|
||||
|
||||
;; Make sure pointmax is up to date
|
||||
(oset obj pointmax (point-max))
|
||||
))
|
||||
|
||||
;; Make sure that the file size and other attributes are
|
||||
;; up to date.
|
||||
(let ((fattr (file-attributes (semanticdb-full-filename obj))))
|
||||
(oset obj fsize (nth 7 fattr))
|
||||
(oset obj lastmodtime (nth 5 fattr))
|
||||
)
|
||||
|
||||
;; Do it!
|
||||
(condition-case tableerror
|
||||
(call-next-method)
|
||||
(error
|
||||
(when semanticdb-data-debug-on-write-error
|
||||
(require 'data-debug)
|
||||
(data-debug-new-buffer (concat "*SEMANTICDB ERROR*"))
|
||||
(data-debug-insert-thing obj "*" "")
|
||||
(setq semanticdb-data-debug-on-write-error nil))
|
||||
(message "Error Writing Table: %s" (object-name obj))
|
||||
(error "%S" (car (cdr tableerror)))))
|
||||
|
||||
;; Clear the dirty bit.
|
||||
(oset obj dirty nil)
|
||||
))
|
||||
|
||||
;;; State queries
|
||||
;;
|
||||
(defmethod semanticdb-write-directory-p ((obj semanticdb-project-database-file))
|
||||
"Return non-nil if OBJ should be written to disk.
|
||||
Uses `semanticdb-persistent-path' to determine the return value."
|
||||
(let ((path semanticdb-persistent-path))
|
||||
(catch 'found
|
||||
(while path
|
||||
(cond ((stringp (car path))
|
||||
(if (string= (oref obj reference-directory) (car path))
|
||||
(throw 'found t)))
|
||||
((eq (car path) 'project)
|
||||
;; @TODO - EDE causes us to go in here and disable
|
||||
;; the old default 'always save' setting.
|
||||
;;
|
||||
;; With new default 'always' should I care?
|
||||
(if semanticdb-project-predicate-functions
|
||||
(if (run-hook-with-args-until-success
|
||||
'semanticdb-project-predicate-functions
|
||||
(oref obj reference-directory))
|
||||
(throw 'found t))
|
||||
;; If the mode is 'project, and there are no project
|
||||
;; modes, then just always save the file. If users
|
||||
;; wish to restrict the search, modify
|
||||
;; `semanticdb-persistent-path' to include desired paths.
|
||||
(if (= (length semanticdb-persistent-path) 1)
|
||||
(throw 'found t))
|
||||
))
|
||||
((eq (car path) 'never)
|
||||
(throw 'found nil))
|
||||
((eq (car path) 'always)
|
||||
(throw 'found t))
|
||||
(t (error "Invalid path %S" (car path))))
|
||||
(setq path (cdr path)))
|
||||
(call-next-method))
|
||||
))
|
||||
|
||||
;;; Filename manipulation
|
||||
;;
|
||||
(defmethod semanticdb-file-table ((obj semanticdb-project-database-file) filename)
|
||||
"From OBJ, return FILENAME's associated table object."
|
||||
;; Cheater option. In this case, we always have files directly
|
||||
;; under ourselves. The main project type may not.
|
||||
(object-assoc (file-name-nondirectory filename) 'file (oref obj tables)))
|
||||
|
||||
(defmethod semanticdb-file-name-non-directory :STATIC
|
||||
((dbclass semanticdb-project-database-file))
|
||||
"Return the file name DBCLASS will use.
|
||||
File name excludes any directory part."
|
||||
semanticdb-default-file-name)
|
||||
|
||||
(defmethod semanticdb-file-name-directory :STATIC
|
||||
((dbclass semanticdb-project-database-file) directory)
|
||||
"Return the relative directory to where DBCLASS will save its cache file.
|
||||
The returned path is related to DIRECTORY."
|
||||
(if semanticdb-default-save-directory
|
||||
(let ((file (cedet-directory-name-to-file-name directory)))
|
||||
;; Now create a filename for the cache file in
|
||||
;; ;`semanticdb-default-save-directory'.
|
||||
(expand-file-name
|
||||
file (file-name-as-directory semanticdb-default-save-directory)))
|
||||
directory))
|
||||
|
||||
(defmethod semanticdb-cache-filename :STATIC
|
||||
((dbclass semanticdb-project-database-file) path)
|
||||
"For DBCLASS, return a file to a cache file belonging to PATH.
|
||||
This could be a cache file in the current directory, or an encoded file
|
||||
name in a secondary directory."
|
||||
;; Use concat and not expand-file-name, because the dir part
|
||||
;; may include some of the file name.
|
||||
(concat (semanticdb-file-name-directory dbclass path)
|
||||
(semanticdb-file-name-non-directory dbclass)))
|
||||
|
||||
(defmethod semanticdb-full-filename ((obj semanticdb-project-database-file))
|
||||
"Fetch the full filename that OBJ refers to."
|
||||
(oref obj file))
|
||||
|
||||
;;; FLUSH OLD FILES
|
||||
;;
|
||||
(defun semanticdb-cleanup-cache-files (&optional noerror)
|
||||
"Cleanup any cache files associated with directories that no longer exist.
|
||||
Optional NOERROR prevents errors from being displayed."
|
||||
(interactive)
|
||||
(when (and (not semanticdb-default-save-directory)
|
||||
(not noerror))
|
||||
(error "No default save directory for semantic-save files"))
|
||||
|
||||
(when semanticdb-default-save-directory
|
||||
|
||||
;; Calculate all the cache files we have.
|
||||
(let* ((regexp (regexp-quote semanticdb-default-file-name))
|
||||
(files (directory-files semanticdb-default-save-directory
|
||||
t regexp))
|
||||
(orig nil)
|
||||
(to-delete nil))
|
||||
(dolist (F files)
|
||||
(setq orig (cedet-file-name-to-directory-name
|
||||
(file-name-nondirectory F)))
|
||||
(when (not (file-exists-p (file-name-directory orig)))
|
||||
(setq to-delete (cons F to-delete))
|
||||
))
|
||||
(if to-delete
|
||||
(save-window-excursion
|
||||
(let ((buff (get-buffer-create "*Semanticdb Delete*")))
|
||||
(with-current-buffer buff
|
||||
(erase-buffer)
|
||||
(insert "The following Cache files appear to be obsolete.\n\n")
|
||||
(dolist (F to-delete)
|
||||
(insert F "\n")))
|
||||
(pop-to-buffer buff t t)
|
||||
(fit-window-to-buffer (get-buffer-window buff) nil 1)
|
||||
(when (y-or-n-p "Delete Old Cache Files? ")
|
||||
(mapc (lambda (F)
|
||||
(message "Deleting to %s..." F)
|
||||
(delete-file F))
|
||||
to-delete)
|
||||
(message "done."))
|
||||
))
|
||||
;; No files to delete
|
||||
(when (not noerror)
|
||||
(message "No obsolete semanticdb.cache files."))
|
||||
))))
|
||||
|
||||
(provide 'semantic/db-file)
|
||||
|
||||
;;; semanticdb-file.el ends here
|
||||
310
lisp/cedet/semantic/db-javascript.el
Normal file
310
lisp/cedet/semantic/db-javascript.el
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
;;; db-javascript.el --- Semantic database extensions for javascript
|
||||
|
||||
;;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
;;; Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Joakim Verona
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Semanticdb database for Javascript.
|
||||
;;
|
||||
;; This is an omniscient database with a hard-coded list of symbols for
|
||||
;; Javascript. See the doc at the end of this file for adding or modifying
|
||||
;; the list of tags.
|
||||
;;
|
||||
|
||||
(require 'semantic/db-search)
|
||||
(eval-when-compile
|
||||
;; For generic function searching.
|
||||
(require 'eieio)
|
||||
(require 'eieio-opt)
|
||||
)
|
||||
;;; Code:
|
||||
(defvar semanticdb-javascript-tags
|
||||
'(("eval" function
|
||||
(:arguments
|
||||
(("x" variable nil nil nil)))
|
||||
nil nil)
|
||||
("parseInt" function
|
||||
(:arguments
|
||||
(("string" variable nil nil nil)
|
||||
("radix" variable nil nil nil)))
|
||||
nil nil)
|
||||
("parseFloat" function
|
||||
(:arguments
|
||||
(("string" variable nil nil nil)))
|
||||
nil nil)
|
||||
("isNaN" function
|
||||
(:arguments
|
||||
(("number" variable nil nil nil)))
|
||||
nil nil)
|
||||
("isFinite" function
|
||||
(:arguments
|
||||
(("number" variable nil nil nil)))
|
||||
nil nil)
|
||||
("decodeURI" function
|
||||
(:arguments
|
||||
(("encodedURI" variable nil nil nil)))
|
||||
nil nil)
|
||||
("decodeURIComponent" function
|
||||
(:arguments
|
||||
(("encodedURIComponent" variable nil nil nil)))
|
||||
nil nil)
|
||||
("encodeURI" function
|
||||
(:arguments
|
||||
(("uri" variable nil nil nil)))
|
||||
nil nil)
|
||||
("encodeURIComponent" function
|
||||
(:arguments
|
||||
(("uriComponent" variable nil nil nil)))
|
||||
nil nil))
|
||||
"Hard-coded list of javascript tags for semanticdb.
|
||||
See bottom of this file for instruction on managing this list.")
|
||||
|
||||
;;; Classes:
|
||||
(defclass semanticdb-table-javascript (semanticdb-search-results-table)
|
||||
((major-mode :initform javascript-mode)
|
||||
)
|
||||
"A table for returning search results from javascript.")
|
||||
|
||||
(defclass semanticdb-project-database-javascript
|
||||
(semanticdb-project-database
|
||||
eieio-singleton ;this db is for js globals, so singleton is apropriate
|
||||
)
|
||||
((new-table-class :initform semanticdb-table-javascript
|
||||
:type class
|
||||
:documentation
|
||||
"New tables created for this database are of this class.")
|
||||
)
|
||||
"Database representing javascript.")
|
||||
|
||||
;; Create the database, and add it to searchable databases for javascript mode.
|
||||
(defvar-mode-local javascript-mode semanticdb-project-system-databases
|
||||
(list
|
||||
(semanticdb-project-database-javascript "Javascript"))
|
||||
"Search javascript for symbols.")
|
||||
|
||||
;; NOTE: Be sure to modify this to the best advantage of your
|
||||
;; language.
|
||||
(defvar-mode-local javascript-mode semanticdb-find-default-throttle
|
||||
'(project omniscience)
|
||||
"Search project files, then search this omniscience database.
|
||||
It is not necessary to to system or recursive searching because of
|
||||
the omniscience database.")
|
||||
|
||||
;;; Filename based methods
|
||||
;;
|
||||
(defmethod semanticdb-get-database-tables ((obj semanticdb-project-database-javascript))
|
||||
"For a javascript database, there are no explicit tables.
|
||||
Create one of our special tables that can act as an intermediary."
|
||||
;; NOTE: This method overrides an accessor for the `tables' slot in
|
||||
;; a database. You can either construct your own (like tmp here
|
||||
;; or you can manage any number of tables.
|
||||
|
||||
;; We need to return something since there is always the "master table"
|
||||
;; The table can then answer file name type questions.
|
||||
(when (not (slot-boundp obj 'tables))
|
||||
(let ((newtable (semanticdb-table-javascript "tmp")))
|
||||
(oset obj tables (list newtable))
|
||||
(oset newtable parent-db obj)
|
||||
(oset newtable tags nil)
|
||||
))
|
||||
(call-next-method)
|
||||
)
|
||||
|
||||
(defmethod semanticdb-file-table ((obj semanticdb-project-database-javascript) filename)
|
||||
"From OBJ, return FILENAME's associated table object."
|
||||
;; NOTE: See not for `semanticdb-get-database-tables'.
|
||||
(car (semanticdb-get-database-tables obj))
|
||||
)
|
||||
|
||||
(defmethod semanticdb-get-tags ((table semanticdb-table-javascript ))
|
||||
"Return the list of tags belonging to TABLE."
|
||||
;; NOTE: Omniscient databases probably don't want to keep large tabes
|
||||
;; lolly-gagging about. Keep internal Emacs tables empty and
|
||||
;; refer to alternate databases when you need something.
|
||||
semanticdb-javascript-tags)
|
||||
|
||||
(defmethod semanticdb-equivalent-mode ((table semanticdb-table-javascript) &optional buffer)
|
||||
"Return non-nil if TABLE's mode is equivalent to BUFFER.
|
||||
Equivalent modes are specified by by `semantic-equivalent-major-modes'
|
||||
local variable."
|
||||
(save-excursion
|
||||
(set-buffer buffer)
|
||||
(eq (or mode-local-active-mode major-mode) 'javascript-mode)))
|
||||
|
||||
;;; Usage
|
||||
;;
|
||||
;; Unlike other tables, an omniscent database does not need to
|
||||
;; be associated with a path. Use this routine to always add ourselves
|
||||
;; to a search list.
|
||||
(define-mode-local-override semanticdb-find-translate-path javascript-mode
|
||||
(path brutish)
|
||||
"Return a list of semanticdb tables asociated with PATH.
|
||||
If brutish, do the default action.
|
||||
If not brutish, do the default action, and append the system
|
||||
database (if available.)"
|
||||
(let ((default
|
||||
;; When we recurse, disable searching of system databases
|
||||
;; so that our Javascript database only shows up once when
|
||||
;; we append it in this iteration.
|
||||
(let ((semanticdb-search-system-databases nil)
|
||||
)
|
||||
(semanticdb-find-translate-path-default path brutish))))
|
||||
;; Don't add anything if BRUTISH is on (it will be added in that fcn)
|
||||
;; or if we aren't supposed to search the system.
|
||||
(if (or brutish (not semanticdb-search-system-databases))
|
||||
default
|
||||
(let ((tables (apply #'append
|
||||
(mapcar
|
||||
(lambda (db) (semanticdb-get-database-tables db))
|
||||
semanticdb-project-system-databases))))
|
||||
(append default tables)))))
|
||||
|
||||
;;; Search Overrides
|
||||
;;
|
||||
;; NOTE WHEN IMPLEMENTING: Be sure to add doc-string updates explaining
|
||||
;; how your new search routines are implemented.
|
||||
;;
|
||||
(defun semanticdb-javascript-regexp-search (regexp)
|
||||
"Search for REGEXP in our fixed list of javascript tags."
|
||||
(let* ((tags semanticdb-javascript-tags)
|
||||
(result nil))
|
||||
(while tags
|
||||
(if (string-match regexp (caar tags))
|
||||
(setq result (cons (car tags) result)))
|
||||
(setq tags (cdr tags)))
|
||||
result))
|
||||
|
||||
(defmethod semanticdb-find-tags-by-name-method
|
||||
((table semanticdb-table-javascript) name &optional tags)
|
||||
"Find all tags named NAME in TABLE.
|
||||
Return a list of tags."
|
||||
(if tags
|
||||
;; If TAGS are passed in, then we don't need to do work here.
|
||||
(call-next-method)
|
||||
(assoc-string name semanticdb-javascript-tags)
|
||||
))
|
||||
|
||||
(defmethod semanticdb-find-tags-by-name-regexp-method
|
||||
((table semanticdb-table-javascript) regex &optional tags)
|
||||
"Find all tags with name matching REGEX in TABLE.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Return a list of tags."
|
||||
(if tags (call-next-method)
|
||||
;; YOUR IMPLEMENTATION HERE
|
||||
(semanticdb-javascript-regexp-search regex)
|
||||
|
||||
))
|
||||
|
||||
(defmethod semanticdb-find-tags-for-completion-method
|
||||
((table semanticdb-table-javascript) prefix &optional tags)
|
||||
"In TABLE, find all occurances of tags matching PREFIX.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Returns a table of all matching tags."
|
||||
(if tags (call-next-method)
|
||||
;; YOUR IMPLEMENTATION HERE
|
||||
(semanticdb-javascript-regexp-search (concat "^" prefix ".*"))
|
||||
))
|
||||
|
||||
(defmethod semanticdb-find-tags-by-class-method
|
||||
((table semanticdb-table-javascript) class &optional tags)
|
||||
"In TABLE, find all occurances of tags of CLASS.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Returns a table of all matching tags."
|
||||
(if tags (call-next-method)
|
||||
;; YOUR IMPLEMENTATION HERE
|
||||
;;
|
||||
;; Note: This search method could be considered optional in an
|
||||
;; omniscient database. It may be unwise to return all tags
|
||||
;; that exist for a language that are a variable or function.
|
||||
;;
|
||||
;; If it is optional, you can just delete this method.
|
||||
nil))
|
||||
|
||||
;;; Deep Searches
|
||||
;;
|
||||
;; If your language does not have a `deep' concept, these can be left
|
||||
;; alone, otherwise replace with implementations similar to those
|
||||
;; above.
|
||||
;;
|
||||
(defmethod semanticdb-deep-find-tags-by-name-method
|
||||
((table semanticdb-table-javascript) name &optional tags)
|
||||
"Find all tags name NAME in TABLE.
|
||||
Optional argument TAGS is a list of tags t
|
||||
Like `semanticdb-find-tags-by-name-method' for javascript."
|
||||
(semanticdb-find-tags-by-name-method table name tags))
|
||||
|
||||
(defmethod semanticdb-deep-find-tags-by-name-regexp-method
|
||||
((table semanticdb-table-javascript) regex &optional tags)
|
||||
"Find all tags with name matching REGEX in TABLE.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Like `semanticdb-find-tags-by-name-method' for javascript."
|
||||
(semanticdb-find-tags-by-name-regexp-method table regex tags))
|
||||
|
||||
(defmethod semanticdb-deep-find-tags-for-completion-method
|
||||
((table semanticdb-table-javascript) prefix &optional tags)
|
||||
"In TABLE, find all occurances of tags matching PREFIX.
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Like `semanticdb-find-tags-for-completion-method' for javascript."
|
||||
(semanticdb-find-tags-for-completion-method table prefix tags))
|
||||
|
||||
;;; Advanced Searches
|
||||
;;
|
||||
(defmethod semanticdb-find-tags-external-children-of-type-method
|
||||
((table semanticdb-table-javascript) type &optional tags)
|
||||
"Find all nonterminals which are child elements of TYPE
|
||||
Optional argument TAGS is a list of tags to search.
|
||||
Return a list of tags."
|
||||
(if tags (call-next-method)
|
||||
;; YOUR IMPLEMENTATION HERE
|
||||
;;
|
||||
;; OPTIONAL: This could be considered an optional function. It is
|
||||
;; used for `semantic-adopt-external-members' and may not
|
||||
;; be possible to do in your language.
|
||||
;;
|
||||
;; If it is optional, you can just delete this method.
|
||||
))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(defun semanticdb-javascript-strip-tags (tags)
|
||||
"Strip TAGS from overlays and reparse symbols."
|
||||
(cond ((and (consp tags) (eq 'reparse-symbol (car tags)))
|
||||
nil)
|
||||
((overlayp tags) nil)
|
||||
((atom tags) tags)
|
||||
(t (cons (semanticdb-javascript-strip-tags
|
||||
(car tags)) (semanticdb-javascript-strip-tags
|
||||
(cdr tags))))))
|
||||
|
||||
;this list was made from a javascript file, and the above function
|
||||
;; function eval(x){}
|
||||
;; function parseInt(string,radix){}
|
||||
;; function parseFloat(string){}
|
||||
;; function isNaN(number){}
|
||||
;; function isFinite(number){}
|
||||
;; function decodeURI(encodedURI){}
|
||||
;; function decodeURIComponent (encodedURIComponent){}
|
||||
;; function encodeURI (uri){}
|
||||
;; function encodeURIComponent (uriComponent){}
|
||||
|
||||
|
||||
(provide 'semantic/db-el)
|
||||
|
||||
;;; semanticdb-el.el ends here
|
||||
451
lisp/cedet/semantic/db-search.el
Normal file
451
lisp/cedet/semantic/db-search.el
Normal file
|
|
@ -0,0 +1,451 @@
|
|||
;;; db-search.el --- Searching through semantic databases.
|
||||
|
||||
;;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2008, 2009
|
||||
;;; Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; NOTE: THESE APIs ARE OBSOLETE:
|
||||
;;
|
||||
;; Databases of various forms can all be searched. These routines
|
||||
;; cover many common forms of searching.
|
||||
;;
|
||||
;; There are three types of searches that can be implemented:
|
||||
;;
|
||||
;; Basic Search:
|
||||
;; These searches allow searching on specific attributes of tags,
|
||||
;; such as name or type.
|
||||
;;
|
||||
;; Advanced Search:
|
||||
;; These are searches that were needed to accomplish some tasks
|
||||
;; during in utilities. Advanced searches include matching methods
|
||||
;; defined outside some parent class.
|
||||
;;
|
||||
;; The reason for advanced searches are so that external
|
||||
;; repositories such as the Emacs obarray, or java .class files can
|
||||
;; quickly answer these needed questions without dumping the entire
|
||||
;; symbol list into Emacs for a regular semanticdb search.
|
||||
;;
|
||||
;; Generic Search:
|
||||
;; The generic search, `semanticdb-find-nonterminal-by-function'
|
||||
;; accepts a Emacs Lisp predicate that tests tags in Semantic
|
||||
;; format. Most external searches cannot perform this search.
|
||||
|
||||
(require 'semantic/db)
|
||||
(require 'semantic/find)
|
||||
|
||||
;;; Code:
|
||||
;;
|
||||
;;; Classes:
|
||||
|
||||
;; @TODO MOVE THIS CLASS?
|
||||
(defclass semanticdb-search-results-table (semanticdb-abstract-table)
|
||||
(
|
||||
)
|
||||
"Table used for search results when there is no file or table association.
|
||||
Examples include search results from external sources such as from
|
||||
Emacs' own symbol table, or from external libraries.")
|
||||
|
||||
(defmethod semanticdb-refresh-table ((obj semanticdb-search-results-table) &optional force)
|
||||
"If the tag list associated with OBJ is loaded, refresh it.
|
||||
This will call `semantic-fetch-tags' if that file is in memory."
|
||||
nil)
|
||||
|
||||
;;; Utils
|
||||
;;
|
||||
;; Convenience routines for searches
|
||||
(defun semanticdb-collect-find-results (result-in-databases
|
||||
result-finding-function
|
||||
ignore-system
|
||||
find-file-on-match)
|
||||
"OBSOLETE:
|
||||
Collect results across RESULT-IN-DATABASES for RESULT-FINDING-FUNCTION.
|
||||
If RESULT-IN-DATABASES is nil, search a range of associated databases
|
||||
calculated by `semanticdb-current-database-list'.
|
||||
RESULT-IN-DATABASES is a list of variable `semanticdb-project-database'
|
||||
objects.
|
||||
RESULT-FINDING-FUNCTION should accept one argument, the database being searched.
|
||||
Argument IGNORE-SYSTEM specifies if any available system databases should
|
||||
be ignored, or searched.
|
||||
Argument FIND-FILE-ON-MATCH indicates that the found databases
|
||||
should be capable of doing so."
|
||||
(if (not (listp result-in-databases))
|
||||
(signal 'wrong-type-argument (list 'listp result-in-databases)))
|
||||
(let* ((semanticdb-search-system-databases
|
||||
(if ignore-system
|
||||
nil
|
||||
semanticdb-search-system-databases))
|
||||
(dbs (or result-in-databases
|
||||
;; Calculate what database to use.
|
||||
;; Something simple and dumb for now.
|
||||
(or (semanticdb-current-database-list)
|
||||
(list (semanticdb-current-database)))))
|
||||
(case-fold-search semantic-case-fold)
|
||||
(res (mapcar
|
||||
(lambda (db)
|
||||
(if (or (not find-file-on-match)
|
||||
(not (child-of-class-p
|
||||
(oref db new-table-class)
|
||||
semanticdb-search-results-table)))
|
||||
(funcall result-finding-function db)))
|
||||
dbs))
|
||||
out)
|
||||
;; Flatten the list. The DB is unimportant at this stage.
|
||||
(setq res (apply 'append res))
|
||||
(setq out nil)
|
||||
;; Move across results, and throw out empties.
|
||||
(while res
|
||||
(if (car res)
|
||||
(setq out (cons (car res) out)))
|
||||
(setq res (cdr res)))
|
||||
;; Results
|
||||
out))
|
||||
|
||||
;;; Programatic interfaces
|
||||
;;
|
||||
;; These routines all perform different types of searches, and are
|
||||
;; interfaces to the database methods used to also perform those searches.
|
||||
|
||||
(defun semanticdb-find-nonterminal-by-token
|
||||
(token &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
|
||||
"OBSOLETE:
|
||||
Find all occurances of nonterminals with token TOKEN in databases.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES, DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(semanticdb-collect-find-results
|
||||
databases
|
||||
(lambda (db)
|
||||
(semanticdb-find-nonterminal-by-token-method
|
||||
db token search-parts search-includes diff-mode find-file-match))
|
||||
ignore-system
|
||||
find-file-match))
|
||||
(make-obsolete 'semanticdb-find-nonterminal-by-token
|
||||
"Please don't use this function")
|
||||
|
||||
(defun semanticdb-find-nonterminal-by-name
|
||||
(name &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
|
||||
"OBSOLETE:
|
||||
Find all occurances of nonterminals with name NAME in databases.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES, DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
|
||||
Return a list ((DB-TABLE . TOKEN) ...)."
|
||||
(semanticdb-collect-find-results
|
||||
databases
|
||||
(lambda (db)
|
||||
(semanticdb-find-nonterminal-by-name-method
|
||||
db name search-parts search-includes diff-mode find-file-match))
|
||||
ignore-system
|
||||
find-file-match))
|
||||
(make-obsolete 'semanticdb-find-nonterminal-by-name
|
||||
"Please don't use this function")
|
||||
|
||||
(defun semanticdb-find-nonterminal-by-name-regexp
|
||||
(regex &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
|
||||
"OBSOLETE:
|
||||
Find all occurances of nonterminals with name matching REGEX in databases.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(semanticdb-collect-find-results
|
||||
databases
|
||||
(lambda (db)
|
||||
(semanticdb-find-nonterminal-by-name-regexp-method
|
||||
db regex search-parts search-includes diff-mode find-file-match))
|
||||
ignore-system
|
||||
find-file-match))
|
||||
(make-obsolete 'semanticdb-find-nonterminal-by-name-regexp
|
||||
"Please don't use this function")
|
||||
|
||||
|
||||
(defun semanticdb-find-nonterminal-by-type
|
||||
(type &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
|
||||
"OBSOLETE:
|
||||
Find all nonterminals with a type of TYPE in databases.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(semanticdb-collect-find-results
|
||||
databases
|
||||
(lambda (db)
|
||||
(semanticdb-find-nonterminal-by-type-method
|
||||
db type search-parts search-includes diff-mode find-file-match))
|
||||
ignore-system
|
||||
find-file-match))
|
||||
(make-obsolete 'semanticdb-find-nonterminal-by-type
|
||||
"Please don't use this function")
|
||||
|
||||
|
||||
(defun semanticdb-find-nonterminal-by-property
|
||||
(property value &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
|
||||
"OBSOLETE:
|
||||
Find all nonterminals with a PROPERTY equal to VALUE in databases.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(semanticdb-collect-find-results
|
||||
databases
|
||||
(lambda (db)
|
||||
(semanticdb-find-nonterminal-by-property-method
|
||||
db property value search-parts search-includes diff-mode find-file-match))
|
||||
ignore-system
|
||||
find-file-match))
|
||||
(make-obsolete 'semanticdb-find-nonterminal-by-property
|
||||
"Please don't use this function")
|
||||
|
||||
(defun semanticdb-find-nonterminal-by-extra-spec
|
||||
(spec &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
|
||||
"OBSOLETE:
|
||||
Find all nonterminals with a SPEC in databases.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(semanticdb-collect-find-results
|
||||
databases
|
||||
(lambda (db)
|
||||
(semanticdb-find-nonterminal-by-extra-spec-method
|
||||
db spec search-parts search-includes diff-mode find-file-match))
|
||||
ignore-system
|
||||
find-file-match))
|
||||
(make-obsolete 'semanticdb-find-nonterminal-by-extra-spec
|
||||
"Please don't use this function")
|
||||
|
||||
(defun semanticdb-find-nonterminal-by-extra-spec-value
|
||||
(spec value &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
|
||||
"OBSOLETE:
|
||||
Find all nonterminals with a SPEC equal to VALUE in databases.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(semanticdb-collect-find-results
|
||||
databases
|
||||
(lambda (db)
|
||||
(semanticdb-find-nonterminal-by-extra-spec-value-method
|
||||
db spec value search-parts search-includes diff-mode find-file-match))
|
||||
ignore-system
|
||||
find-file-match))
|
||||
(make-obsolete 'semanticdb-find-nonterminal-by-extra-spec-value
|
||||
"Please don't use this function")
|
||||
|
||||
;;; Advanced Search Routines
|
||||
;;
|
||||
(defun semanticdb-find-nonterminal-external-children-of-type
|
||||
(type &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
|
||||
"OBSOLETE:
|
||||
Find all nonterminals which are child elements of TYPE.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(semanticdb-collect-find-results
|
||||
databases
|
||||
(lambda (db)
|
||||
(semanticdb-find-nonterminal-external-children-of-type-method
|
||||
db type search-parts search-includes diff-mode find-file-match))
|
||||
ignore-system
|
||||
find-file-match))
|
||||
|
||||
;;; Generic Search routine
|
||||
;;
|
||||
|
||||
(defun semanticdb-find-nonterminal-by-function
|
||||
(function &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
|
||||
"OBSOLETE:
|
||||
Find all occurances of nonterminals which match FUNCTION.
|
||||
Search in all DATABASES. If DATABASES is nil, search a range of
|
||||
associated databases calculated `semanticdb-current-database-list' and
|
||||
DATABASES is a list of variable `semanticdb-project-database' objects.
|
||||
When SEARCH-PARTS is non-nil the search will include children of tags.
|
||||
When SEARCH-INCLUDES is non-nil, the search will include dependency files.
|
||||
When DIFF-MODE is non-nil, search databases which are of a different mode.
|
||||
A Mode is the `major-mode' that file was in when it was last parsed.
|
||||
When FIND-FILE-MATCH is non-nil, the make sure any found token's file is
|
||||
in an Emacs buffer.
|
||||
When IGNORE-SYSTEM is non-nil, system libraries are not searched.
|
||||
Return a list ((DB-TABLE . TOKEN-OR-TOKEN-LIST) ...)."
|
||||
(semanticdb-collect-find-results
|
||||
databases
|
||||
(lambda (db)
|
||||
(semanticdb-find-nonterminal-by-function-method
|
||||
db function search-parts search-includes diff-mode find-file-match))
|
||||
ignore-system
|
||||
find-file-match))
|
||||
|
||||
;;; Search Methods
|
||||
;;
|
||||
;; These are the base routines for searching semantic databases.
|
||||
;; Overload these with your subclasses to participate in the searching
|
||||
;; mechanism.
|
||||
(defmethod semanticdb-find-nonterminal-by-token-method
|
||||
((database semanticdb-project-database) token search-parts search-includes diff-mode find-file-match)
|
||||
"OBSOLETE:
|
||||
In DB, find all occurances of nonterminals with token TOKEN in databases.
|
||||
See `semanticdb-find-nonterminal-by-function-method' for details on,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES, DIFF-MODE, and FIND-FILE-MATCH.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(let ((goofy-token-name token))
|
||||
(semanticdb-find-nonterminal-by-function-method
|
||||
database (lambda (stream sp si)
|
||||
(semantic-brute-find-tag-by-class goofy-token-name stream sp si))
|
||||
search-parts search-includes diff-mode find-file-match)))
|
||||
|
||||
(defmethod semanticdb-find-nonterminal-by-name-method
|
||||
((database semanticdb-project-database) name search-parts search-includes diff-mode find-file-match)
|
||||
"OBSOLETE:
|
||||
Find all occurances of nonterminals with name NAME in databases.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES, DIFF-MODE, and FIND-FILE-MATCH.
|
||||
Return a list ((DB-TABLE . TOKEN) ...)."
|
||||
(semanticdb-find-nonterminal-by-function-method
|
||||
database
|
||||
(lambda (stream sp si)
|
||||
(semantic-brute-find-first-tag-by-name name stream sp si))
|
||||
search-parts search-includes diff-mode find-file-match))
|
||||
|
||||
(defmethod semanticdb-find-nonterminal-by-name-regexp-method
|
||||
((database semanticdb-project-database) regex search-parts search-includes diff-mode find-file-match)
|
||||
"OBSOLETE:
|
||||
Find all occurances of nonterminals with name matching REGEX in databases.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, and FIND-FILE-MATCH.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(semanticdb-find-nonterminal-by-function-method
|
||||
database
|
||||
(lambda (stream sp si)
|
||||
(semantic-brute-find-tag-by-name-regexp regex stream sp si))
|
||||
search-parts search-includes diff-mode find-file-match))
|
||||
|
||||
(defmethod semanticdb-find-nonterminal-by-type-method
|
||||
((database semanticdb-project-database) type search-parts search-includes diff-mode find-file-match)
|
||||
"OBSOLETE:
|
||||
Find all nonterminals with a type of TYPE in databases.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, and FIND-FILE-MATCH.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(semanticdb-find-nonterminal-by-function-method
|
||||
database
|
||||
(lambda (stream sp si)
|
||||
(semantic-brute-find-tag-by-type type stream sp si))
|
||||
search-parts search-includes diff-mode find-file-match))
|
||||
|
||||
(defmethod semanticdb-find-nonterminal-by-property-method
|
||||
((database semanticdb-project-database) property value search-parts search-includes diff-mode find-file-match)
|
||||
"OBSOLETE:
|
||||
Find all nonterminals with a PROPERTY equal to VALUE in databases.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, and FIND-FILE-MATCH.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(semanticdb-find-nonterminal-by-function-method
|
||||
database
|
||||
(lambda (stream sp si)
|
||||
(semantic-brute-find-tag-by-property property value stream sp si))
|
||||
search-parts search-includes diff-mode find-file-match))
|
||||
|
||||
(defmethod semanticdb-find-nonterminal-by-extra-spec-method
|
||||
((database semanticdb-project-database) spec search-parts search-includes diff-mode find-file-match)
|
||||
"OBSOLETE:
|
||||
Find all nonterminals with a SPEC in databases.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, and FIND-FILE-MATCH.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(semanticdb-find-nonterminal-by-function-method
|
||||
database
|
||||
(lambda (stream sp si)
|
||||
(semantic-brute-find-tag-by-attribute spec stream sp si))
|
||||
search-parts search-includes diff-mode find-file-match))
|
||||
|
||||
(defmethod semanticdb-find-nonterminal-by-extra-spec-value-method
|
||||
((database semanticdb-project-database) spec value search-parts search-includes diff-mode find-file-match)
|
||||
"OBSOLETE:
|
||||
Find all nonterminals with a SPEC equal to VALUE in databases.
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, and FIND-FILE-MATCH.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(semanticdb-find-nonterminal-by-function-method
|
||||
database
|
||||
(lambda (stream sp si)
|
||||
(semantic-brute-find-tag-by-attribute-value spec value stream sp si))
|
||||
search-parts search-includes diff-mode find-file-match))
|
||||
|
||||
;;; Advanced Searches
|
||||
;;
|
||||
(defmethod semanticdb-find-nonterminal-external-children-of-type-method
|
||||
((database semanticdb-project-database) type search-parts search-includes diff-mode find-file-match)
|
||||
"OBSOLETE:
|
||||
Find all nonterminals which are child elements of TYPE
|
||||
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
|
||||
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
|
||||
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
|
||||
(semanticdb-find-nonterminal-by-function-method
|
||||
database
|
||||
`(lambda (stream sp si)
|
||||
(semantic-brute-find-tag-by-function
|
||||
(lambda (tok)
|
||||
(let ((p (semantic-nonterminal-external-member-parent tok)))
|
||||
(and (stringp p) (string= ,type p)))
|
||||
)
|
||||
stream sp si))
|
||||
nil nil t))
|
||||
|
||||
;;; Generic Search
|
||||
;;
|
||||
(defmethod semanticdb-find-nonterminal-by-function-method
|
||||
((database semanticdb-project-database)
|
||||
function &optional search-parts search-includes diff-mode find-file-match)
|
||||
"OBSOLETE:
|
||||
In DATABASE, find all occurances of nonterminals which match FUNCTION.
|
||||
When SEARCH-PARTS is non-nil the search will include children of tags.
|
||||
When SEARCH-INCLUDES is non-nil, the search will include dependency files.
|
||||
When DIFF-MODE is non-nil, search databases which are of a different mode.
|
||||
A mode is the `major-mode' that file was in when it was last parsed.
|
||||
When FIND-FILE-MATCH is non-nil, the make sure any found token's file is
|
||||
in an Emacs buffer.
|
||||
Return a list of matches."
|
||||
(let* ((ret nil)
|
||||
(files (semanticdb-get-database-tables database))
|
||||
(found nil)
|
||||
(orig-buffer (current-buffer)))
|
||||
(while files
|
||||
(when (or diff-mode
|
||||
(semanticdb-equivalent-mode (car files) orig-buffer))
|
||||
;; This can cause unneeded refreshes while typing with
|
||||
;; senator-eldoc mode.
|
||||
;;(semanticdb-refresh-table (car files))
|
||||
(setq found (funcall function
|
||||
(semanticdb-get-tags (car files))
|
||||
search-parts
|
||||
search-includes
|
||||
)))
|
||||
(if found
|
||||
(progn
|
||||
;; When something is found, make sure we read in that buffer if it
|
||||
;; had not already been loaded.
|
||||
(if find-file-match
|
||||
(save-excursion (semanticdb-set-buffer (car files))))
|
||||
;; In theory, the database is up-to-date with what is in the file, and
|
||||
;; these tags are ready to go.
|
||||
;; There is a bug lurking here I don't have time to fix.
|
||||
(setq ret (cons (cons (car files) found) ret))
|
||||
(setq found nil)))
|
||||
(setq files (cdr files)))
|
||||
(nreverse ret)))
|
||||
|
||||
(provide 'semantic/db-search)
|
||||
|
||||
;;; semanticdb-search.el ends here
|
||||
585
lisp/cedet/semantic/db-typecache.el
Normal file
585
lisp/cedet/semantic/db-typecache.el
Normal file
|
|
@ -0,0 +1,585 @@
|
|||
;;; db-typecache.el --- Manage Datatypes
|
||||
|
||||
;; Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Manage a datatype cache.
|
||||
;;
|
||||
;; For typed languages like C++ collect all known types from various
|
||||
;; headers, merge namespaces, and expunge duplicates.
|
||||
;;
|
||||
;; It is likely this feature will only be needed for C/C++.
|
||||
|
||||
(require 'semantic/db)
|
||||
(require 'semantic/db-find)
|
||||
|
||||
;;; Code:
|
||||
|
||||
|
||||
;;; TABLE TYPECACHE
|
||||
(defclass semanticdb-typecache ()
|
||||
((filestream :initform nil
|
||||
:documentation
|
||||
"Fully sorted/merged list of tags within this buffer.")
|
||||
(includestream :initform nil
|
||||
:documentation
|
||||
"Fully sorted/merged list of tags from this file's includes list.")
|
||||
(stream :initform nil
|
||||
:documentation
|
||||
"The searchable tag stream for this cache.
|
||||
NOTE: Can I get rid of this? Use a hashtable instead?")
|
||||
(dependants :initform nil
|
||||
:documentation
|
||||
"Any other object that is dependent on typecache results.
|
||||
Said object must support `semantic-reset' methods.")
|
||||
;; @todo - add some sort of fast-hash.
|
||||
;; @note - Rebuilds in large projects already take a while, and the
|
||||
;; actual searches are pretty fast. Really needed?
|
||||
)
|
||||
"Structure for maintaining a typecache.")
|
||||
|
||||
(defmethod semantic-reset ((tc semanticdb-typecache))
|
||||
"Reset the object IDX."
|
||||
(oset tc filestream nil)
|
||||
(oset tc includestream nil)
|
||||
|
||||
(oset tc stream nil)
|
||||
|
||||
(mapc 'semantic-reset (oref tc dependants))
|
||||
(oset tc dependants nil)
|
||||
)
|
||||
|
||||
(defmethod semanticdb-typecache-notify-reset ((tc semanticdb-typecache))
|
||||
"Do a reset from a notify from a table we depend on."
|
||||
(oset tc includestream nil)
|
||||
(mapc 'semantic-reset (oref tc dependants))
|
||||
(oset tc dependants nil)
|
||||
)
|
||||
|
||||
(defmethod semanticdb-partial-synchronize ((tc semanticdb-typecache)
|
||||
new-tags)
|
||||
"Reset the typecache based on a partial reparse."
|
||||
(when (semantic-find-tags-by-class 'include new-tags)
|
||||
(oset tc includestream nil)
|
||||
(mapc 'semantic-reset (oref tc dependants))
|
||||
(oset tc dependants nil)
|
||||
)
|
||||
|
||||
(when (semantic-find-tags-by-class 'type new-tags)
|
||||
;; Reset our index
|
||||
(oset tc filestream nil)
|
||||
t ;; Return true, our core file tags have changed in a relavant way.
|
||||
)
|
||||
|
||||
;; NO CODE HERE
|
||||
)
|
||||
|
||||
(defun semanticdb-typecache-add-dependant (dep)
|
||||
"Add into the local typecache a dependant DEP."
|
||||
(let* ((table semanticdb-current-table)
|
||||
;;(idx (semanticdb-get-table-index table))
|
||||
(cache (semanticdb-get-typecache table))
|
||||
)
|
||||
(object-add-to-list cache 'dependants dep)))
|
||||
|
||||
(defun semanticdb-typecache-length(thing)
|
||||
"How long is THING?
|
||||
Debugging function."
|
||||
(cond ((semanticdb-typecache-child-p thing)
|
||||
(length (oref thing stream)))
|
||||
((semantic-tag-p thing)
|
||||
(length (semantic-tag-type-members thing)))
|
||||
((and (listp thing) (semantic-tag-p (car thing)))
|
||||
(length thing))
|
||||
((null thing)
|
||||
0)
|
||||
(t -1) ))
|
||||
|
||||
|
||||
(defmethod semanticdb-get-typecache ((table semanticdb-abstract-table))
|
||||
"Retrieve the typecache from the semanticdb TABLE.
|
||||
If there is no table, create one, and fill it in."
|
||||
(semanticdb-refresh-table table)
|
||||
(let* ((idx (semanticdb-get-table-index table))
|
||||
(cache (oref idx type-cache))
|
||||
)
|
||||
|
||||
;; Make sure we have a cache object in the DB index.
|
||||
(when (not cache)
|
||||
;; The object won't change as we fill it with stuff.
|
||||
(setq cache (semanticdb-typecache (semanticdb-full-filename table)))
|
||||
(oset idx type-cache cache))
|
||||
|
||||
cache))
|
||||
|
||||
(defmethod semanticdb-have-typecache-p ((table semanticdb-abstract-table))
|
||||
"Return non-nil (the typecache) if TABLE has a pre-calculated typecache."
|
||||
(let* ((idx (semanticdb-get-table-index table)))
|
||||
(oref idx type-cache)))
|
||||
|
||||
|
||||
;;; DATABASE TYPECACHE
|
||||
;;
|
||||
;; A full database can cache the types across its files.
|
||||
;;
|
||||
;; Unlike file based caches, this one is a bit simpler, and just needs
|
||||
;; to get reset when a table gets updated.
|
||||
|
||||
(defclass semanticdb-database-typecache (semanticdb-abstract-db-cache)
|
||||
((stream :initform nil
|
||||
:documentation
|
||||
"The searchable tag stream for this cache.")
|
||||
)
|
||||
"Structure for maintaining a typecache.")
|
||||
|
||||
(defmethod semantic-reset ((tc semanticdb-database-typecache))
|
||||
"Reset the object IDX."
|
||||
(oset tc stream nil)
|
||||
)
|
||||
|
||||
(defmethod semanticdb-synchronize ((cache semanticdb-database-typecache)
|
||||
new-tags)
|
||||
"Synchronize a CACHE with some NEW-TAGS."
|
||||
)
|
||||
|
||||
(defmethod semanticdb-partial-synchronize ((cache semanticdb-database-typecache)
|
||||
new-tags)
|
||||
"Synchronize a CACHE with some changed NEW-TAGS."
|
||||
)
|
||||
|
||||
(defmethod semanticdb-get-typecache ((db semanticdb-project-database))
|
||||
"Retrieve the typecache from the semantic database DB.
|
||||
If there is no table, create one, and fill it in."
|
||||
(semanticdb-cache-get db semanticdb-database-typecache)
|
||||
)
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; MERGING
|
||||
;;
|
||||
;; Managing long streams of tags representing data types.
|
||||
;;
|
||||
(defun semanticdb-typecache-apply-filename (file stream)
|
||||
"Apply the filename FILE to all tags in STREAM."
|
||||
(let ((new nil))
|
||||
(while stream
|
||||
(setq new (cons (semantic-tag-copy (car stream) nil file)
|
||||
new))
|
||||
;The below is handled by the tag-copy fcn.
|
||||
;(semantic--tag-put-property (car new) :filename file)
|
||||
(setq stream (cdr stream)))
|
||||
(nreverse new)))
|
||||
|
||||
|
||||
(defsubst semanticdb-typecache-safe-tag-members (tag)
|
||||
"Return a list of members for TAG that are safe to permute."
|
||||
(let ((mem (semantic-tag-type-members tag))
|
||||
(fname (semantic-tag-file-name tag)))
|
||||
(if fname
|
||||
(setq mem (semanticdb-typecache-apply-filename fname mem))
|
||||
(copy-sequence mem))))
|
||||
|
||||
(defsubst semanticdb-typecache-safe-tag-list (tags table)
|
||||
"Make the tag list TAGS found in TABLE safe for the typecache.
|
||||
Adds a filename and copies the tags."
|
||||
(semanticdb-typecache-apply-filename
|
||||
(semanticdb-full-filename table)
|
||||
tags))
|
||||
|
||||
(defun semanticdb-typecache-merge-streams (cache1 cache2)
|
||||
"Merge into CACHE1 and CACHE2 together. The Caches will be merged in place."
|
||||
(if (or (and (not cache1) (not cache2))
|
||||
(and (not (cdr cache1)) (not cache2))
|
||||
(and (not cache1) (not (cdr cache2))))
|
||||
;; If all caches are empty OR
|
||||
;; cache1 is length 1 and no cache2 OR
|
||||
;; no cache1 and length 1 cache2
|
||||
;;
|
||||
;; then just return the cache, and skip all this merging stuff.
|
||||
(or cache1 cache2)
|
||||
|
||||
;; Assume we always have datatypes, as this typecache isn't really
|
||||
;; useful without a typed language.
|
||||
(let ((S (semantic-sort-tags-by-name-then-type-increasing
|
||||
;; I used to use append, but it copied cache1 but not cache2.
|
||||
;; Since sort was permuting cache2, I already had to make sure
|
||||
;; the caches were permute-safe. Might as well use nconc here.
|
||||
(nconc cache1 cache2)))
|
||||
(ans nil)
|
||||
(next nil)
|
||||
(prev nil)
|
||||
(type nil))
|
||||
;; With all the tags in order, we can loop over them, and when
|
||||
;; two have the same name, we can either throw one away, or construct
|
||||
;; a fresh new tag merging the items together.
|
||||
(while S
|
||||
(setq prev (car ans))
|
||||
(setq next (car S))
|
||||
(if (or
|
||||
;; CASE 1 - First item
|
||||
(null prev)
|
||||
;; CASE 2 - New name
|
||||
(not (string= (semantic-tag-name next)
|
||||
(semantic-tag-name prev))))
|
||||
(setq ans (cons next ans))
|
||||
;; ELSE - We have a NAME match.
|
||||
(setq type (semantic-tag-type next))
|
||||
(if (semantic-tag-of-type-p prev type) ; Are they the same datatype
|
||||
;; Same Class, we can do a merge.
|
||||
(cond
|
||||
((and (semantic-tag-of-class-p next 'type)
|
||||
(string= type "namespace"))
|
||||
;; Namespaces - merge the children together.
|
||||
(setcar ans
|
||||
(semantic-tag-new-type
|
||||
(semantic-tag-name prev) ; - they are the same
|
||||
"namespace" ; - we know this as fact
|
||||
(semanticdb-typecache-merge-streams
|
||||
(semanticdb-typecache-safe-tag-members prev)
|
||||
(semanticdb-typecache-safe-tag-members next))
|
||||
nil ; - no attributes
|
||||
))
|
||||
;; Make sure we mark this as a fake tag.
|
||||
(semantic-tag-set-faux (car ans))
|
||||
)
|
||||
((semantic-tag-prototype-p next)
|
||||
;; NEXT is a prototype... so keep previous.
|
||||
nil ; - keep prev, do nothing
|
||||
)
|
||||
((semantic-tag-prototype-p prev)
|
||||
;; PREV is a prototype, but not next.. so keep NEXT.
|
||||
;; setcar - set by side-effect on top of prev
|
||||
(setcar ans next)
|
||||
)
|
||||
(t
|
||||
;;(message "Don't know how to merge %s. Keeping first entry." (semantic-tag-name next))
|
||||
))
|
||||
;; Not same class... but same name
|
||||
;(message "Same name, different type: %s, %s!=%s"
|
||||
; (semantic-tag-name next)
|
||||
; (semantic-tag-type next)
|
||||
; (semantic-tag-type prev))
|
||||
(setq ans (cons next ans))
|
||||
))
|
||||
(setq S (cdr S)))
|
||||
(nreverse ans))))
|
||||
|
||||
;;; Refresh / Query API
|
||||
;;
|
||||
;; Queries that can be made for the typecache.
|
||||
(defmethod semanticdb-typecache-file-tags ((table semanticdb-abstract-table))
|
||||
"No tags available from non-file based tables."
|
||||
nil)
|
||||
|
||||
(defmethod semanticdb-typecache-file-tags ((table semanticdb-table))
|
||||
"Update the typecache for TABLE, and return the file-tags.
|
||||
File-tags are those that belong to this file only, and excludes
|
||||
all included files."
|
||||
(let* (;(idx (semanticdb-get-table-index table))
|
||||
(cache (semanticdb-get-typecache table))
|
||||
)
|
||||
|
||||
;; Make sure our file-tags list is up to date.
|
||||
(when (not (oref cache filestream))
|
||||
(let ((tags (semantic-find-tags-by-class 'type table)))
|
||||
(when tags
|
||||
(setq tags (semanticdb-typecache-safe-tag-list tags table))
|
||||
(oset cache filestream (semanticdb-typecache-merge-streams tags nil)))))
|
||||
|
||||
;; Return our cache.
|
||||
(oref cache filestream)
|
||||
))
|
||||
|
||||
(defmethod semanticdb-typecache-include-tags ((table semanticdb-abstract-table))
|
||||
"No tags available from non-file based tables."
|
||||
nil)
|
||||
|
||||
(defmethod semanticdb-typecache-include-tags ((table semanticdb-table))
|
||||
"Update the typecache for TABLE, and return the merged types from the include tags.
|
||||
Include-tags are the tags brought in via includes, all merged together into
|
||||
a master list."
|
||||
(let* ((cache (semanticdb-get-typecache table))
|
||||
)
|
||||
|
||||
;; Make sure our file-tags list is up to date.
|
||||
(when (not (oref cache includestream))
|
||||
(let (;; Calc the path first. This will have a nice side -effect of
|
||||
;; getting the cache refreshed if a refresh is needed. Most of the
|
||||
;; time this value is itself cached, so the query is fast.
|
||||
(incpath (semanticdb-find-translate-path table nil))
|
||||
(incstream nil))
|
||||
;; Get the translated path, and extract all the type tags, then merge
|
||||
;; them all together.
|
||||
(dolist (i incpath)
|
||||
;; don't include ourselves in this crazy list.
|
||||
(when (and i (not (eq i table))
|
||||
;; @todo - This eieio fcn can be slow! Do I need it?
|
||||
;; (semanticdb-table-child-p i)
|
||||
)
|
||||
(setq incstream
|
||||
(semanticdb-typecache-merge-streams
|
||||
incstream
|
||||
;; Getting the cache from this table will also cause this
|
||||
;; file to update it's cache from it's decendants.
|
||||
;;
|
||||
;; In theory, caches are only built for most includes
|
||||
;; only once (in the loop before this one), so this ends
|
||||
;; up being super fast as we edit our file.
|
||||
(copy-sequence
|
||||
(semanticdb-typecache-file-tags i))))
|
||||
))
|
||||
|
||||
;; Save...
|
||||
(oset cache includestream incstream)))
|
||||
|
||||
;; Return our cache.
|
||||
(oref cache includestream)
|
||||
))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; Search Routines
|
||||
;;
|
||||
(define-overloadable-function semanticdb-typecache-find (type &optional path find-file-match)
|
||||
"Search the typecache for TYPE in PATH.
|
||||
If type is a string, split the string, and search for the parts.
|
||||
If type is a list, treat the type as a pre-split string.
|
||||
PATH can be nil for the current buffer, or a semanticdb table.
|
||||
FIND-FILE-MATCH is non-nil to force all found tags to be loaded into a buffer.")
|
||||
|
||||
(defun semanticdb-typecache-find-default (type &optional path find-file-match)
|
||||
"Default implementation of `semanticdb-typecache-find'.
|
||||
TYPE is the datatype to find.
|
||||
PATH is the search path.. which should be one table object.
|
||||
If FIND-FILE-MATCH is non-nil, then force the file belonging to the
|
||||
found tag to be loaded."
|
||||
(semanticdb-typecache-find-method (or path semanticdb-current-table)
|
||||
type find-file-match))
|
||||
|
||||
(defun semanticdb-typecache-find-by-name-helper (name table)
|
||||
"Find the tag with NAME in TABLE, which is from a typecache.
|
||||
If more than one tag has NAME in TABLE, we will prefer the tag that
|
||||
is of class 'type."
|
||||
(let* ((names (semantic-find-tags-by-name name table))
|
||||
(types (semantic-find-tags-by-class 'type names)))
|
||||
(or (car-safe types) (car-safe names))))
|
||||
|
||||
(defmethod semanticdb-typecache-find-method ((table semanticdb-abstract-table)
|
||||
type find-file-match)
|
||||
"Search the typecache in TABLE for the datatype TYPE.
|
||||
If type is a string, split the string, and search for the parts.
|
||||
If type is a list, treat the type as a pre-split string.
|
||||
If FIND-FILE-MATCH is non-nil, then force the file belonging to the
|
||||
found tag to be loaded."
|
||||
;; convert string to a list.
|
||||
(when (stringp type) (setq type (semantic-analyze-split-name type)))
|
||||
(when (stringp type) (setq type (list type)))
|
||||
|
||||
;; Search for the list in our typecache.
|
||||
(let* ((file (semanticdb-typecache-file-tags table))
|
||||
(inc (semanticdb-typecache-include-tags table))
|
||||
(stream nil)
|
||||
(f-ans nil)
|
||||
(i-ans nil)
|
||||
(ans nil)
|
||||
(notdone t)
|
||||
(lastfile nil)
|
||||
(thisfile nil)
|
||||
(lastans nil)
|
||||
(calculated-scope nil)
|
||||
)
|
||||
;; 1) Find first symbol in the two master lists and then merge
|
||||
;; the found streams.
|
||||
|
||||
;; We stripped duplicates, so these will be super-fast!
|
||||
(setq f-ans (semantic-find-first-tag-by-name (car type) file))
|
||||
(setq i-ans (semantic-find-first-tag-by-name (car type) inc))
|
||||
(if (and f-ans i-ans)
|
||||
(progn
|
||||
;; This trick merges the two identified tags, making sure our lists are
|
||||
;; complete. The second find then gets the new 'master' from the list of 2.
|
||||
(setq ans (semanticdb-typecache-merge-streams (list f-ans) (list i-ans)))
|
||||
(setq ans (semantic-find-first-tag-by-name (car type) ans))
|
||||
)
|
||||
|
||||
;; The answers are already sorted and merged, so if one misses,
|
||||
;; no need to do any special work.
|
||||
(setq ans (or f-ans i-ans)))
|
||||
|
||||
;; 2) Loop over the remaining parts.
|
||||
(while (and type notdone)
|
||||
|
||||
;; For pass > 1, stream will be non-nil, so do a search, otherwise
|
||||
;; ans is from outside the loop.
|
||||
(when stream
|
||||
(setq ans (semanticdb-typecache-find-by-name-helper (car type) stream))
|
||||
|
||||
;; NOTE: The below test to make sure we get a type is only relevant
|
||||
;; for the SECOND pass or later. The first pass can only ever
|
||||
;; find a type/namespace because everything else is excluded.
|
||||
|
||||
;; If this is not the last entry from the list, then it
|
||||
;; must be a type or a namespace. Lets double check.
|
||||
(when (cdr type)
|
||||
|
||||
;; From above, there is only one tag in ans, and we prefer
|
||||
;; types.
|
||||
(when (not (semantic-tag-of-class-p ans 'type))
|
||||
|
||||
(setq ans nil)))
|
||||
)
|
||||
|
||||
(push ans calculated-scope)
|
||||
|
||||
;; Track most recent file.
|
||||
(setq thisfile (semantic-tag-file-name ans))
|
||||
(when (and thisfile (stringp thisfile))
|
||||
(setq lastfile thisfile))
|
||||
|
||||
;; If we have a miss, exit, otherwise, update the stream to
|
||||
;; the next set of members.
|
||||
(if (not ans)
|
||||
(setq notdone nil)
|
||||
(setq stream (semantic-tag-type-members ans)))
|
||||
|
||||
(setq lastans ans
|
||||
ans nil
|
||||
type (cdr type)))
|
||||
|
||||
(if (or type (not notdone))
|
||||
;; If there is stuff left over, then we failed. Just return
|
||||
;; nothing.
|
||||
nil
|
||||
|
||||
;; We finished, so return everything.
|
||||
|
||||
(if (and find-file-match lastfile)
|
||||
;; This won't liven up the tag since we have a copy, but
|
||||
;; we ought to be able to get there and go to the right line.
|
||||
(find-file-noselect lastfile)
|
||||
;; We don't want to find-file match, so instead lets
|
||||
;; push the filename onto the return tag.
|
||||
(when lastans
|
||||
(setq lastans (semantic-tag-copy lastans nil lastfile))
|
||||
;; We used to do the below, but we would erroneously be putting
|
||||
;; attributes on tags being shred with other lists.
|
||||
;;(semantic--tag-put-property lastans :filename lastfile)
|
||||
)
|
||||
)
|
||||
|
||||
(if (and lastans calculated-scope)
|
||||
|
||||
;; Put our discovered scope into the tag if we have a tag
|
||||
(semantic-scope-tag-clone-with-scope
|
||||
lastans (reverse (cdr calculated-scope)))
|
||||
|
||||
;; Else, just return
|
||||
lastans
|
||||
))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; BRUTISH Typecache
|
||||
;;
|
||||
;; Routines for a typecache that crosses all tables in a given database
|
||||
;; for a matching major-mode.
|
||||
(defmethod semanticdb-typecache-for-database ((db semanticdb-project-database)
|
||||
&optional mode)
|
||||
"Return the typecache for the project database DB.
|
||||
If there isn't one, create it.
|
||||
"
|
||||
(let ((lmode (or mode major-mode))
|
||||
(cache (semanticdb-get-typecache db))
|
||||
(stream nil)
|
||||
)
|
||||
(dolist (table (semanticdb-get-database-tables db))
|
||||
(when (eq lmode (oref table :major-mode))
|
||||
(setq stream
|
||||
(semanticdb-typecache-merge-streams
|
||||
stream
|
||||
(copy-sequence
|
||||
(semanticdb-typecache-file-tags table))))
|
||||
))
|
||||
(oset cache stream stream)
|
||||
cache))
|
||||
|
||||
(defun semanticdb-typecache-refresh-for-buffer (buffer)
|
||||
"Refresh the typecache for BUFFER."
|
||||
(save-excursion
|
||||
(set-buffer buffer)
|
||||
(let* ((tab semanticdb-current-table)
|
||||
;(idx (semanticdb-get-table-index tab))
|
||||
(tc (semanticdb-get-typecache tab)))
|
||||
(semanticdb-typecache-file-tags tab)
|
||||
(semanticdb-typecache-include-tags tab)
|
||||
tc)))
|
||||
|
||||
|
||||
;;; DEBUG
|
||||
;;
|
||||
(defun semanticdb-typecache-complete-flush ()
|
||||
"Flush all typecaches referenced by the current buffer."
|
||||
(interactive)
|
||||
(let* ((path (semanticdb-find-translate-path nil nil)))
|
||||
(dolist (P path)
|
||||
(oset P pointmax nil)
|
||||
(semantic-reset (semanticdb-get-typecache P)))))
|
||||
|
||||
(defun semanticdb-typecache-dump ()
|
||||
"Dump the typecache for the current buffer."
|
||||
(interactive)
|
||||
(require 'data-debug)
|
||||
(let* ((start (current-time))
|
||||
(tc (semanticdb-typecache-refresh-for-buffer (current-buffer)))
|
||||
(end (current-time))
|
||||
)
|
||||
(data-debug-new-buffer "*TypeCache ADEBUG*")
|
||||
(message "Calculating Cache took %.2f seconds."
|
||||
(semantic-elapsed-time start end))
|
||||
|
||||
(data-debug-insert-thing tc "]" "")
|
||||
|
||||
))
|
||||
|
||||
(defun semanticdb-db-typecache-dump ()
|
||||
"Dump the typecache for the current buffer's database."
|
||||
(interactive)
|
||||
(require 'data-debug)
|
||||
(let* ((tab semanticdb-current-table)
|
||||
(idx (semanticdb-get-table-index tab))
|
||||
(junk (oset idx type-cache nil)) ;; flush!
|
||||
(start (current-time))
|
||||
(tc (semanticdb-typecache-for-database (oref tab parent-db)))
|
||||
(end (current-time))
|
||||
)
|
||||
(data-debug-new-buffer "*TypeCache ADEBUG*")
|
||||
(message "Calculating Cache took %.2f seconds."
|
||||
(semantic-elapsed-time start end))
|
||||
|
||||
(data-debug-insert-thing tc "]" "")
|
||||
|
||||
))
|
||||
|
||||
|
||||
(provide 'semantic/db-typecache)
|
||||
;;; semanticdb-typecache.el ends here
|
||||
228
lisp/cedet/semantic/dep.el
Normal file
228
lisp/cedet/semantic/dep.el
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
;;; dep.el --- Methods for tracking dependencies (include files)
|
||||
|
||||
;;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
;; Keywords: syntax
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Include tags (dependencies for a given source file) usually have
|
||||
;; some short name. The target file that it is dependent on is
|
||||
;; generally found on some sort of path controlled by the compiler or
|
||||
;; project.
|
||||
;;
|
||||
;; EDE or even ECB can control our project dependencies, and help us
|
||||
;; find file within the setting of a given project. For system
|
||||
;; dependencies, we need to depend on user supplied lists, which can
|
||||
;; manifest themselves in the form of system datatabases (from
|
||||
;; semanticdb.)
|
||||
;;
|
||||
;; Provide ways to track these different files here.
|
||||
|
||||
(require 'semantic/tag)
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defvar semantic-dependency-include-path nil
|
||||
"Defines the include path used when searching for files.
|
||||
This should be a list of directories to search which is specific
|
||||
to the file being included.
|
||||
|
||||
If `semantic-dependency-tag-file' is overridden for a given
|
||||
language, this path is most likely ignored.
|
||||
|
||||
The above function, reguardless of being overriden, caches the
|
||||
located dependency file location in the tag property
|
||||
`dependency-file'. If you override this function, you do not
|
||||
need to implement your own cache. Each time the buffer is fully
|
||||
reparsed, the cache will be reset.
|
||||
|
||||
TODO: use ffap.el to locate such items?
|
||||
|
||||
NOTE: Obsolete this, or use as special user")
|
||||
(make-variable-buffer-local `semantic-dependency-include-path)
|
||||
|
||||
(defvar semantic-dependency-system-include-path nil
|
||||
"Defines the system include path.
|
||||
This should be set with either `defvar-mode-local', or with
|
||||
`semantic-add-system-include'.
|
||||
|
||||
For mode authors, use
|
||||
`defcustom-mode-local-semantic-dependency-system-include-path'
|
||||
to create a mode-specific variable to control this.
|
||||
|
||||
When searching for a file associated with a name found in an tag of
|
||||
class include, this path will be inspected for includes of type
|
||||
`system'. Some include tags are agnostic to this setting and will
|
||||
check both the project and system directories.")
|
||||
(make-variable-buffer-local `semantic-dependency-system-include-path)
|
||||
|
||||
(defmacro defcustom-mode-local-semantic-dependency-system-include-path
|
||||
(mode name value &optional docstring)
|
||||
"Create a mode-local value of the system-dependency include path.
|
||||
MODE is the `major-mode' this name/value pairs is for.
|
||||
NAME is the name of the customizable value users will use.
|
||||
VALUE is the path (a list of strings) to add.
|
||||
DOCSTRING is a documentation string applied to the variable NAME
|
||||
users will customize.
|
||||
|
||||
Creates a customizable variable users can customize that will
|
||||
keep semantic data structures up to date."
|
||||
`(progn
|
||||
;; Create a variable users can customize.
|
||||
(defcustom ,name ,value
|
||||
,docstring
|
||||
:group (quote ,(intern (car (split-string (symbol-name mode) "-"))))
|
||||
:group 'semantic
|
||||
:type '(repeat (directory :tag "Directory"))
|
||||
:set (lambda (sym val)
|
||||
(set-default sym val)
|
||||
(setq-mode-local ,mode
|
||||
semantic-dependency-system-include-path
|
||||
val)
|
||||
(when (fboundp
|
||||
'semantic-decoration-unparsed-include-do-reset)
|
||||
(mode-local-map-mode-buffers
|
||||
'semantic-decoration-unparsed-include-do-reset
|
||||
(quote ,mode))))
|
||||
)
|
||||
;; Set the variable to the default value.
|
||||
(defvar-mode-local ,mode semantic-dependency-system-include-path
|
||||
,name
|
||||
"System path to search for include files.")
|
||||
;; Bind NAME onto our variable so tools can customize it
|
||||
;; without knowing about it.
|
||||
(put 'semantic-dependency-system-include-path
|
||||
(quote ,mode) (quote ,name))
|
||||
))
|
||||
|
||||
;;; PATH MANAGEMENT
|
||||
;;
|
||||
;; Some fcns to manage paths for a give mode.
|
||||
(defun semantic-add-system-include (dir &optional mode)
|
||||
"Add a system include DIR to path for MODE.
|
||||
Modifies a mode-local version of `semantic-dependency-system-include-path'.
|
||||
|
||||
Changes made by this function are not persistent."
|
||||
(interactive "DNew Include Directory: ")
|
||||
(if (not mode) (setq mode major-mode))
|
||||
(let ((dirtmp (file-name-as-directory dir))
|
||||
(value
|
||||
(mode-local-value mode 'semantic-dependency-system-include-path))
|
||||
)
|
||||
(add-to-list 'value dirtmp t)
|
||||
(eval `(setq-mode-local ,mode
|
||||
semantic-dependency-system-include-path value))
|
||||
))
|
||||
|
||||
(defun semantic-remove-system-include (dir &optional mode)
|
||||
"Add a system include DIR to path for MODE.
|
||||
Modifies a mode-local version of`semantic-dependency-system-include-path'.
|
||||
|
||||
Changes made by this function are not persistent."
|
||||
(interactive (list
|
||||
(completing-read
|
||||
"Include Directory to Remove: "
|
||||
semantic-dependency-system-include-path))
|
||||
)
|
||||
(if (not mode) (setq mode major-mode))
|
||||
(let ((dirtmp (file-name-as-directory dir))
|
||||
(value
|
||||
(mode-local-value mode 'semantic-dependency-system-include-path))
|
||||
)
|
||||
(setq value (delete dirtmp value))
|
||||
(eval `(setq-mode-local ,mode semantic-dependency-system-include-path
|
||||
value))
|
||||
))
|
||||
|
||||
(defun semantic-reset-system-include (&optional mode)
|
||||
"Reset the system include list to empty for MODE.
|
||||
Modifies a mode-local version of
|
||||
`semantic-dependency-system-include-path'."
|
||||
(interactive)
|
||||
(if (not mode) (setq mode major-mode))
|
||||
(eval `(setq-mode-local ,mode semantic-dependency-system-include-path
|
||||
nil))
|
||||
)
|
||||
|
||||
(defun semantic-customize-system-include-path (&optional mode)
|
||||
"Customize the include path for this `major-mode'.
|
||||
To create a customizable include path for a major MODE, use the
|
||||
macro `defcustom-mode-local-semantic-dependency-system-include-path'."
|
||||
(interactive)
|
||||
(let ((ips (get 'semantic-dependency-system-include-path
|
||||
(or mode major-mode))))
|
||||
;; Do we have one?
|
||||
(when (not ips)
|
||||
(error "There is no customizable includepath variable for %s"
|
||||
(or mode major-mode)))
|
||||
;; Customize it.
|
||||
(customize-variable ips)))
|
||||
|
||||
;;; PATH SEARCH
|
||||
;;
|
||||
;; methods for finding files on a provided path.
|
||||
(if (fboundp 'locate-file)
|
||||
(defsubst semantic--dependency-find-file-on-path (file path)
|
||||
"Return an expanded file name for FILE on PATH."
|
||||
(locate-file file path))
|
||||
|
||||
;; Else, older version of Emacs.
|
||||
|
||||
(defsubst semantic--dependency-find-file-on-path (file path)
|
||||
"Return an expanded file name for FILE on PATH."
|
||||
(let ((p path)
|
||||
(found nil))
|
||||
(while (and p (not found))
|
||||
(let ((f (expand-file-name file (car p))))
|
||||
(if (file-exists-p f)
|
||||
(setq found f)))
|
||||
(setq p (cdr p)))
|
||||
found))
|
||||
|
||||
)
|
||||
|
||||
(defun semantic-dependency-find-file-on-path (file systemp &optional mode)
|
||||
"Return an expanded file name for FILE on available paths.
|
||||
If SYSTEMP is true, then only search system paths.
|
||||
If optional argument MODE is non-nil, then derive paths from the
|
||||
provided mode, not from the current major mode."
|
||||
(if (not mode) (setq mode major-mode))
|
||||
(let ((sysp (mode-local-value
|
||||
mode 'semantic-dependency-system-include-path))
|
||||
(edesys (when (and (featurep 'ede) ede-minor-mode
|
||||
ede-object)
|
||||
(ede-system-include-path ede-object)))
|
||||
(locp (mode-local-value
|
||||
mode 'semantic-dependency-include-path))
|
||||
(found nil))
|
||||
(when (file-exists-p file)
|
||||
(setq found file))
|
||||
(when (and (not found) (not systemp))
|
||||
(setq found (semantic--dependency-find-file-on-path file locp)))
|
||||
(when (and (not found) edesys)
|
||||
(setq found (semantic--dependency-find-file-on-path file edesys)))
|
||||
(when (not found)
|
||||
(setq found (semantic--dependency-find-file-on-path file sysp)))
|
||||
(if found (expand-file-name found))))
|
||||
|
||||
|
||||
(provide 'semantic/dep)
|
||||
|
||||
;;; semantic-dep.el ends here
|
||||
439
lisp/cedet/semantic/ia.el
Normal file
439
lisp/cedet/semantic/ia.el
Normal file
|
|
@ -0,0 +1,439 @@
|
|||
;;; ia.el --- Interactive Analysis functions
|
||||
|
||||
;;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
;;; 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
;; Keywords: syntax
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Interactive access to `semantic-analyze'.
|
||||
;;
|
||||
;; These routines are fairly simple, and show how to use the Semantic
|
||||
;; analyzer to provide things such as completion lists, summaries,
|
||||
;; locations, or documentation.
|
||||
;;
|
||||
|
||||
;;; TODO
|
||||
;;
|
||||
;; fast-jump. For a virtual method, offer some of the possible
|
||||
;; implementations in various sub-classes.
|
||||
|
||||
(require 'senator)
|
||||
(require 'semantic/analyze)
|
||||
(require 'pulse)
|
||||
(eval-when-compile
|
||||
(require 'semantic/analyze)
|
||||
(require 'semantic/analyze/refs))
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;; COMPLETION
|
||||
;;
|
||||
;; This set of routines provides some simplisting completion
|
||||
;; functions.
|
||||
|
||||
(defcustom semantic-ia-completion-format-tag-function
|
||||
'semantic-prototype-nonterminal
|
||||
"*Function used to convert a tag to a string during completion."
|
||||
:group 'semantic
|
||||
:type semantic-format-tag-custom-list)
|
||||
|
||||
(defvar semantic-ia-cache nil
|
||||
"Cache of the last completion request.
|
||||
Of the form ( POINT . COMPLETIONS ) where POINT is a location in the
|
||||
buffer where the completion was requested. COMPLETONS is the list
|
||||
of semantic tag names that provide logical completions from that
|
||||
location.")
|
||||
(make-variable-buffer-local 'semantic-ia-cache)
|
||||
|
||||
(defun semantic-ia-get-completions (context point)
|
||||
"Fetch the completion of CONTEXT at POINT.
|
||||
Supports caching."
|
||||
;; Cache the current set of symbols so that we can get at
|
||||
;; them quickly the second time someone presses the
|
||||
;; complete button.
|
||||
(let ((symbols
|
||||
(if (and semantic-ia-cache
|
||||
(= point (car semantic-ia-cache)))
|
||||
(cdr semantic-ia-cache)
|
||||
(semantic-analyze-possible-completions context))))
|
||||
;; Set the cache
|
||||
(setq semantic-ia-cache (cons point symbols))
|
||||
symbols))
|
||||
|
||||
(defun semantic-ia-complete-symbol (point)
|
||||
"Complete the current symbol at POINT.
|
||||
Completion options are calculated with `semantic-analyze-possible-completions'."
|
||||
(interactive "d")
|
||||
;; Calculating completions is a two step process.
|
||||
;;
|
||||
;; The first analyzer the current context, which finds tags
|
||||
;; for all the stuff that may be references by the code around
|
||||
;; POINT.
|
||||
;;
|
||||
;; The second step derives completions from that context.
|
||||
(let* ((a (semantic-analyze-current-context point))
|
||||
(syms (semantic-ia-get-completions a point))
|
||||
(pre (car (reverse (oref a prefix))))
|
||||
)
|
||||
;; If PRE was actually an already completed symbol, it doesn't
|
||||
;; come in as a string, but as a tag instead.
|
||||
(if (semantic-tag-p pre)
|
||||
;; We will try completions on it anyway.
|
||||
(setq pre (semantic-tag-name pre)))
|
||||
;; Complete this symbol.
|
||||
(if (null syms)
|
||||
(progn
|
||||
;(message "No smart completions found. Trying senator-complete-symbol.")
|
||||
(if (semantic-analyze-context-p a)
|
||||
;; This is a clever hack. If we were unable to find any
|
||||
;; smart completions, lets divert to how senator derives
|
||||
;; completions.
|
||||
;;
|
||||
;; This is a way of making this fcn more useful since the
|
||||
;; smart completion engine sometimes failes.
|
||||
(senator-complete-symbol)
|
||||
))
|
||||
;; Use try completion to seek a common substring.
|
||||
(let ((tc (try-completion (or pre "") syms)))
|
||||
(if (and (stringp tc) (not (string= tc (or pre ""))))
|
||||
(let ((tok (semantic-find-first-tag-by-name
|
||||
tc syms)))
|
||||
;; Delete what came before...
|
||||
(when (and (car (oref a bounds)) (cdr (oref a bounds)))
|
||||
(delete-region (car (oref a bounds))
|
||||
(cdr (oref a bounds)))
|
||||
(goto-char (car (oref a bounds))))
|
||||
;; We have some new text. Stick it in.
|
||||
(if tok
|
||||
(semantic-ia-insert-tag tok)
|
||||
(insert tc)))
|
||||
;; We don't have new text. Show all completions.
|
||||
(when (cdr (oref a bounds))
|
||||
(goto-char (cdr (oref a bounds))))
|
||||
(with-output-to-temp-buffer "*Completions*"
|
||||
(display-completion-list
|
||||
(mapcar semantic-ia-completion-format-tag-function syms))
|
||||
))))))
|
||||
|
||||
(defcustom semantic-ia-completion-menu-format-tag-function
|
||||
'semantic-uml-concise-prototype-nonterminal
|
||||
"*Function used to convert a tag to a string during completion."
|
||||
:group 'semantic
|
||||
:type semantic-format-tag-custom-list)
|
||||
|
||||
(defun semantic-ia-complete-symbol-menu (point)
|
||||
"Complete the current symbol via a menu based at POINT.
|
||||
Completion options are calculated with `semantic-analyze-possible-completions'."
|
||||
(interactive "d")
|
||||
(let* ((a (semantic-analyze-current-context point))
|
||||
(syms (semantic-ia-get-completions a point))
|
||||
)
|
||||
;; Complete this symbol.
|
||||
(if (not syms)
|
||||
(progn
|
||||
(message "No smart completions found. Trying Senator.")
|
||||
(when (semantic-analyze-context-p a)
|
||||
;; This is a quick way of getting a nice completion list
|
||||
;; in the menu if the regular context mechanism fails.
|
||||
(senator-completion-menu-popup)))
|
||||
|
||||
(let* ((menu
|
||||
(mapcar
|
||||
(lambda (tag)
|
||||
(cons
|
||||
(funcall semantic-ia-completion-menu-format-tag-function tag)
|
||||
(vector tag)))
|
||||
syms))
|
||||
(ans
|
||||
(imenu--mouse-menu
|
||||
;; XEmacs needs that the menu has at least 2 items. So,
|
||||
;; include a nil item that will be ignored by imenu.
|
||||
(cons nil menu)
|
||||
(senator-completion-menu-point-as-event)
|
||||
"Completions")))
|
||||
(when ans
|
||||
(if (not (semantic-tag-p ans))
|
||||
(setq ans (aref (cdr ans) 0)))
|
||||
(delete-region (car (oref a bounds)) (cdr (oref a bounds)))
|
||||
(semantic-ia-insert-tag ans))
|
||||
))))
|
||||
|
||||
;;; COMPLETION HELPER
|
||||
;;
|
||||
;; This overload function handles inserting a tag
|
||||
;; into a buffer for these local completion routines.
|
||||
;;
|
||||
;; By creating the functions as overloadable, it can be
|
||||
;; customized. For example, the default will put a paren "("
|
||||
;; character after function names. For Lisp, it might check
|
||||
;; to put a "(" in front of a function name.
|
||||
|
||||
(define-overloadable-function semantic-ia-insert-tag (tag)
|
||||
"Insert TAG into the current buffer based on completion.")
|
||||
|
||||
(defun semantic-ia-insert-tag-default (tag)
|
||||
"Insert TAG into the current buffer based on completion."
|
||||
(insert (semantic-tag-name tag))
|
||||
(let ((tt (semantic-tag-class tag)))
|
||||
(cond ((eq tt 'function)
|
||||
(insert "("))
|
||||
(t nil))))
|
||||
|
||||
;;; Completions Tip
|
||||
;;
|
||||
;; This functions shows how to get the list of completions,
|
||||
;; to place in a tooltip. It doesn't actually do any completion.
|
||||
|
||||
(defun semantic-ia-complete-tip (point)
|
||||
"Pop up a tooltip for completion at POINT."
|
||||
(interactive "d")
|
||||
(let* ((a (semantic-analyze-current-context point))
|
||||
(syms (semantic-ia-get-completions a point))
|
||||
(x (mod (- (current-column) (window-hscroll))
|
||||
(window-width)))
|
||||
(y (save-excursion
|
||||
(save-restriction
|
||||
(widen)
|
||||
(narrow-to-region (window-start) (point))
|
||||
(goto-char (point-min))
|
||||
(1+ (vertical-motion (buffer-size))))))
|
||||
(str (mapconcat #'semantic-tag-name
|
||||
syms
|
||||
"\n"))
|
||||
)
|
||||
(cond ((fboundp 'x-show-tip)
|
||||
(x-show-tip str
|
||||
(selected-frame)
|
||||
nil
|
||||
nil
|
||||
x y)
|
||||
)
|
||||
(t (message str))
|
||||
)))
|
||||
|
||||
;;; Summary
|
||||
;;
|
||||
;; Like idle-summary-mode, this shows how to get something to
|
||||
;; show a summary on.
|
||||
|
||||
(defun semantic-ia-show-summary (point)
|
||||
"Display a summary for the symbol under POINT."
|
||||
(interactive "P")
|
||||
(let* ((ctxt (semantic-analyze-current-context point))
|
||||
(pf (when ctxt
|
||||
;; The CTXT is an EIEIO object. The below
|
||||
;; method will attempt to pick the most interesting
|
||||
;; tag associated with the current context.
|
||||
(semantic-analyze-interesting-tag ctxt)))
|
||||
)
|
||||
(when pf
|
||||
(message "%s" (semantic-format-tag-summarize pf nil t)))))
|
||||
|
||||
;;; FAST Jump
|
||||
;;
|
||||
;; Jump to a destination based on the local context.
|
||||
;;
|
||||
;; This shows how to use the analyzer context, and the
|
||||
;; analyer references objects to choose a good destination.
|
||||
|
||||
(defun semantic-ia--fast-jump-helper (dest)
|
||||
"Jump to DEST, a Semantic tag.
|
||||
This helper manages the mark, buffer switching, and pulsing."
|
||||
;; We have a tag, but in C++, we usually get a prototype instead
|
||||
;; because of header files. Lets try to find the actual
|
||||
;; implementaion instead.
|
||||
(when (semantic-tag-prototype-p dest)
|
||||
(let* ((refs (semantic-analyze-tag-references dest))
|
||||
(impl (semantic-analyze-refs-impl refs t))
|
||||
)
|
||||
(when impl (setq dest (car impl)))))
|
||||
|
||||
;; Make sure we have a place to go...
|
||||
(if (not (and (or (semantic-tag-with-position-p dest)
|
||||
(semantic-tag-get-attribute dest :line))
|
||||
(semantic-tag-file-name dest)))
|
||||
(error "Tag %s has no buffer information"
|
||||
(semantic-format-tag-name dest)))
|
||||
|
||||
;; Once we have the tag, we can jump to it. Here
|
||||
;; are the key bits to the jump:
|
||||
|
||||
;; 1) Push the mark, so you can pop global mark back, or
|
||||
;; use semantic-mru-bookmark mode to do so.
|
||||
(push-mark)
|
||||
(when (fboundp 'push-tag-mark)
|
||||
(push-tag-mark))
|
||||
;; 2) Visits the tag.
|
||||
(semantic-go-to-tag dest)
|
||||
;; 3) go-to-tag doesn't switch the buffer in the current window,
|
||||
;; so it is like find-file-noselect. Bring it forward.
|
||||
(switch-to-buffer (current-buffer))
|
||||
;; 4) Fancy pulsing.
|
||||
(pulse-momentary-highlight-one-line (point))
|
||||
)
|
||||
|
||||
(defun semantic-ia-fast-jump (point)
|
||||
"Jump to the tag referred to by the code at POINT.
|
||||
Uses `semantic-analyze-current-context' output to identify an accurate
|
||||
origin of the code at point."
|
||||
(interactive "d")
|
||||
(let* ((ctxt (semantic-analyze-current-context point))
|
||||
(pf (and ctxt (reverse (oref ctxt prefix))))
|
||||
;; In the analyzer context, the PREFIX is the list of items
|
||||
;; that makes up the code context at point. Thus the c++ code
|
||||
;; this.that().theothe
|
||||
;; would make a list:
|
||||
;; ( ("this" variable ..) ("that" function ...) "theothe")
|
||||
;; Where the first two elements are the semantic tags of the prefix.
|
||||
;;
|
||||
;; PF is the reverse of this list. If the first item is a string,
|
||||
;; then it is an incomplete symbol, thus we pick the second.
|
||||
;; The second cannot be a string, as that would have been an error.
|
||||
(first (car pf))
|
||||
(second (nth 1 pf))
|
||||
)
|
||||
(cond
|
||||
((semantic-tag-p first)
|
||||
;; We have a match. Just go there.
|
||||
(semantic-ia--fast-jump-helper first))
|
||||
|
||||
((semantic-tag-p second)
|
||||
;; Because FIRST failed, we should visit our second tag.
|
||||
;; HOWEVER, the tag we actually want that was only an unfound
|
||||
;; string may be related to some take in the datatype that belongs
|
||||
;; to SECOND. Thus, instead of visiting second directly, we
|
||||
;; can offer to find the type of SECOND, and go there.
|
||||
(let ((secondclass (car (reverse (oref ctxt prefixtypes)))))
|
||||
(cond
|
||||
((and (semantic-tag-with-position-p secondclass)
|
||||
(y-or-n-p (format "Could not find `%s'. Jump to %s? "
|
||||
first (semantic-tag-name secondclass))))
|
||||
(semantic-ia--fast-jump-helper secondclass)
|
||||
)
|
||||
;; If we missed out on the class of the second item, then
|
||||
;; just visit SECOND.
|
||||
((and (semantic-tag-p second)
|
||||
(y-or-n-p (format "Could not find `%s'. Jump to %s? "
|
||||
first (semantic-tag-name second))))
|
||||
(semantic-ia--fast-jump-helper second)
|
||||
))))
|
||||
|
||||
((semantic-tag-of-class-p (semantic-current-tag) 'include)
|
||||
;; Just borrow this cool fcn.
|
||||
(semantic-decoration-include-visit)
|
||||
)
|
||||
|
||||
(t
|
||||
(error "Could not find suitable jump point for %s"
|
||||
first))
|
||||
)))
|
||||
|
||||
(defun semantic-ia-fast-mouse-jump (evt)
|
||||
"Jump to the tag referred to by the point clicked on.
|
||||
See `semantic-ia-fast-jump' for details on how it works.
|
||||
This command is meant to be bound to a mouse event."
|
||||
(interactive "e")
|
||||
(semantic-ia-fast-jump
|
||||
(save-excursion
|
||||
(posn-set-point (event-end evt))
|
||||
(point))))
|
||||
|
||||
;;; DOC/DESCRIBE
|
||||
;;
|
||||
;; These routines show how to get additional information about a tag
|
||||
;; for purposes of describing or showing documentation about them.
|
||||
(defun semantic-ia-show-doc (point)
|
||||
"Display the code-level documentation for the symbol at POINT."
|
||||
(interactive "d")
|
||||
(let* ((ctxt (semantic-analyze-current-context point))
|
||||
(pf (reverse (oref ctxt prefix)))
|
||||
)
|
||||
;; If PF, the prefix is non-nil, then the last element is either
|
||||
;; a string (incomplete type), or a semantic TAG. If it is a TAG
|
||||
;; then we should be able to find DOC for it.
|
||||
(cond
|
||||
((stringp (car pf))
|
||||
(message "Incomplete symbol name."))
|
||||
((semantic-tag-p (car pf))
|
||||
;; The `semantic-documentation-for-tag' fcn is language
|
||||
;; specific. If it doesn't return what you expect, you may
|
||||
;; need to implement something for your language.
|
||||
;;
|
||||
;; The default tries to find a comment in front of the tag
|
||||
;; and then strings off comment prefixes.
|
||||
(let ((doc (semantic-documentation-for-tag (car pf))))
|
||||
(with-output-to-temp-buffer "*TAG DOCUMENTATION*"
|
||||
(princ "Tag: ")
|
||||
(princ (semantic-format-tag-prototype (car pf)))
|
||||
(princ "\n")
|
||||
(princ "\n")
|
||||
(princ "Snarfed Documentation: ")
|
||||
(princ "\n")
|
||||
(princ "\n")
|
||||
(if doc
|
||||
(princ doc)
|
||||
(princ " Documentation unavailable."))
|
||||
)))
|
||||
(t
|
||||
(message "Unknown tag.")))
|
||||
))
|
||||
|
||||
(defun semantic-ia-describe-class (typename)
|
||||
"Display all known parts for the datatype TYPENAME.
|
||||
If the type in question is a class, all methods and other accessible
|
||||
parts of the parent classes are displayed."
|
||||
;; @todo - use a fancy completing reader.
|
||||
(interactive "sType Name: ")
|
||||
|
||||
;; When looking for a tag of any name there are a couple ways to do
|
||||
;; it. The simple `semanticdb-find-tag-by-...' are simple, and
|
||||
;; you need to pass it the exact name you want.
|
||||
;;
|
||||
;; The analyzer function `semantic-analyze-tag-name' will take
|
||||
;; more complex names, such as the cpp symbol foo::bar::baz,
|
||||
;; and break it up, and dive through the namespaces.
|
||||
(let ((class (semantic-analyze-find-tag typename)))
|
||||
|
||||
(when (not (semantic-tag-p class))
|
||||
(error "Cannot find class %s" class))
|
||||
(with-output-to-temp-buffer "*TAG DOCUMENTATION*"
|
||||
;; There are many semantic-format-tag-* fcns.
|
||||
;; The summarize routine is a fairly generic one.
|
||||
(princ (semantic-format-tag-summarize class))
|
||||
(princ "\n")
|
||||
(princ " Type Members:\n")
|
||||
;; The type tag contains all the parts of the type.
|
||||
;; In complex languages with inheritance, not all the
|
||||
;; parts are in the tag. This analyzer fcn will traverse
|
||||
;; the inheritance tree, and find all the pieces that
|
||||
;; are inherited.
|
||||
(let ((parts (semantic-analyze-scoped-type-parts class)))
|
||||
(while parts
|
||||
(princ " ")
|
||||
(princ (semantic-format-tag-summarize (car parts)))
|
||||
(princ "\n")
|
||||
(setq parts (cdr parts)))
|
||||
)
|
||||
)))
|
||||
|
||||
(provide 'semantic/ia)
|
||||
|
||||
;;; semantic-ia.el ends here
|
||||
202
lisp/cedet/semantic/tag-file.el
Normal file
202
lisp/cedet/semantic/tag-file.el
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
;;; tag-file.el --- Routines that find files based on tags.
|
||||
|
||||
;;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007,
|
||||
;;; 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
;; Keywords: syntax
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; A tag, by itself, can have representations in several files.
|
||||
;; These routines will find those files.
|
||||
|
||||
(require 'semantic/tag)
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;; Location a TAG came from.
|
||||
;;
|
||||
(define-overloadable-function semantic-go-to-tag (tag &optional parent)
|
||||
"Go to the location of TAG.
|
||||
TAG may be a stripped element, in which case PARENT specifies a
|
||||
parent tag that has position information.
|
||||
PARENT can also be a `semanticdb-table' object."
|
||||
(:override
|
||||
(cond ((semantic-tag-in-buffer-p tag)
|
||||
;; We have a linked tag, go to that buffer.
|
||||
(set-buffer (semantic-tag-buffer tag)))
|
||||
((semantic-tag-file-name tag)
|
||||
;; If it didn't have a buffer, but does have a file
|
||||
;; name, then we need to get to that file so the tag
|
||||
;; location is made accurate.
|
||||
(set-buffer (find-file-noselect (semantic-tag-file-name tag))))
|
||||
((and parent (semantic-tag-p parent) (semantic-tag-in-buffer-p parent))
|
||||
;; The tag had nothing useful, but we have a parent with
|
||||
;; a buffer, then go there.
|
||||
(set-buffer (semantic-tag-buffer parent)))
|
||||
((and parent (semantic-tag-p parent) (semantic-tag-file-name parent))
|
||||
;; Tag had nothing, and the parent only has a file-name, then
|
||||
;; find that file, and switch to that buffer.
|
||||
(set-buffer (find-file-noselect (semantic-tag-file-name parent))))
|
||||
((and parent (semanticdb-table-child-p parent))
|
||||
(set-buffer (semanticdb-get-buffer parent)))
|
||||
(t
|
||||
;; Well, just assume things are in the current buffer.
|
||||
nil
|
||||
))
|
||||
;; We should be in the correct buffer now, try and figure out
|
||||
;; where the tag is.
|
||||
(cond ((semantic-tag-with-position-p tag)
|
||||
;; If it's a number, go there
|
||||
(goto-char (semantic-tag-start tag)))
|
||||
((semantic-tag-with-position-p parent)
|
||||
;; Otherwise, it's a trimmed vector, such as a parameter,
|
||||
;; or a structure part. If there is a parent, we can use it
|
||||
;; as a bounds for searching.
|
||||
(goto-char (semantic-tag-start parent))
|
||||
;; Here we make an assumption that the text returned by
|
||||
;; the parser and concocted by us actually exists
|
||||
;; in the buffer.
|
||||
(re-search-forward (semantic-tag-name tag)
|
||||
(semantic-tag-end parent)
|
||||
t))
|
||||
((semantic-tag-get-attribute tag :line)
|
||||
;; The tag has a line number in it. Go there.
|
||||
(goto-line (semantic-tag-get-attribute tag :line)))
|
||||
((and (semantic-tag-p parent) (semantic-tag-get-attribute parent :line))
|
||||
;; The tag has a line number in it. Go there.
|
||||
(goto-line (semantic-tag-get-attribute parent :line))
|
||||
(re-search-forward (semantic-tag-name tag) nil t)
|
||||
)
|
||||
(t
|
||||
;; Take a guess that the tag has a unique name, and just
|
||||
;; search for it from the beginning of the buffer.
|
||||
(goto-char (point-min))
|
||||
(re-search-forward (semantic-tag-name tag) nil t)))
|
||||
)
|
||||
)
|
||||
|
||||
(make-obsolete-overload 'semantic-find-nonterminal
|
||||
'semantic-go-to-tag)
|
||||
|
||||
;;; Dependencies
|
||||
;;
|
||||
;; A tag which is of type 'include specifies a dependency.
|
||||
;; Dependencies usually represent a file of some sort.
|
||||
;; Find the file described by a dependency.
|
||||
|
||||
(define-overloadable-function semantic-dependency-tag-file (&optional tag)
|
||||
"Find the filename represented from TAG.
|
||||
Depends on `semantic-dependency-include-path' for searching. Always searches
|
||||
`.' first, then searches additional paths."
|
||||
(or tag (setq tag (car (semantic-find-tag-by-overlay nil))))
|
||||
(unless (semantic-tag-of-class-p tag 'include)
|
||||
(signal 'wrong-type-argument (list tag 'include)))
|
||||
(save-excursion
|
||||
(let ((result nil)
|
||||
(default-directory default-directory)
|
||||
(edefind nil)
|
||||
(tag-fname nil))
|
||||
(cond ((semantic-tag-in-buffer-p tag)
|
||||
;; If the tag has an overlay and buffer associated with it,
|
||||
;; switch to that buffer so that we get the right override metohds.
|
||||
(set-buffer (semantic-tag-buffer tag)))
|
||||
((semantic-tag-file-name tag)
|
||||
;; If it didn't have a buffer, but does have a file
|
||||
;; name, then we need to get to that file so the tag
|
||||
;; location is made accurate.
|
||||
;;(set-buffer (find-file-noselect (semantic-tag-file-name tag)))
|
||||
;;
|
||||
;; 2/3/08
|
||||
;; The above causes unnecessary buffer loads all over the place. Ick!
|
||||
;; All we really need is for 'default-directory' to be set correctly.
|
||||
(setq default-directory (file-name-directory (semantic-tag-file-name tag)))
|
||||
))
|
||||
;; Setup the filename represented by this include
|
||||
(setq tag-fname (semantic-tag-include-filename tag))
|
||||
|
||||
;; First, see if this file exists in the current EDE project
|
||||
(if (and (fboundp 'ede-expand-filename) ede-minor-mode
|
||||
(setq edefind
|
||||
(condition-case nil
|
||||
(let ((proj (ede-toplevel)))
|
||||
(when proj
|
||||
(ede-expand-filename proj tag-fname)))
|
||||
(error nil))))
|
||||
(setq result edefind))
|
||||
(if (not result)
|
||||
(setq result
|
||||
;; I don't have a plan for refreshing tags with a dependency
|
||||
;; stuck on them somehow. I'm thinking that putting a cache
|
||||
;; onto the dependancy finding with a hash table might be best.
|
||||
;;(if (semantic--tag-get-property tag 'dependency-file)
|
||||
;; (semantic--tag-get-property tag 'dependency-file)
|
||||
(:override
|
||||
(save-excursion
|
||||
(semantic-dependency-find-file-on-path
|
||||
tag-fname (semantic-tag-include-system-p tag))))
|
||||
;; )
|
||||
))
|
||||
(if (stringp result)
|
||||
(progn
|
||||
(semantic--tag-put-property tag 'dependency-file result)
|
||||
result)
|
||||
;; @todo: Do something to make this get flushed w/
|
||||
;; when the path is changed.
|
||||
;; @undo: Just eliminate
|
||||
;; (semantic--tag-put-property tag 'dependency-file 'none)
|
||||
nil)
|
||||
)))
|
||||
|
||||
(make-obsolete-overload 'semantic-find-dependency
|
||||
'semantic-dependency-tag-file)
|
||||
|
||||
;;; PROTOTYPE FILE
|
||||
;;
|
||||
;; In C, a function in the .c file often has a representation in a
|
||||
;; corresponding .h file. This routine attempts to find the
|
||||
;; prototype file a given source file would be associated with.
|
||||
;; This can be used by prototype manager programs.
|
||||
(define-overloadable-function semantic-prototype-file (buffer)
|
||||
"Return a file in which prototypes belonging to BUFFER should be placed.
|
||||
Default behavior (if not overridden) looks for a token specifying the
|
||||
prototype file, or the existence of an EDE variable indicating which
|
||||
file prototypes belong in."
|
||||
(:override
|
||||
;; Perform some default behaviors
|
||||
(if (and (fboundp 'ede-header-file) ede-minor-mode)
|
||||
(save-excursion
|
||||
(set-buffer buffer)
|
||||
(ede-header-file))
|
||||
;; No EDE options for a quick answer. Search.
|
||||
(save-excursion
|
||||
(set-buffer buffer)
|
||||
(if (re-search-forward "::Header:: \\([a-zA-Z0-9.]+\\)" nil t)
|
||||
(match-string 1))))))
|
||||
|
||||
(semantic-alias-obsolete 'semantic-find-nonterminal
|
||||
'semantic-go-to-tag)
|
||||
|
||||
(semantic-alias-obsolete 'semantic-find-dependency
|
||||
'semantic-dependency-tag-file)
|
||||
|
||||
|
||||
(provide 'semantic/tag-file)
|
||||
|
||||
;;; semantic-tag-file.el ends here
|
||||
276
lisp/cedet/semantic/tag-ls.el
Normal file
276
lisp/cedet/semantic/tag-ls.el
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
;;; tag-ls.el --- Language Specific override functions for tags
|
||||
|
||||
;;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2006, 2007, 2008
|
||||
;;; Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; There are some features of tags that are too langauge dependent to
|
||||
;; put in the core `semantic-tag' functionality. For instance, the
|
||||
;; protection of a tag (as specified by UML) could be almost anything.
|
||||
;; In Java, it is a type specifier. In C, there is a label. This
|
||||
;; informatin can be derived, and thus should not be stored in the tag
|
||||
;; itself. These are the functions that languages can use to derive
|
||||
;; the information.
|
||||
|
||||
(require 'semantic/tag)
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;; UML features:
|
||||
;;
|
||||
;; UML can represent several types of features of a tag
|
||||
;; such as the `protection' of a symbol, or if it is abstract,
|
||||
;; leaf, etc. Learn about UML to catch onto the lingo.
|
||||
|
||||
(define-overloadable-function semantic-tag-calculate-parent (tag)
|
||||
"Attempt to calculate the parent of TAG.
|
||||
The default behavior (if not overriden with `tag-calculate-parent')
|
||||
is to search a buffer found with TAG, and if externally defined,
|
||||
search locally, then semanticdb for that tag (when enabled.)")
|
||||
|
||||
(defun semantic-tag-calculate-parent-default (tag)
|
||||
"Attempt to calculate the parent of TAG."
|
||||
(when (semantic-tag-in-buffer-p tag)
|
||||
(save-excursion
|
||||
(set-buffer (semantic-tag-buffer tag))
|
||||
(save-excursion
|
||||
(goto-char (semantic-tag-start tag))
|
||||
(semantic-current-tag-parent))
|
||||
)))
|
||||
|
||||
(define-overloadable-function semantic-tag-protection (tag &optional parent)
|
||||
"Return protection information about TAG with optional PARENT.
|
||||
This function returns on of the following symbols:
|
||||
nil - No special protection. Language dependent.
|
||||
'public - Anyone can access this TAG.
|
||||
'private - Only methods in the local scope can access TAG.
|
||||
'protected - Like private for outside scopes, like public for child
|
||||
classes.
|
||||
Some languages may choose to provide additional return symbols specific
|
||||
to themselves. Use of this function should allow for this.
|
||||
|
||||
The default behavior (if not overridden with `tag-protection'
|
||||
is to return a symbol based on type modifiers."
|
||||
(and (not parent)
|
||||
(semantic-tag-overlay tag)
|
||||
(semantic-tag-in-buffer-p tag)
|
||||
(setq parent (semantic-tag-calculate-parent tag)))
|
||||
(:override))
|
||||
|
||||
(make-obsolete-overload 'semantic-nonterminal-protection
|
||||
'semantic-tag-protection)
|
||||
|
||||
(defun semantic-tag-protection-default (tag &optional parent)
|
||||
"Return the protection of TAG as a child of PARENT default action.
|
||||
See `semantic-tag-protection'."
|
||||
(let ((mods (semantic-tag-modifiers tag))
|
||||
(prot nil))
|
||||
(while (and (not prot) mods)
|
||||
(if (stringp (car mods))
|
||||
(let ((s (car mods)))
|
||||
(setq prot
|
||||
;; A few silly defaults to get things started.
|
||||
(cond ((or (string= s "public")
|
||||
(string= s "extern")
|
||||
(string= s "export"))
|
||||
'public)
|
||||
((string= s "private")
|
||||
'private)
|
||||
((string= s "protected")
|
||||
'protected)))))
|
||||
(setq mods (cdr mods)))
|
||||
prot))
|
||||
|
||||
(defun semantic-tag-protected-p (tag protection &optional parent)
|
||||
"Non-nil if TAG is is protected.
|
||||
PROTECTION is a symbol which can be returned by the method
|
||||
`semantic-tag-protection'.
|
||||
PARENT is the parent data type which contains TAG.
|
||||
|
||||
For these PROTECTIONs, true is returned if TAG is:
|
||||
@table @asis
|
||||
@item nil
|
||||
Always true
|
||||
@item private
|
||||
True if nil.
|
||||
@item protected
|
||||
True if private or nil.
|
||||
@item public
|
||||
True if private, protected, or nil.
|
||||
@end table"
|
||||
(if (null protection)
|
||||
t
|
||||
(let ((tagpro (semantic-tag-protection tag parent)))
|
||||
(or (and (eq protection 'private)
|
||||
(null tagpro))
|
||||
(and (eq protection 'protected)
|
||||
(or (null tagpro)
|
||||
(eq tagpro 'private)))
|
||||
(and (eq protection 'public)
|
||||
(not (eq tagpro 'public)))))
|
||||
))
|
||||
|
||||
(define-overloadable-function semantic-tag-abstract-p (tag &optional parent)
|
||||
"Return non nil if TAG is abstract.
|
||||
Optional PARENT is the parent tag of TAG.
|
||||
In UML, abstract methods and classes have special meaning and behavior
|
||||
in how methods are overridden. In UML, abstract methods are italicized.
|
||||
|
||||
The default behavior (if not overridden with `tag-abstract-p'
|
||||
is to return true if `abstract' is in the type modifiers.")
|
||||
|
||||
(make-obsolete-overload 'semantic-nonterminal-abstract
|
||||
'semantic-tag-abstract-p)
|
||||
|
||||
(defun semantic-tag-abstract-p-default (tag &optional parent)
|
||||
"Return non-nil if TAG is abstract as a child of PARENT default action.
|
||||
See `semantic-tag-abstract-p'."
|
||||
(let ((mods (semantic-tag-modifiers tag))
|
||||
(abs nil))
|
||||
(while (and (not abs) mods)
|
||||
(if (stringp (car mods))
|
||||
(setq abs (or (string= (car mods) "abstract")
|
||||
(string= (car mods) "virtual"))))
|
||||
(setq mods (cdr mods)))
|
||||
abs))
|
||||
|
||||
(define-overloadable-function semantic-tag-leaf-p (tag &optional parent)
|
||||
"Return non nil if TAG is leaf.
|
||||
Optional PARENT is the parent tag of TAG.
|
||||
In UML, leaf methods and classes have special meaning and behavior.
|
||||
|
||||
The default behavior (if not overridden with `tag-leaf-p'
|
||||
is to return true if `leaf' is in the type modifiers.")
|
||||
|
||||
(make-obsolete-overload 'semantic-nonterminal-leaf
|
||||
'semantic-tag-leaf-p)
|
||||
|
||||
(defun semantic-tag-leaf-p-default (tag &optional parent)
|
||||
"Return non-nil if TAG is leaf as a child of PARENT default action.
|
||||
See `semantic-tag-leaf-p'."
|
||||
(let ((mods (semantic-tag-modifiers tag))
|
||||
(leaf nil))
|
||||
(while (and (not leaf) mods)
|
||||
(if (stringp (car mods))
|
||||
;; Use java FINAL as example default. There is none
|
||||
;; for C/C++
|
||||
(setq leaf (string= (car mods) "final")))
|
||||
(setq mods (cdr mods)))
|
||||
leaf))
|
||||
|
||||
(define-overloadable-function semantic-tag-static-p (tag &optional parent)
|
||||
"Return non nil if TAG is static.
|
||||
Optional PARENT is the parent tag of TAG.
|
||||
In UML, static methods and attributes mean that they are allocated
|
||||
in the parent class, and are not instance specific.
|
||||
UML notation specifies that STATIC entries are underlined.")
|
||||
|
||||
(defun semantic-tag-static-p-default (tag &optional parent)
|
||||
"Return non-nil if TAG is static as a child of PARENT default action.
|
||||
See `semantic-tag-static-p'."
|
||||
(let ((mods (semantic-tag-modifiers tag))
|
||||
(static nil))
|
||||
(while (and (not static) mods)
|
||||
(if (stringp (car mods))
|
||||
(setq static (string= (car mods) "static")))
|
||||
(setq mods (cdr mods)))
|
||||
static))
|
||||
|
||||
(define-overloadable-function semantic-tag-prototype-p (tag)
|
||||
"Return non nil if TAG is a prototype.
|
||||
For some laguages, such as C, a prototype is a declaration of
|
||||
something without an implementation."
|
||||
)
|
||||
|
||||
(defun semantic-tag-prototype-p-default (tag)
|
||||
"Non-nil if TAG is a prototype."
|
||||
(let ((p (semantic-tag-get-attribute tag :prototype-flag)))
|
||||
(cond
|
||||
;; Trust the parser author.
|
||||
(p p)
|
||||
;; Empty types might be a prototype.
|
||||
;; @todo - make this better.
|
||||
((eq (semantic-tag-class tag) 'type)
|
||||
(not (semantic-tag-type-members tag)))
|
||||
;; No other heuristics.
|
||||
(t nil))
|
||||
))
|
||||
|
||||
;;; FULL NAMES
|
||||
;;
|
||||
;; For programmer convenience, a full name is not specified in source
|
||||
;; code. Instead some abbreviation is made, and the local environment
|
||||
;; will contain the info needed to determine the full name.
|
||||
|
||||
(define-overloadable-function semantic-tag-full-name (tag &optional stream-or-buffer)
|
||||
"Return the fully qualified name of TAG in the package hierarchy.
|
||||
STREAM-OR-BUFFER can be anything convertable by `semantic-something-to-stream',
|
||||
but must be a toplevel semantic tag stream that contains TAG.
|
||||
A Package Hierarchy is defined in UML by the way classes and methods
|
||||
are organized on disk. Some language use this concept such that a
|
||||
class can be accessed via it's fully qualified name, (such as Java.)
|
||||
Other languages qualify names within a Namespace (such as C++) which
|
||||
result in a different package like structure. Languages which do not
|
||||
override this function with `tag-full-name' will use
|
||||
`semantic-tag-name'. Override functions only need to handle
|
||||
STREAM-OR-BUFFER with a tag stream value, or nil."
|
||||
(let ((stream (semantic-something-to-tag-table
|
||||
(or stream-or-buffer tag))))
|
||||
(:override-with-args (tag stream))))
|
||||
|
||||
(make-obsolete-overload 'semantic-nonterminal-full-name
|
||||
'semantic-tag-full-name)
|
||||
|
||||
(defun semantic-tag-full-name-default (tag stream)
|
||||
"Default method for `semantic-tag-full-name'.
|
||||
Return the name of TAG found in the toplevel STREAM."
|
||||
(semantic-tag-name tag))
|
||||
|
||||
;;; Compatibility aliases.
|
||||
;;
|
||||
(semantic-alias-obsolete 'semantic-nonterminal-protection
|
||||
'semantic-tag-protection)
|
||||
(semantic-alias-obsolete 'semantic-nonterminal-protection-default
|
||||
'semantic-tag-protection-default)
|
||||
(semantic-alias-obsolete 'semantic-nonterminal-abstract
|
||||
'semantic-tag-abstract-p)
|
||||
(semantic-alias-obsolete 'semantic-nonterminal-abstract-default
|
||||
'semantic-tag-abstract-p-default)
|
||||
(semantic-alias-obsolete 'semantic-nonterminal-leaf
|
||||
'semantic-tag-leaf-p)
|
||||
(semantic-alias-obsolete 'semantic-nonterminal-leaf-default
|
||||
'semantic-tag-leaf-p-default)
|
||||
(semantic-alias-obsolete 'semantic-nonterminal-static-default
|
||||
'semantic-tag-static-p-default)
|
||||
(semantic-alias-obsolete 'semantic-nonterminal-full-name
|
||||
'semantic-tag-full-name)
|
||||
(semantic-alias-obsolete 'semantic-nonterminal-full-name-default
|
||||
'semantic-tag-full-name-default)
|
||||
|
||||
;; TEMPORARY within betas of CEDET 1.0
|
||||
(semantic-alias-obsolete 'semantic-tag-static 'semantic-tag-static-p)
|
||||
(semantic-alias-obsolete 'semantic-tag-leaf 'semantic-tag-leaf-p)
|
||||
(semantic-alias-obsolete 'semantic-tag-abstract 'semantic-tag-abstract-p)
|
||||
|
||||
|
||||
(provide 'semantic/tag-ls)
|
||||
|
||||
;;; semantic-tag-ls.el ends here
|
||||
Loading…
Add table
Add a link
Reference in a new issue