semantic/cedet/db-global.el, semantic/cedet/ia-sb.el,
authorChong Yidong <cyd@stupidchicken.com>
Sun, 30 Aug 2009 14:36:00 +0000 (14:36 +0000)
committerChong Yidong <cyd@stupidchicken.com>
Sun, 30 Aug 2009 14:36:00 +0000 (14:36 +0000)
semantic/cedet/sb.el, semantic/cedet/scope.el: New files.

lisp/cedet/semantic/db-global.el [new file with mode: 0644]
lisp/cedet/semantic/ia-sb.el [new file with mode: 0644]
lisp/cedet/semantic/sb.el [new file with mode: 0644]
lisp/cedet/semantic/scope.el [new file with mode: 0644]

diff --git a/lisp/cedet/semantic/db-global.el b/lisp/cedet/semantic/db-global.el
new file mode 100644 (file)
index 0000000..1677f57
--- /dev/null
@@ -0,0 +1,248 @@
+;;; semantic/db-global.el --- Semantic database extensions for GLOBAL
+
+;;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 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:
+;;
+;; Use GNU Global for by-name database searches.
+;;
+;; This will work as an "omniscient" database for a given project.
+;;
+
+(require 'cedet-global)
+(require 'semantic/db-search)
+(require 'semantic/symref/global)
+
+(eval-when-compile
+  ;; For generic function searching.
+  (require 'eieio)
+  (require 'eieio-opt)
+  )
+;;; Code:
+(defun semanticdb-enable-gnu-global-databases (mode)
+  "Enable the use of the GNU Global SemanticDB back end for all files of MODE.
+This will add an instance of a GNU Global database to each buffer
+in a GNU Global supported hierarchy."
+  (interactive
+   (list (completing-read
+          "Emable in Mode: " obarray
+          #'(lambda (s) (get s 'mode-local-symbol-table))
+          t (symbol-name major-mode))))
+
+  ;; First, make sure the version is ok.
+  (cedet-gnu-global-version-check)
+
+  ;; Make sure mode is a symbol.
+  (when (stringp mode)
+    (setq mode (intern mode)))
+
+  (let ((ih (mode-local-value mode 'semantic-init-mode-hooks)))
+    (eval `(setq-mode-local
+           ,mode semantic-init-mode-hooks
+           (cons 'semanticdb-enable-gnu-global-hook ih))))
+
+  )
+
+(defun semanticdb-enable-gnu-global-hook ()
+  "Add support for GNU Global in the current buffer via semantic-init-hook.
+MODE is the major mode to support."
+  (semanticdb-enable-gnu-global-in-buffer t))
+
+(defun semanticdb-enable-gnu-global-in-buffer (&optional dont-err-if-not-available)
+  "Enable a GNU Global database in the current buffer.
+Argument DONT-ERR-IF-NOT-AVAILABLE will throw an error if GNU Global
+is not available for this directory."
+  (interactive "P")
+  (if (cedet-gnu-global-root)
+      (setq
+       ;; Add to the system database list.
+       semanticdb-project-system-databases
+       (cons (semanticdb-project-database-global "global")
+            semanticdb-project-system-databases)
+       ;; Apply the throttle.
+       semanticdb-find-default-throttle
+       (append semanticdb-find-default-throttle
+              '(omniscience))
+       )
+    (if dont-err-if-not-available
+       (message "No Global support in %s" default-directory)
+      (error "No Global support in %s" default-directory))
+    ))
+
+;;; Classes:
+(defclass semanticdb-table-global (semanticdb-search-results-table)
+  ((major-mode :initform nil)
+   )
+  "A table for returning search results from GNU Global.")
+
+(defclass semanticdb-project-database-global
+  ;; @todo - convert to one DB per directory.
+  (semanticdb-project-database eieio-instance-tracker)
+  ()
+  "Database representing a GNU Global tags file.")
+
+(defmethod semanticdb-equivalent-mode ((table semanticdb-table-global) &optional buffer)
+  "Return t, pretend that this table's mode is equivalent to BUFFER.
+Equivalent modes are specified by by `semantic-equivalent-major-modes'
+local variable."
+  ;; @todo - hack alert!
+  t)
+
+;;; Filename based methods
+;;
+(defmethod semanticdb-get-database-tables ((obj semanticdb-project-database-global))
+  "For a global database, there are no explicit tables.
+For each file hit, get the traditional semantic table from that file."
+  ;; 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-global "GNU Global Search 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-global) filename)
+  "From OBJ, return FILENAME's associated table object."
+  ;; We pass in "don't load".  I wonder if we need to avoid that or not?
+  (car (semanticdb-get-database-tables obj))
+  )
+
+;;; Search Overrides
+;;
+;; Only NAME based searches work with GLOBAL as that is all it tracks.
+;;
+(defmethod semanticdb-find-tags-by-name-method
+  ((table semanticdb-table-global) 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)
+    ;; Call out to GNU Global for some results.
+    (let* ((semantic-symref-tool 'global)
+          (result (semantic-symref-find-tags-by-name name 'project))
+          )
+      (when result
+       ;; We could ask to keep the buffer open, but that annoys
+       ;; people.
+       (semantic-symref-result-get-tags result))
+      )))
+
+(defmethod semanticdb-find-tags-by-name-regexp-method
+  ((table semanticdb-table-global) 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
+    (let* ((semantic-symref-tool 'global)
+          (result (semantic-symref-find-tags-by-regexp regex 'project))
+          )
+      (when result
+       (semantic-symref-result-get-tags result))
+      )))
+
+(defmethod semanticdb-find-tags-for-completion-method
+  ((table semanticdb-table-global) 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)
+    (let* ((semantic-symref-tool 'global)
+          (result (semantic-symref-find-tags-by-completion prefix 'project))
+          (faketags nil)
+          )
+      (when result
+       (dolist (T (oref result :hit-text))
+         ;; We should look up each tag one at a time, but I'm lazy!
+         ;; Doing this may be good enough.
+         (setq faketags (cons
+                         (semantic-tag T 'function :faux t)
+                         faketags))
+         )
+       faketags))))
+
+;;; 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-global) 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 global."
+  (semanticdb-find-tags-by-name-method table name tags))
+
+(defmethod semanticdb-deep-find-tags-by-name-regexp-method
+  ((table semanticdb-table-global) 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 global."
+  (semanticdb-find-tags-by-name-regexp-method table regex tags))
+
+(defmethod semanticdb-deep-find-tags-for-completion-method
+  ((table semanticdb-table-global) 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 global."
+  (semanticdb-find-tags-for-completion-method table prefix tags))
+
+;;; TEST
+;;
+;; Here is a testing fcn to try out searches via the GNU Global database.
+(defvar semanticdb-test-gnu-global-startfile "~/src/global-5.7.3/global/global.c"
+  "File to use for testing.")
+
+(defun semanticdb-test-gnu-global (searchfor &optional standardfile)
+  "Test the GNU Global semanticdb.
+Argument SEARCHFOR is the text to search for.
+If optional arg STANDARDFILE is non nil, use a standard file w/ global enabled."
+  (interactive "sSearch For Tag: \nP")
+
+  (require 'data-debug)
+  (save-excursion
+    (when standardfile
+      (set-buffer (find-file-noselect semanticdb-test-gnu-global-startfile)))
+
+    (condition-case err
+       (semanticdb-enable-gnu-global-in-buffer)
+      (error (if standardfile
+                (error err)
+              (set-buffer (find-file-noselect semanticdb-test-gnu-global-startfile))
+              (semanticdb-enable-gnu-global-in-buffer))))
+
+    (let* ((db (semanticdb-project-database-global "global"))
+          (tab (semanticdb-file-table db (buffer-file-name)))
+          (result (semanticdb-deep-find-tags-for-completion-method tab searchfor))
+          )
+      (data-debug-new-buffer "*SemanticDB Gnu Global Result*")
+      (data-debug-insert-thing result "?" "")
+      )))
+
+(provide 'semantic/db-global)
+
+;;; semantic/db-global.el ends here
diff --git a/lisp/cedet/semantic/ia-sb.el b/lisp/cedet/semantic/ia-sb.el
new file mode 100644 (file)
index 0000000..97f5318
--- /dev/null
@@ -0,0 +1,367 @@
+;;; semantic/ia-sb.el --- Speedbar analysis display interactor
+
+;;; Copyright (C) 2002, 2003, 2004, 2006, 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:
+;;
+;; Speedbar node for displaying derived context information.
+;;
+
+(require 'semantic/analyze)
+(require 'speedbar)
+
+;;; Code:
+(defvar semantic-ia-sb-key-map nil
+  "Keymap used when in semantic analysis display mode.")
+
+(if semantic-ia-sb-key-map
+    nil
+  (setq semantic-ia-sb-key-map (speedbar-make-specialized-keymap))
+
+  ;; Basic featuers.
+  (define-key semantic-ia-sb-key-map "\C-m" 'speedbar-edit-line)
+  (define-key semantic-ia-sb-key-map "I" 'semantic-ia-sb-show-tag-info)
+  )
+
+(defvar semantic-ia-sb-easymenu-definition
+  '( "---"
+;     [ "Expand" speedbar-expand-line nil ]
+;     [ "Contract" speedbar-contract-line nil ]
+     [ "Tag Information" semantic-ia-sb-show-tag-info t ]
+     [ "Jump to Tag" speedbar-edit-line t ]
+     [ "Complete" speedbar-edit-line t ]
+     )
+  "Extra menu items Analysis mode.")
+
+;; Make sure our special speedbar major mode is loaded
+(speedbar-add-expansion-list '("Analyze"
+                              semantic-ia-sb-easymenu-definition
+                              semantic-ia-sb-key-map
+                              semantic-ia-speedbar))
+
+(speedbar-add-mode-functions-list
+ (list "Analyze"
+       ;;'(speedbar-item-info . eieio-speedbar-item-info)
+       '(speedbar-line-directory . semantic-ia-sb-line-path)))
+
+(defun semantic-speedbar-analysis ()
+  "Start Speedbar in semantic analysis mode.
+The analyzer displays information about the current context, plus a smart
+list of possible completions."
+  (interactive)
+  ;; Make sure that speedbar is active
+  (speedbar-frame-mode 1)
+  ;; Now, throw us into Analyze  mode on speedbar.
+  (speedbar-change-initial-expansion-list "Analyze")
+  )
+
+(defun semantic-ia-speedbar (directory zero)
+  "Create buttons in speedbar which define the current analysis at POINT.
+DIRECTORY is the current directory, which is ignored, and ZERO is 0."
+  (let ((analysis nil)
+       (scope nil)
+       (buffer nil)
+       (completions nil)
+       (cf (selected-frame))
+       (cnt nil)
+       (mode-local-active-mode nil)
+       )
+    ;; Try and get some sort of analysis
+    (condition-case nil
+       (progn
+         (speedbar-select-attached-frame)
+         (setq buffer (current-buffer))
+         (setq mode-local-active-mode major-mode)
+         (save-excursion
+           ;; Get the current scope
+           (setq scope (semantic-calculate-scope (point)))
+           ;; Get the analysis
+           (setq analysis (semantic-analyze-current-context (point)))
+           (setq cnt (semantic-find-tag-by-overlay))
+           (when analysis
+             (setq completions (semantic-analyze-possible-completions analysis))
+             )
+           ))
+      (error nil))
+    (select-frame cf)
+    (save-excursion
+      (set-buffer speedbar-buffer)
+      ;; If we have something, do something spiff with it.
+      (erase-buffer)
+      (speedbar-insert-separator "Buffer/Function")
+      ;; Note to self: Turn this into an expandable file name.
+      (speedbar-make-tag-line 'bracket ?  nil nil
+                             (buffer-name buffer)
+                             nil nil 'speedbar-file-face 0)
+
+      (when cnt
+       (semantic-ia-sb-string-list cnt
+                                   'speedbar-tag-face
+                                   'semantic-sb-token-jump))
+      (when analysis
+       ;; If this analyzer happens to point at a complete symbol, then
+       ;; see if we can dig up some documentation for it.
+       (semantic-ia-sb-show-doc analysis))
+
+      (when analysis
+       ;; Let different classes draw more buttons.
+       (semantic-ia-sb-more-buttons analysis)
+       (when completions
+         (speedbar-insert-separator "Completions")
+         (semantic-ia-sb-completion-list completions
+                                         'speedbar-tag-face
+                                         'semantic-ia-sb-complete))
+       )
+
+      ;; Show local variables
+      (when scope
+       (semantic-ia-sb-show-scope scope))
+
+      )))
+
+(defmethod semantic-ia-sb-show-doc ((context semantic-analyze-context))
+  "Show documentation about CONTEXT iff CONTEXT points at a complete symbol."
+  (let ((sym (car (reverse (oref context prefix))))
+       (doc nil))
+    (when (semantic-tag-p sym)
+      (setq doc (semantic-documentation-for-tag sym))
+      (when doc
+       (speedbar-insert-separator "Documentation")
+       (insert doc)
+       (insert "\n")
+       ))
+    ))
+
+(defun semantic-ia-sb-show-scope (scope)
+  "Show SCOPE information."
+  (let ((localvars (when scope
+                    (oref scope localvar)))
+       )
+    (when localvars
+      (speedbar-insert-separator "Local Variables")
+      (semantic-ia-sb-string-list localvars
+                                 'speedbar-tag-face
+                                 ;; This is from semantic-sb
+                                 'semantic-sb-token-jump))))
+
+(defmethod semantic-ia-sb-more-buttons ((context semantic-analyze-context))
+  "Show a set of speedbar buttons specific to CONTEXT."
+  (let ((prefix (oref context prefix)))
+    (when prefix
+      (speedbar-insert-separator "Prefix")
+      (semantic-ia-sb-string-list prefix
+                                 'speedbar-tag-face
+                                 'semantic-sb-token-jump))
+    ))
+
+(defmethod semantic-ia-sb-more-buttons ((context semantic-analyze-context-assignment))
+  "Show a set of speedbar buttons specific to CONTEXT."
+  (call-next-method)
+  (let ((assignee (oref context assignee)))
+    (when assignee
+      (speedbar-insert-separator "Assignee")
+      (semantic-ia-sb-string-list assignee
+                                 'speedbar-tag-face
+                                 'semantic-sb-token-jump))))
+
+(defmethod semantic-ia-sb-more-buttons ((context semantic-analyze-context-functionarg))
+  "Show a set of speedbar buttons specific to CONTEXT."
+  (call-next-method)
+  (let ((func (oref context function)))
+    (when func
+      (speedbar-insert-separator "Function")
+      (semantic-ia-sb-string-list func
+                                 'speedbar-tag-face
+                                 'semantic-sb-token-jump)
+      ;; An index for the argument the prefix is in:
+      (let ((arg (oref context argument))
+           (args (semantic-tag-function-arguments (car func)))
+           (idx 0)
+           )
+       (speedbar-insert-separator
+        (format "Argument #%d" (oref context index)))
+       (if args
+           (semantic-ia-sb-string-list args
+                                       'speedbar-tag-face
+                                       'semantic-sb-token-jump
+                                       (oref context index)
+                                       'speedbar-selected-face)
+         ;; Else, no args list, so use what the context had.
+         (semantic-ia-sb-string-list arg
+                                     'speedbar-tag-face
+                                     'semantic-sb-token-jump))
+       ))))
+
+(defun semantic-ia-sb-string-list (list face function &optional idx idxface)
+  "Create some speedbar buttons from LIST.
+Each button will use FACE, and be activated with FUNCTION.
+Optional IDX is an index into LIST to apply IDXFACE instead."
+  (let ((count 1))
+    (while list
+      (let* ((usefn nil)
+            (string (cond ((stringp (car list))
+                           (car list))
+                          ((semantic-tag-p (car list))
+                           (setq usefn (semantic-tag-with-position-p (car list)))
+                           (semantic-format-tag-uml-concise-prototype (car list)))
+                          (t "<No Tag>")))
+            (localface (if (or (not idx) (/= idx count))
+                           face
+                         idxface))
+            )
+       (if (semantic-tag-p (car list))
+           (speedbar-make-tag-line 'angle ?i
+                                   'semantic-ia-sb-tag-info (car list)
+                                   string (if usefn function) (car list) localface
+                                   0)
+         (speedbar-make-tag-line 'statictag ??
+                                 nil nil
+                                 string (if usefn function) (car list) localface
+                                 0))
+       (setq list (cdr list)
+             count (1+ count)))
+      )))
+
+(defun semantic-ia-sb-completion-list (list face function)
+  "Create some speedbar buttons from LIST.
+Each button will use FACE, and be activated with FUNCTION."
+  (while list
+    (let* ((documentable nil)
+          (string (cond ((stringp (car list))
+                         (car list))
+                        ((semantic-tag-p (car list))
+                         (setq documentable t)
+                         (semantic-format-tag-uml-concise-prototype (car list)))
+                       (t "foo"))))
+      (if documentable
+         (speedbar-make-tag-line 'angle ?i
+                                 'semantic-ia-sb-tag-info
+                                 (car list)
+                                 string function (car list) face
+                                 0)
+       (speedbar-make-tag-line 'statictag ?  nil nil
+                               string function (car list) face
+                               0))
+      (setq list (cdr list)))))
+
+(defun semantic-ia-sb-show-tag-info ()
+  "Display information about the tag on the current line.
+Same as clicking on the <i> button.
+See `semantic-ia-sb-tag-info' for more."
+  (interactive)
+  (let ((tok nil))
+    (save-excursion
+      (end-of-line)
+      (forward-char -1)
+      (setq tok (get-text-property (point) 'speedbar-token)))
+    (semantic-ia-sb-tag-info nil tok 0)))
+
+(defun semantic-ia-sb-tag-info (text tag indent)
+  "Display as much information as we can about tag.
+Show the information in a shrunk split-buffer and expand
+out as many details as possible.
+TEXT, TAG, and INDENT are speedbar function arguments."
+  (when (semantic-tag-p tag)
+    (unwind-protect
+       (let ((ob nil))
+         (speedbar-select-attached-frame)
+         (setq ob (current-buffer))
+         (with-output-to-temp-buffer "*Tag Information*"
+           ;; Output something about this tag:
+           (save-excursion
+             (set-buffer "*Tag Information*")
+             (goto-char (point-max))
+             (insert
+              (semantic-format-tag-prototype tag nil t)
+              "\n")
+             (let ((typetok
+                    (condition-case nil
+                        (save-excursion
+                          (set-buffer ob)
+                          ;; @todo - We need a context to derive a scope from.
+                          (semantic-analyze-tag-type tag nil))
+                      (error nil))))
+               (if typetok
+                   (insert (semantic-format-tag-prototype
+                            typetok nil t))
+                 ;; No type found by the analyzer
+                 ;; The below used to try and select the buffer from the last
+                 ;; analysis, but since we are already in the correct buffer, I
+                 ;; don't think that is needed.
+                 (let ((type (semantic-tag-type tag)))
+                   (cond ((semantic-tag-p type)
+                          (setq type (semantic-tag-name type)))
+                         ((listp type)
+                          (setq type (car type))))
+                   (if (semantic-lex-keyword-p type)
+                       (setq typetok
+                             (semantic-lex-keyword-get type 'summary))))
+                 (if typetok
+                     (insert typetok))
+                 ))
+             ))
+         ;; Make it small
+         (shrink-window-if-larger-than-buffer
+          (get-buffer-window "*Tag Information*")))
+      (select-frame speedbar-frame))))
+
+(defun semantic-ia-sb-line-path (&optional depth)
+  "Return the file name associated with DEPTH."
+  (save-match-data
+    (let* ((tok (speedbar-line-token))
+          (buff (if (semantic-tag-buffer tok)
+                    (semantic-tag-buffer tok)
+                  (current-buffer))))
+      (buffer-file-name buff))))
+
+(defun semantic-ia-sb-complete (text tag indent)
+  "At point in the attached buffer, complete the symbol clicked on.
+TEXT TAG and INDENT are the details."
+  ;; Find the specified bounds from the current analysis.
+  (speedbar-select-attached-frame)
+  (unwind-protect
+      (let* ((a (semantic-analyze-current-context (point)))
+            (bounds (oref a bounds))
+            (movepoint nil)
+            )
+       (save-excursion
+         (if (and (<= (point) (cdr bounds)) (>= (point) (car bounds)))
+             (setq movepoint t))
+         (goto-char (car bounds))
+         (delete-region (car bounds) (cdr bounds))
+         (insert (semantic-tag-name tag))
+         (if movepoint (setq movepoint (point)))
+         ;; I'd like to use this to add fancy () or what not at the end
+         ;; but we need the parent file whih requires an upgrade to the
+         ;; analysis tool.
+         ;;(semantic-insert-foreign-tag tag ??))
+         )
+       (if movepoint
+           (let ((cf (selected-frame)))
+             (speedbar-select-attached-frame)
+             (goto-char movepoint)
+             (select-frame cf))))
+    (select-frame speedbar-frame)))
+
+(provide 'semantic/ia-sb)
+
+;;; semantic/ia-sb.el ends here
diff --git a/lisp/cedet/semantic/sb.el b/lisp/cedet/semantic/sb.el
new file mode 100644 (file)
index 0000000..f1a6beb
--- /dev/null
@@ -0,0 +1,419 @@
+;;; semantic/sb.el --- Semantic tag display for speedbar
+
+;;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+;;; 2007, 2008 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:
+;;
+;; Convert a tag table into speedbar buttons.
+
+;;; TODO:
+
+;; Use semanticdb to find which semanticdb-table is being used for each
+;; file/tag.  Replace `semantic-sb-with-tag-buffer' to instead call
+;; children with the new `with-mode-local' instead.
+
+(require 'semantic)
+(require 'semantic/util)
+(require 'speedbar)
+;; (require 'inversion)
+;; (eval-and-compile
+;;   (inversion-require 'speedbar "0.15beta1"))
+
+(defcustom semantic-sb-autoexpand-length 1
+  "*Length of a semantic bucket to autoexpand in place.
+This will replace the named bucket that would have usually occured here."
+  :group 'speedbar
+  :type 'integer)
+
+(defcustom semantic-sb-button-format-tag-function 'semantic-format-tag-abbreviate
+  "*Function called to create the text for a but from a token."
+  :group 'speedbar
+  :type semantic-format-tag-custom-list)
+
+(defcustom semantic-sb-info-format-tag-function 'semantic-format-tag-summarize
+  "*Function called to create the text for info display from a token."
+  :group 'speedbar
+  :type semantic-format-tag-custom-list)
+
+;;; Code:
+;;
+
+;;; Buffer setting for correct mode manipulation.
+(defun semantic-sb-tag-set-buffer (tag)
+  "Set the current buffer to something associated with TAG.
+use the `speedbar-line-file' to get this info if needed."
+  (if (semantic-tag-buffer tag)
+      (set-buffer (semantic-tag-buffer tag))
+    (let ((f (speedbar-line-file)))
+      (set-buffer (find-file-noselect f)))))
+
+(defmacro semantic-sb-with-tag-buffer (tag &rest forms)
+  "Set the current buffer to the origin of TAG and execute FORMS.
+Restore the old current buffer when completed."
+  `(save-excursion
+     (semantic-sb-tag-set-buffer ,tag)
+     ,@forms))
+(put 'semantic-sb-with-tag-buffer 'lisp-indent-function 1)
+
+;;; Button Generation
+;;
+;;  Here are some button groups:
+;;
+;;  +> Function ()
+;;     @ return_type
+;;    +( arg1
+;;    +| arg2
+;;    +) arg3
+;;
+;;  +> Variable[1] =
+;;    @ type
+;;    = default value
+;;
+;;  +> keywrd Type
+;;   +> type part
+;;
+;;  +>  -> click to see additional information
+
+(define-overloadable-function semantic-sb-tag-children-to-expand (tag)
+  "For TAG, return a list of children that TAG expands to.
+If this returns a value, then a +> icon is created.
+If it returns nil, then a => icon is created.")
+
+(defun semantic-sb-tag-children-to-expand-default (tag)
+  "For TAG, the children for type, variable, and function classes."
+  (semantic-sb-with-tag-buffer tag
+    (semantic-tag-components tag)))
+
+(defun semantic-sb-one-button (tag depth &optional prefix)
+  "Insert TAG as a speedbar button at DEPTH.
+Optional PREFIX is used to specify special marker characters."
+  (let* ((class (semantic-tag-class tag))
+        (edata (semantic-sb-tag-children-to-expand tag))
+        (type (semantic-tag-type tag))
+        (abbrev (semantic-sb-with-tag-buffer tag
+                  (funcall semantic-sb-button-format-tag-function tag)))
+        (start (point))
+        (end (progn
+               (insert (int-to-string depth) ":")
+               (point))))
+    (insert-char ?  (1- depth) nil)
+    (put-text-property end (point) 'invisible nil)
+    ;; take care of edata = (nil) -- a yucky but hard to clean case
+    (if (and edata (listp edata) (and (<= (length edata) 1) (not (car edata))))
+       (setq edata nil))
+    (if (and (not edata)
+            (member class '(variable function))
+            type)
+       (setq edata t))
+    ;; types are a bit unique.  Variable types can have special meaning.
+    (if edata
+       (speedbar-insert-button (if prefix (concat " +" prefix) " +>")
+                               'speedbar-button-face
+                               'speedbar-highlight-face
+                               'semantic-sb-show-extra
+                               tag t)
+      (speedbar-insert-button (if prefix (concat "  " prefix) " =>")
+                             nil nil nil nil t))
+    (speedbar-insert-button abbrev
+                           'speedbar-tag-face
+                           'speedbar-highlight-face
+                           'semantic-sb-token-jump
+                           tag t)
+    ;; This is very bizarre.  When this was just after the insertion
+    ;; of the depth: text, the : would get erased, but only for the
+    ;; auto-expanded short- buckets.  Move back for a later version
+    ;; version of Emacs 21 CVS
+    (put-text-property start end 'invisible t)
+    ))
+
+(defun semantic-sb-speedbar-data-line (depth button text &optional
+                                            text-fun text-data)
+  "Insert a semantic token data element.
+DEPTH is the current depth.  BUTTON is the text for the button.
+TEXT is the actual info with TEXT-FUN to occur when it happens.
+Argument TEXT-DATA is the token data to pass to TEXT-FUN."
+  (let ((start (point))
+       (end (progn
+              (insert (int-to-string depth) ":")
+              (point))))
+    (put-text-property start end 'invisible t)
+    (insert-char ?  depth nil)
+    (put-text-property end (point) 'invisible nil)
+    (speedbar-insert-button button nil nil nil nil t)
+    (speedbar-insert-button text
+                           'speedbar-tag-face
+                           (if text-fun 'speedbar-highlight-face)
+                           text-fun text-data t)
+    ))
+
+(defun semantic-sb-maybe-token-to-button (obj indent &optional
+                                             prefix modifiers)
+  "Convert OBJ, which was returned from the semantic parser, into a button.
+This OBJ might be a plain string (simple type or untyped variable)
+or a complete tag.
+Argument INDENT is the indentation used when making the button.
+Optional PREFIX is the character to use when marking the line.
+Optional MODIFIERS is additional text needed for variables."
+  (let ((myprefix (or prefix ">")))
+    (if (stringp obj)
+       (semantic-sb-speedbar-data-line indent myprefix obj)
+      (if (listp obj)
+         (progn
+           (if (and (stringp (car obj))
+                    (= (length obj) 1))
+               (semantic-sb-speedbar-data-line indent myprefix
+                                               (concat
+                                                (car obj)
+                                                (or modifiers "")))
+             (semantic-sb-one-button obj indent prefix)))))))
+
+(defun semantic-sb-insert-details (tag indent)
+  "Insert details about TAG at level INDENT."
+  (let ((tt (semantic-tag-class tag))
+       (type (semantic-tag-type tag)))
+    (cond ((eq tt 'type)
+          (let ((parts (semantic-tag-type-members tag))
+                (newparts nil))
+            ;; Lets expect PARTS to be a list of either strings,
+            ;; or variable tokens.
+            (when (semantic-tag-p (car parts))
+              ;; Bucketize into groups
+              (semantic-sb-with-tag-buffer (car parts)
+                (setq newparts (semantic-bucketize parts)))
+              (when (> (length newparts) semantic-sb-autoexpand-length)
+                ;; More than one bucket, insert inline
+                (semantic-sb-insert-tag-table (1- indent) newparts)
+                (setq parts nil))
+              ;; Dump the strings in.
+              (while parts
+                (semantic-sb-maybe-token-to-button (car parts) indent)
+                (setq parts (cdr parts))))))
+         ((eq tt 'variable)
+          (if type
+              (semantic-sb-maybe-token-to-button type indent "@"))
+          (let ((default (semantic-tag-variable-default tag)))
+            (if default
+                (semantic-sb-maybe-token-to-button default indent "=")))
+          )
+         ((eq tt 'function)
+          (if type
+              (semantic-sb-speedbar-data-line
+               indent "@"
+               (if (stringp type) type
+                 (semantic-tag-name type))))
+          ;; Arguments to the function
+          (let ((args (semantic-tag-function-arguments tag)))
+            (if (and args (car args))
+                (progn
+                  (semantic-sb-maybe-token-to-button (car args) indent "(")
+                  (setq args (cdr args))
+                  (while (> (length args) 1)
+                    (semantic-sb-maybe-token-to-button (car args)
+                                                       indent
+                                                       "|")
+                    (setq args (cdr args)))
+                  (if args
+                      (semantic-sb-maybe-token-to-button
+                       (car args) indent ")"))
+                  ))))
+         (t
+          (let ((components
+                 (save-excursion
+                   (when (and (semantic-tag-overlay tag)
+                              (semantic-tag-buffer tag))
+                     (set-buffer (semantic-tag-buffer tag)))
+                   (semantic-sb-tag-children-to-expand tag))))
+            ;; Well, it wasn't one of the many things we expect.
+            ;; Lets just insert them in with no decoration.
+            (while components
+              (semantic-sb-one-button (car components) indent)
+              (setq components (cdr components)))
+            ))
+         )
+    ))
+
+(defun semantic-sb-detail-parent ()
+  "Return the first parent token of the current line that includes a location."
+  (save-excursion
+    (beginning-of-line)
+    (let ((dep (if (looking-at "[0-9]+:")
+                  (1- (string-to-number (match-string 0)))
+                0)))
+      (re-search-backward (concat "^"
+                                 (int-to-string dep)
+                                 ":")
+                         nil t))
+    (beginning-of-line)
+    (if (looking-at "[0-9]+: +[-+][>()@|] \\([^\n]+\\)$")
+       (let ((prop nil))
+         (goto-char (match-beginning 1))
+         (setq prop (get-text-property (point) 'speedbar-token))
+         (if (semantic-tag-with-position-p prop)
+             prop
+           (semantic-sb-detail-parent)))
+      nil)))
+
+(defun semantic-sb-show-extra (text token indent)
+  "Display additional information about the token as an expansion.
+TEXT TOKEN and INDENT are the details."
+  (cond ((string-match "+" text)       ;we have to expand this file
+        (speedbar-change-expand-button-char ?-)
+        (speedbar-with-writable
+          (save-excursion
+            (end-of-line) (forward-char 1)
+            (save-restriction
+              (narrow-to-region (point) (point))
+              ;; Add in stuff specific to this type of token.
+              (semantic-sb-insert-details token (1+ indent))))))
+       ((string-match "-" text)        ;we have to contract this node
+        (speedbar-change-expand-button-char ?+)
+        (speedbar-delete-subblock indent))
+       (t (error "Ooops...  not sure what to do")))
+  (speedbar-center-buffer-smartly))
+
+(defun semantic-sb-token-jump (text token indent)
+  "Jump to the location specified in token.
+TEXT TOKEN and INDENT are the details."
+  (let ((file
+        (or
+         (cond ((fboundp 'speedbar-line-path)
+                (speedbar-line-directory indent))
+               ((fboundp 'speedbar-line-directory)
+                (speedbar-line-directory indent)))
+         ;; If speedbar cannot figure this out, extract the filename from
+         ;; the token.  True for Analysis mode.
+         (semantic-tag-file-name token)))
+       (parent (semantic-sb-detail-parent)))
+    (let ((f (selected-frame)))
+      (dframe-select-attached-frame speedbar-frame)
+      (run-hooks 'speedbar-before-visiting-tag-hook)
+      (select-frame f))
+    ;; Sometimes FILE may be nil here.  If you are debugging a problem
+    ;; when this happens, go back and figure out why FILE is nil and try
+    ;; and fix the source.
+    (speedbar-find-file-in-frame file)
+    (save-excursion (speedbar-stealthy-updates))
+    (semantic-go-to-tag token parent)
+    (switch-to-buffer (current-buffer))
+    ;; Reset the timer with a new timeout when cliking a file
+    ;; in case the user was navigating directories, we can cancel
+    ;; that other timer.
+    ;; (speedbar-set-timer dframe-update-speed)
+    ;;(recenter)
+    (speedbar-maybee-jump-to-attached-frame)
+    (run-hooks 'speedbar-visiting-tag-hook)))
+
+(defun semantic-sb-expand-group (text token indent)
+  "Expand a group which has semantic tokens.
+TEXT TOKEN and INDENT are the details."
+  (cond ((string-match "+" text)       ;we have to expand this file
+        (speedbar-change-expand-button-char ?-)
+        (speedbar-with-writable
+          (save-excursion
+            (end-of-line) (forward-char 1)
+            (save-restriction
+              (narrow-to-region (point-min) (point))
+              (semantic-sb-buttons-plain (1+ indent) token)))))
+       ((string-match "-" text)        ;we have to contract this node
+        (speedbar-change-expand-button-char ?+)
+        (speedbar-delete-subblock indent))
+       (t (error "Ooops...  not sure what to do")))
+  (speedbar-center-buffer-smartly))
+
+(defun semantic-sb-buttons-plain (level tokens)
+  "Create buttons at LEVEL using TOKENS."
+  (let ((sordid (speedbar-create-tag-hierarchy tokens)))
+    (while sordid
+      (cond ((null (car-safe sordid)) nil)
+           ((consp (car-safe (cdr-safe (car-safe sordid))))
+            ;; A group!
+            (speedbar-make-tag-line 'curly ?+ 'semantic-sb-expand-group
+                                    (cdr (car sordid))
+                                    (car (car sordid))
+                                    nil nil 'speedbar-tag-face
+                                    level))
+           (t ;; Assume that this is a token.
+            (semantic-sb-one-button (car sordid) level)))
+      (setq sordid (cdr sordid)))))
+
+(defun semantic-sb-insert-tag-table (level table)
+  "At LEVEL, insert the tag table TABLE.
+Use arcane knowledge about the semantic tokens in the tagged elements
+to create much wiser decisions about how to sort and group these items."
+  (semantic-sb-buttons level table))
+
+(defun semantic-sb-buttons (level lst)
+  "Create buttons at LEVEL using LST sorting into type buckets."
+  (save-restriction
+    (narrow-to-region (point-min) (point))
+    (let (tmp)
+      (while lst
+       (setq tmp (car lst))
+       (if (cdr tmp)
+           (if (<= (length (cdr tmp)) semantic-sb-autoexpand-length)
+               (semantic-sb-buttons-plain (1+ level) (cdr tmp))
+             (speedbar-make-tag-line 'curly ?+ 'semantic-sb-expand-group
+                                     (cdr tmp)
+                                     (car (car lst))
+                                     nil nil 'speedbar-tag-face
+                                     (1+ level))))
+       (setq lst (cdr lst))))))
+
+(defun semantic-sb-fetch-tag-table (file)
+  "Load FILE into a buffer, and generate tags using the Semantic parser.
+Returns the tag list, or t for an error."
+  (let ((out nil))
+    (if (and (featurep 'semanticdb) (semanticdb-minor-mode-p)
+            (not speedbar-power-click)
+            ;; If the database is loaded and running, try to get
+            ;; tokens from it.
+            (setq out (semanticdb-file-stream file)))
+       ;; Successful DB query.
+       nil
+      ;; No database, do it the old way.
+      (save-excursion
+       (set-buffer (find-file-noselect file))
+       (if (or (not (featurep 'semantic))
+               (not semantic--parse-table))
+           (setq out t)
+         (if speedbar-power-click (semantic-clear-toplevel-cache))
+         (setq out (semantic-fetch-tags)))))
+    (if (listp out)
+       (condition-case nil
+           (progn
+             ;; This brings externally defind methods into
+             ;; their classes, and creates meta classes for
+             ;; orphans.
+             (setq out (semantic-adopt-external-members out))
+             ;; Dump all the tokens into buckets.
+             (semantic-sb-with-tag-buffer (car out)
+               (semantic-bucketize out)))
+         (error t))
+      t)))
+
+;; Link ourselves into the tagging process.
+(add-to-list 'speedbar-dynamic-tags-function-list
+            '(semantic-sb-fetch-tag-table  . semantic-sb-insert-tag-table))
+
+(provide 'semantic/sb)
+
+;;; semantic/sb.el ends here
diff --git a/lisp/cedet/semantic/scope.el b/lisp/cedet/semantic/scope.el
new file mode 100644 (file)
index 0000000..c89bd79
--- /dev/null
@@ -0,0 +1,796 @@
+;;; semantic/scope.el --- Analyzer Scope Calculations
+
+;; 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:
+;;
+;; Calculate information about the current scope.
+;;
+;; Manages the current scope as a structure that can be cached on a
+;; per-file basis and recycled between different occurances of
+;; analysis on different parts of a file.
+;;
+;; Pattern for Scope Calculation
+;;
+;; Step 1: Calculate DataTypes in Scope:
+;;
+;; a) What is in scope via using statements or local namespaces
+;; b) Lineage of current context.  Some names drawn from step 1.
+;;
+;; Step 2: Convert type names into lists of concrete tags
+;;
+;; a) Convert each datatype into the real datatype tag
+;; b) Convert namespaces into the list of contents of the namespace.
+;; c) Merge all existing scopes together into one search list.
+;;
+;; Step 3: Local variables
+;;
+;; a) Local variables are in the master search list.
+;;
+
+(require 'semantic/db)
+(require 'semantic/analyze/fcn)
+(require 'semantic/ctxt)
+
+
+;;; Code:
+
+(defclass semantic-scope-cache (semanticdb-abstract-cache)
+  ((tag :initform nil
+       :documentation
+       "The tag this scope was calculated for.")
+   (scopetypes :initform nil
+              :documentation
+              "The list of types currently in scope.
+For C++, this would contain anonymous namespaces known, and
+anything labled by a `using' statement.")
+   (parents :initform nil
+           :documentation
+           "List of parents in scope w/in the body of this function.
+Presumably, the members of these parent classes are available for access
+based on private:, or public: style statements.")
+   (parentinheritance :initform nil
+                     :documentation "Alist of parents by inheritance.
+Each entry is ( PARENT . PROTECTION ), where PARENT is a type, and
+PROTECTION is a symbol representing the level of inheritance, such as 'private, or 'protected.")
+   (scope :initform nil
+         :documentation
+         "Items in scope due to the scopetypes or parents.")
+   (fullscope :initform nil
+             :documentation
+             "All the other stuff on one master list you can search.")
+   (localargs :initform nil
+             :documentation
+             "The arguments to the function tag.")
+   (localvar :initform nil
+            :documentation
+            "The local variables.")
+   (typescope :initform nil
+             :documentation
+             "Slot to save intermediate scope while metatypes are dereferenced.")
+   )
+  "Cache used for storage of the current scope by the Semantic Analyzer.
+Saves scoping information between runs of the analyzer.")
+
+;;; METHODS
+;;
+;; Methods for basic management of the structure in semanticdb.
+;;
+(defmethod semantic-reset ((obj semantic-scope-cache))
+  "Reset OBJ back to it's empty settings."
+  (oset obj tag nil)
+  (oset obj scopetypes nil)
+  (oset obj parents nil)
+  (oset obj parentinheritance nil)
+  (oset obj scope nil)
+  (oset obj fullscope nil)
+  (oset obj localargs nil)
+  (oset obj localvar nil)
+  (oset obj typescope nil)
+  )
+
+(defmethod semanticdb-synchronize ((cache semantic-scope-cache)
+                                  new-tags)
+  "Synchronize a CACHE with some NEW-TAGS."
+  (semantic-reset cache))
+
+
+(defmethod semanticdb-partial-synchronize ((cache semantic-scope-cache)
+                                          new-tags)
+  "Synchronize a CACHE with some changed NEW-TAGS."
+  ;; If there are any includes or datatypes changed, then clear.
+  (if (or (semantic-find-tags-by-class 'include new-tags)
+         (semantic-find-tags-by-class 'type new-tags)
+         (semantic-find-tags-by-class 'using new-tags))
+      (semantic-reset cache))
+  )
+
+(defun semantic-scope-reset-cache ()
+  "Get the current cached scope, and reset it."
+  (when semanticdb-current-table
+    (let ((co (semanticdb-cache-get semanticdb-current-table
+                                   semantic-scope-cache)))
+      (semantic-reset co))))
+
+(defmethod semantic-scope-set-typecache ((cache semantic-scope-cache)
+                                        types-in-scope)
+  "Set the :typescope property on CACHE to some types.
+TYPES-IN-SCOPE is a list of type tags whos members are
+currently in scope.  For each type in TYPES-IN-SCOPE,
+add those members to the types list.
+If nil, then the typescope is reset."
+  (let ((newts nil)) ;; New Type Scope
+    (dolist (onetype types-in-scope)
+      (setq newts (append (semantic-tag-type-members onetype)
+                         newts))
+      )
+    (oset cache typescope newts)))
+
+;;; TAG SCOPES
+;;
+;; These fcns should be used by search routines that return a single
+;; tag which, in turn, may have come from a deep scope.  The scope
+;; will be attached to the tag.  Thus, in future scope based calls, a
+;; tag can be passed in and a scope derived from it.
+
+(defun semantic-scope-tag-clone-with-scope (tag scopetags)
+  "Close TAG, and return it.  Add SCOPETAGS as a tag-local scope.
+Stores the SCOPETAGS as a set of tag properties on the cloned tag."
+  (let ((clone (semantic-tag-clone tag))
+       )
+    (semantic--tag-put-property clone 'scope scopetags)
+    ))
+
+(defun semantic-scope-tag-get-scope (tag)
+  "Get from TAG the list of tags comprising the scope from TAG."
+  (semantic--tag-get-property tag 'scope))
+
+;;; SCOPE UTILITIES
+;;
+;; Functions that do the main scope calculations
+
+
+(define-overloadable-function semantic-analyze-scoped-types (position)
+  "Return a list of types currently in scope at POSITION.
+This is based on what tags exist at POSITION, and any associated
+types available.")
+
+(defun semantic-analyze-scoped-types-default (position)
+  "Return a list of types currently in scope at POSITION.
+Use `semantic-ctxt-scoped-types' to find types."
+  (save-excursion
+    (goto-char position)
+    (let ((code-scoped-types nil))
+      ;; Lets ask if any types are currently scoped.  Scoped
+      ;; classes and types provide their public methods and types
+      ;; in source code, but are unrelated hierarchically.
+      (let ((sp (semantic-ctxt-scoped-types)))
+       (while sp
+         ;; Get this thing as a tag
+         (let ((tmp (cond
+                     ((stringp (car sp))
+                      (semanticdb-typecache-find (car sp)))
+                      ;(semantic-analyze-find-tag (car sp) 'type))
+                     ((semantic-tag-p (car sp))
+                      (if (semantic-analyze-tag-prototype-p (car sp))
+                          (semanticdb-typecache-find (semantic-tag-name (car sp)))
+                          ;;(semantic-analyze-find-tag (semantic-tag-name (car sp)) 'type)
+                        (car sp)))
+                     (t nil))))
+           (when tmp
+             (setq code-scoped-types
+                   (cons tmp code-scoped-types))))
+         (setq  sp (cdr sp))))
+      (setq code-scoped-types (nreverse code-scoped-types))
+
+      (when code-scoped-types
+       (semanticdb-typecache-merge-streams code-scoped-types nil))
+
+      )))
+
+;;------------------------------------------------------------
+(define-overloadable-function semantic-analyze-scope-nested-tags (position scopedtypes)
+  "Return a list of types in order of nesting for the context of POSITION.
+If POSITION is in a method with a named parent, find that parent, and
+identify it's scope via overlay instead.
+Optional SCOPETYPES are additional scoped entities in which our parent might
+be found.")
+
+(defun semantic-analyze-scope-nested-tags-default (position scopetypes)
+  "Return a list of types in order of nesting for the context of POSITION.
+If POSITION is in a method with a named parent, find that parent, and
+identify it's scope via overlay instead.
+Optional SCOPETYPES are additional scoped entities in which our parent might
+be found.
+This only finds ONE immediate parent by name.  All other parents returned
+are from nesting data types."
+  (save-excursion
+    (if position (goto-char position))
+    (let* ((stack (reverse (semantic-find-tag-by-overlay (point))))
+          (tag (car stack))
+          (pparent (car (cdr stack)))
+          (returnlist nil)
+          )
+      ;; In case of arg lists or some-such, throw out non-types.
+      (while (and stack (not (semantic-tag-of-class-p pparent 'type)))
+       (setq stack (cdr stack)
+                   pparent (car (cdr stack))))
+
+      ;; Step 1:
+      ;;    Analyze the stack of tags we are nested in as parents.
+      ;;
+
+      ;; If we have a pparent tag, lets go there
+      ;; an analyze that stack of tags.
+      (when (and pparent (semantic-tag-with-position-p pparent))
+       (semantic-go-to-tag pparent)
+       (setq stack (semantic-find-tag-by-overlay (point)))
+       ;; Step one, find the merged version of stack in the typecache.
+       (let* ((stacknames (reverse (mapcar 'semantic-tag-name stack)))
+              (tc nil)
+              )
+         ;; @todo - can we use the typecache ability to
+         ;;         put a scope into a tag to do this?
+         (while (and stacknames
+                     (setq tc (semanticdb-typecache-find
+                               (reverse stacknames))))
+           (setq returnlist (cons tc returnlist)
+                 stacknames (cdr stacknames)))
+         (when (not returnlist)
+           ;; When there was nothing from the typecache, then just
+           ;; use what's right here.
+           (setq stack (reverse stack))
+           ;; Add things to STACK until we cease finding tags of class type.
+           (while (and stack (eq (semantic-tag-class (car stack)) 'type))
+             ;; Otherwise, just add this to the returnlist.
+             (setq returnlist (cons (car stack) returnlist))
+             (setq stack (cdr stack)))
+
+           (setq returnlist (nreverse returnlist))
+           ))
+       )
+
+      ;; Only do this level of analysis for functions.
+      (when (eq (semantic-tag-class tag) 'function)
+       ;; Step 2:
+       ;;   If the function tag itself has a "parent" by name, then that
+       ;;   parent will exist in the scope we just calculated, so look it
+       ;;   up now.
+       ;;
+       (let ((p (semantic-tag-function-parent tag)))
+         (when p
+           ;; We have a parent, search for it.
+           (let* ((searchnameraw (cond ((stringp p) p)
+                                       ((semantic-tag-p p)
+                                        (semantic-tag-name p))
+                                       ((and (listp p) (stringp (car p)))
+                                        (car p))))
+                  (searchname (semantic-analyze-split-name searchnameraw))
+                  (snlist (if (consp searchname)
+                              searchname
+                            (list searchname)))
+                  (fullsearchname nil)
+
+                  (miniscope (semantic-scope-cache "mini"))
+                  ptag)
+
+             ;; Find the next entry in the refereneced type for
+             ;; our function, and append to return list till our
+             ;; returnlist is empty.
+             (while snlist
+               (setq fullsearchname
+                     (append (mapcar 'semantic-tag-name returnlist)
+                             (list (car snlist)))) ;; Next one
+               (setq ptag
+                     (semanticdb-typecache-find fullsearchname))
+
+               (when (or (not ptag)
+                         (not (semantic-tag-of-class-p ptag 'type)))
+                 (let ((rawscope
+                        (apply 'append
+                               (mapcar 'semantic-tag-type-members
+                                       (cons (car returnlist) scopetypes)
+                                       )))
+                       )
+                   (oset miniscope parents returnlist) ;; Not really accurate, but close
+                   (oset miniscope scope rawscope)
+                   (oset miniscope fullscope rawscope)
+                   (setq ptag
+                         (semantic-analyze-find-tag searchnameraw
+                                                    'type
+                                                    miniscope
+                                                    ))
+                   ))
+
+               (when ptag
+                 (when (and (not (semantic-tag-p ptag))
+                            (semantic-tag-p (car ptag)))
+                   (setq ptag (car ptag)))
+                 (setq returnlist (append returnlist (list ptag)))
+                 )
+
+               (setq snlist (cdr snlist)))
+             (setq returnlist returnlist)
+             )))
+       )
+      returnlist
+      )))
+
+(define-overloadable-function semantic-analyze-scope-lineage-tags (parents scopedtypes)
+  "Return the full lineage of tags from PARENTS.
+The return list is of the form ( TAG . PROTECTION ), where TAG is a tag,
+and PROTECTION is the level of protection offered by the relationship.
+Optional SCOPETYPES are additional scoped entities in which our parent might
+be found.")
+
+(defun semantic-analyze-scope-lineage-tags-default (parents scopetypes)
+  "Return the full lineage of tags from PARENTS.
+The return list is of the form ( TAG . PROTECTION ), where TAG is a tag,
+and PROTECTION is the level of protection offered by the relationship.
+Optional SCOPETYPES are additional scoped entities in which our parent might
+be found."
+  (let ((lineage nil)
+       (miniscope (semantic-scope-cache "mini"))
+       )
+    (oset miniscope parents parents)
+    (oset miniscope scope scopetypes)
+    (oset miniscope fullscope scopetypes)
+
+    (dolist (slp parents)
+      (semantic-analyze-scoped-inherited-tag-map
+       slp (lambda (newparent)
+            (let* ((pname (semantic-tag-name newparent))
+                   (prot (semantic-tag-type-superclass-protection slp pname))
+                   (effectiveprot (cond ((eq prot 'public)
+                                         ;; doesn't provide access to private slots?
+                                         'protected)
+                                        (t prot))))
+              (push (cons newparent effectiveprot) lineage)
+              ))
+       miniscope))
+
+    lineage))
+
+
+;;------------------------------------------------------------
+
+(define-overloadable-function semantic-analyze-scoped-tags (typelist parentlist)
+  "Return accessable tags when TYPELIST and PARENTLIST is in scope.
+Tags returned are not in the global name space, but are instead
+scoped inside a class or namespace.  Such items can be referenced
+without use of \"object.function()\" style syntax due to an
+implicit \"object\".")
+
+(defun semantic-analyze-scoped-tags-default (typelist halfscope)
+  "Return accessable tags when TYPELIST and HALFSCOPE is in scope.
+HALFSCOPE is the current scope partially initialized.
+Tags returned are not in the global name space, but are instead
+scoped inside a class or namespace.  Such items can be referenced
+without use of \"object.function()\" style syntax due to an
+implicit \"object\"."
+  (let ((typelist2 nil)
+       (currentscope nil)
+       (parentlist (oref halfscope parents))
+       (miniscope halfscope)
+       )
+    ;; Loop over typelist, and find and merge all namespaces matching
+    ;; the names in typelist.
+    (while typelist
+      (let ((tt (semantic-tag-type (car typelist))))
+       (when (and (stringp tt) (string= tt "namespace"))
+         ;; By using the typecache, our namespaces are pre-merged.
+         (setq typelist2 (cons (car typelist) typelist2))
+         ))
+      (setq typelist (cdr typelist)))
+
+    ;; Loop over the types (which should be sorted by postion
+    ;; adding to the scopelist as we go, and using the scopelist
+    ;; for additional searching!
+    (while typelist2
+      (oset miniscope scope currentscope)
+      (oset miniscope fullscope currentscope)
+      (setq currentscope (append
+                         (semantic-analyze-scoped-type-parts (car typelist2)
+                                                             miniscope)
+                         currentscope))
+      (setq typelist2 (cdr typelist2)))
+
+    ;; Collect all the types (class, etc) that are in our heratage.
+    ;; These are types that we can extract members from, not those
+    ;; delclared in using statements, or the like.
+    ;; Get the PARENTS including nesting scope for this location.
+    (while parentlist
+      (oset miniscope scope currentscope)
+      (oset miniscope fullscope currentscope)
+      (setq currentscope (append
+                         (semantic-analyze-scoped-type-parts (car parentlist)
+                                                             miniscope)
+                         currentscope))
+      (setq parentlist (cdr parentlist)))
+
+    ;; Loop over all the items, and collect any type constants.
+    (let ((constants nil))
+      (dolist (T currentscope)
+       (setq constants (append constants
+                               (semantic-analyze-type-constants T)))
+       )
+
+      (setq currentscope (append currentscope constants)))
+
+    currentscope))
+
+;;------------------------------------------------------------
+(define-overloadable-function  semantic-analyze-scope-calculate-access (type scope)
+  "Calculate the access class for TYPE as defined by the current SCOPE.
+Access is related to the :parents in SCOPE.  If type is a member of SCOPE
+then access would be 'private.  If TYPE is inherited by a member of SCOPE,
+the access would be 'protected.  Otherwise, access is 'public")
+
+(defun semantic-analyze-scope-calculate-access-default (type scope)
+  "Calculate the access class for TYPE as defined by the current SCOPE."
+  (cond ((semantic-scope-cache-p scope)
+        (let ((parents (oref scope parents))
+              (parentsi (oref scope parentinheritance))
+              )
+          (catch 'moose
+            ;; Investigate the parent, and see how it relates to type.
+            ;; If these tags are basically the same, then we have full access.
+            (dolist (p parents)
+              (when (semantic-tag-similar-p type p)
+                (throw 'moose 'private))
+              )
+            ;; Look to see if type is in our list of inherited parents.
+            (dolist (pi parentsi)
+              ;; pi is a cons cell ( PARENT . protection)
+              (let ((pip (car pi))
+                    (piprot (cdr pi)))
+                (when (semantic-tag-similar-p type pip)
+                  (throw 'moose
+                         ;; protection via inheritance means to pull out different
+                         ;; bits based on protection labels in an opposite way.
+                         (cdr (assoc piprot
+                                     '((public . private)
+                                       (protected . protected)
+                                       (private . public))))
+                         )))
+              )
+            ;; Not in our parentage.  Is type a FRIEND?
+            (let ((friends (semantic-find-tags-by-class 'friend (semantic-tag-type-members type))))
+              (dolist (F friends)
+                (dolist (pi parents)
+                  (if (string= (semantic-tag-name F) (semantic-tag-name pi))
+                      (throw 'moose 'private))
+                  )))
+            ;; Found nothing, return public
+            'public)
+          ))
+       (t 'public)))
+
+(defun semantic-completable-tags-from-type (type)
+  "Return a list of slots that are valid completions from the list of SLOTS.
+If a tag in SLOTS has a named parent, then that implies that the
+tag is not something you can complete from within TYPE."
+  (let ((allslots (semantic-tag-components type))
+       (leftover nil)
+       )
+    (dolist (S allslots)
+      (when (or (not (semantic-tag-of-class-p S 'function))
+               (not (semantic-tag-function-parent S)))
+       (setq leftover (cons S leftover)))
+      )
+    (nreverse leftover)))
+
+(defun semantic-analyze-scoped-type-parts (type &optional scope noinherit protection)
+  "Return all parts of TYPE, a tag representing a TYPE declaration.
+SCOPE is the scope object.
+NOINHERIT turns off searching of inherited tags.
+PROTECTION specifies the type of access requested, such as 'public or 'private."
+  (if (not type)
+      nil
+    (let* ((access (semantic-analyze-scope-calculate-access type scope))
+          ;; SLOTS are the slots directly a part of TYPE.
+          (allslots (semantic-completable-tags-from-type type))
+          (slots (semantic-find-tags-by-scope-protection
+                  access
+                  type allslots))
+          (fname (semantic-tag-file-name type))
+          ;; EXTMETH are externally defined methods that are still
+          ;; a part of this class.
+
+          ;; @TODO - is this line needed??  Try w/out for a while
+          ;; @note - I think C++ says no.  elisp might, but methods
+          ;;         look like defuns, so it makes no difference.
+          (extmeth nil) ; (semantic-tag-external-member-children type t))
+
+          ;; INHERITED are tags found in classes that our TYPE tag
+          ;; inherits from.  Do not do this if it was not requested.
+          (inherited (when (not noinherit)
+                       (semantic-analyze-scoped-inherited-tags type scope
+                                                               access)))
+          )
+      (when (not (semantic-tag-in-buffer-p type))
+       (let ((copyslots nil))
+         (dolist (TAG slots)
+           ;;(semantic--tag-put-property TAG :filename fname)
+           (if (semantic-tag-file-name TAG)
+               ;; If it has a filename, just go with it...
+               (setq copyslots (cons TAG copyslots))
+             ;; Otherwise, copy the tag w/ the guessed filename.
+             (setq copyslots (cons (semantic-tag-copy TAG nil fname)
+                                   copyslots)))
+           )
+         (setq slots (nreverse copyslots))
+         ))
+      ;; Flatten the database output.
+      (append slots extmeth inherited)
+      )))
+
+(defun semantic-analyze-scoped-inherited-tags (type scope access)
+  "Return all tags that TYPE inherits from.
+Argument SCOPE specify additional tags that are in scope
+whose tags can be searched when needed, OR it may be a scope object.
+ACCESS is the level of access we filter on child supplied tags.
+For langauges with protection on specific methods or slots,
+it should strip out those not accessable by methods of TYPE.
+An ACCESS of 'public means not in a method of a subclass of type.
+A value of 'private means we can access private parts of the originating
+type."
+  (let ((ret nil))
+    (semantic-analyze-scoped-inherited-tag-map
+     type (lambda (p)
+           (let* ((pname (semantic-tag-name p))
+                  (protection (semantic-tag-type-superclass-protection
+                               type pname))
+                  )
+             (if (and (eq access 'public) (not (eq protection 'public)))
+                 nil ;; Don't do it.
+
+               ;; We can get some parts of this type.
+               (setq ret (nconc ret
+                                ;; Do not pull in inherited parts here.  Those
+                                ;; will come via the inherited-tag-map fcn
+                                (semantic-analyze-scoped-type-parts
+                                 p scope t protection))
+                     ))))
+     scope)
+    ret))
+
+(defun semantic-analyze-scoped-inherited-tag-map (type fcn scope)
+  "Map all parents of TYPE to FCN.  Return tags of all the types.
+Argument SCOPE specify additional tags that are in scope
+whose tags can be searched when needed, OR it may be a scope object."
+  (let* (;; PARENTS specifies only the superclasses and not
+        ;; interfaces.  Inheriting from an interfaces implies
+        ;; you have a copy of all methods locally.  I think.
+        (parents (semantic-tag-type-superclasses type))
+        ps pt
+        (tmpscope scope)
+        )
+    (save-excursion
+
+      ;; Create a SCOPE just for looking up the parent based on where
+      ;; the parent came from.
+      ;;
+      ;; @TODO - Should we cache these mini-scopes around in Emacs
+      ;;         for recycling later?  Should this become a helpful
+      ;;         extra routine?
+      (when (and parents (semantic-tag-with-position-p type))
+       ;; If TYPE has a position, go there and get the scope.
+       (semantic-go-to-tag type)
+
+       ;; We need to make a mini scope, and only include the misc bits
+       ;; that will help in finding the parent.  We don't really need
+       ;; to do any of the stuff related to variables and what-not.
+       (setq tmpscope (semantic-scope-cache "mini"))
+       (let* (;; Step 1:
+              (scopetypes (semantic-analyze-scoped-types (point)))
+              (parents (semantic-analyze-scope-nested-tags (point) scopetypes))
+              ;;(parentinherited (semantic-analyze-scope-lineage-tags parents scopetypes))
+              (lscope nil)
+              )
+         (oset tmpscope scopetypes scopetypes)
+         (oset tmpscope parents parents)
+         ;;(oset tmpscope parentinheritance parentinherited)
+
+         (when (or scopetypes parents)
+           (setq lscope (semantic-analyze-scoped-tags scopetypes tmpscope))
+           (oset tmpscope scope lscope))
+         (oset tmpscope fullscope (append scopetypes lscope parents))
+         ))
+      ;; END creating tmpscope
+
+      ;; Look up each parent one at a time.
+      (dolist (p parents)
+       (setq ps (cond ((stringp p) p)
+                      ((and (semantic-tag-p p) (semantic-tag-prototype-p p))
+                       (semantic-tag-name p))
+                      ((and (listp p) (stringp (car p)))
+                       p))
+             pt (condition-case nil
+                    (or (semantic-analyze-find-tag ps 'type tmpscope)
+                        ;; A backup hack.
+                        (semantic-analyze-find-tag ps 'type scope))
+                  (error nil)))
+
+       (when pt
+         (funcall fcn pt)
+         ;; Note that we pass the original SCOPE in while recursing.
+         ;; so that the correct inheritance model is passed along.
+         (semantic-analyze-scoped-inherited-tag-map pt fcn scope)
+         )))
+    nil))
+
+;;; ANALYZER
+;;
+;; Create the scope structure for use in the Analyzer.
+;;
+(defun semantic-calculate-scope (&optional point)
+  "Calculate the scope at POINT.
+If POINT is not provided, then use the current location of point.
+The class returned from the scope calculation is variable
+`semantic-scope-cache'."
+  (interactive)
+  (if (not (and (featurep 'semanticdb) semanticdb-current-database))
+      nil ;; Don't do anything...
+    (if (not point) (setq point (point)))
+    (when (interactive-p)
+      (semantic-fetch-tags)
+      (semantic-scope-reset-cache)
+      )
+    (save-excursion
+      (goto-char point)
+      (let* ((TAG  (semantic-current-tag))
+            (scopecache
+             (semanticdb-cache-get semanticdb-current-table
+                                   semantic-scope-cache))
+            )
+       (when (not (semantic-equivalent-tag-p TAG (oref scopecache tag)))
+         (semantic-reset scopecache))
+       (if (oref scopecache tag)
+           ;; Even though we can recycle most of the scope, we
+           ;; need to redo the local variables since those change
+           ;; as you move about the tag.
+           (condition-case nil
+               (oset scopecache localvar (semantic-get-all-local-variables))
+             (error nil))
+
+         (let* (;; Step 1:
+                (scopetypes (semantic-analyze-scoped-types point))
+                (parents (semantic-analyze-scope-nested-tags point scopetypes))
+                (parentinherited (semantic-analyze-scope-lineage-tags
+                                  parents scopetypes))
+                )
+           (oset scopecache tag TAG)
+           (oset scopecache scopetypes scopetypes)
+           (oset scopecache parents parents)
+           (oset scopecache parentinheritance parentinherited)
+
+           (let* (;; Step 2:
+                  (scope (when (or scopetypes parents)
+                           (semantic-analyze-scoped-tags scopetypes scopecache))
+                         )
+                  ;; Step 3:
+                  (localargs (semantic-get-local-arguments))
+                  (localvar (condition-case nil
+                                (semantic-get-all-local-variables)
+                              (error nil)))
+                  )
+
+             ;; Try looking for parents again.
+             (when (not parentinherited)
+               (setq parentinherited (semantic-analyze-scope-lineage-tags
+                                      parents (append scopetypes scope)))
+               (when parentinherited
+                 (oset scopecache parentinheritance parentinherited)
+                 ;; Try calculating the scope again with the new inherited parent list.
+                 (setq scope (when (or scopetypes parents)
+                               (semantic-analyze-scoped-tags scopetypes scopecache))
+                       )))
+
+             ;; Fill out the scope.
+             (oset scopecache scope scope)
+             (oset scopecache fullscope (append scopetypes scope parents))
+             (oset scopecache localargs localargs)
+             (oset scopecache localvar localvar)
+             )))
+       ;; Make sure we become dependant on the typecache.
+       (semanticdb-typecache-add-dependant scopecache)
+       ;; Handy debug output.
+       (when (interactive-p)
+         (data-debug-show scopecache)
+         )
+       ;; Return ourselves
+       scopecache))))
+
+(defun semantic-scope-find (name &optional class scope-in)
+  "Find the tag with NAME, and optinal CLASS in the current SCOPE-IN.
+Searches various elements of the scope for NAME.  Return ALL the
+hits in order, with the first tag being in the closest scope."
+  (let ((scope (or scope-in (semantic-calculate-scope)))
+       (ans nil))
+    ;; Is the passed in scope really a scope?  if so, look through
+    ;; the options in that scope.
+    (if (semantic-scope-cache-p scope)
+       (let* ((la
+               ;; This should be first, but bugs in the
+               ;; C parser will turn function calls into
+               ;; assumed int return function prototypes.  Yuck!
+               (semantic-find-tags-by-name name (oref scope localargs)))
+              (lv
+               (semantic-find-tags-by-name name (oref scope localvar)))
+              (fullscoperaw (oref scope fullscope))
+              (sc (semantic-find-tags-by-name name fullscoperaw))
+              (typescoperaw  (oref scope typescope))
+              (tsc (semantic-find-tags-by-name name typescoperaw))
+              )
+         (setq ans
+               (if class
+                   ;; Scan out things not of the right class.
+                   (semantic-find-tags-by-class class (append la lv sc tsc))
+                 (append la lv sc tsc))
+               )
+
+         (when (and (not ans) (or typescoperaw fullscoperaw))
+           (let ((namesplit (semantic-analyze-split-name name)))
+             (when (consp namesplit)
+               ;; It may be we need to hack our way through type typescope.
+               (while namesplit
+                 (setq ans (append
+                            (semantic-find-tags-by-name (car namesplit)
+                                                        typescoperaw)
+                            (semantic-find-tags-by-name (car namesplit)
+                                                        fullscoperaw)
+                            ))
+                 (if (not ans)
+                     (setq typescoperaw nil)
+                   (when (cdr namesplit)
+                     (setq typescoperaw (semantic-tag-type-members
+                                         (car ans)))))
+
+                 (setq namesplit (cdr namesplit)))
+               ;; Once done, store the current typecache lookup
+               (oset scope typescope
+                     (append typescoperaw (oref scope typescope)))
+               )))
+         ;; Return it.
+         ans)
+      ;; Not a real scope.  Our scope calculation analyze parts of
+      ;; what it finds, and needs to pass lists through to do it's work.
+      ;; Tread that list as a singly entry.
+      (if class
+         (semantic-find-tags-by-class class scope)
+       scope)
+      )))
+
+;;; DUMP
+;;
+(defmethod semantic-analyze-show ((context semantic-scope-cache))
+  "Insert CONTEXT into the current buffer in a nice way."
+  (semantic-analyze-princ-sequence (oref context scopetypes) "-> ScopeTypes: " )
+  (semantic-analyze-princ-sequence (oref context parents) "-> Parents: " )
+  (semantic-analyze-princ-sequence (oref context scope) "-> Scope: " )
+  ;;(semantic-analyze-princ-sequence (oref context fullscope) "Fullscope:  " )
+  (semantic-analyze-princ-sequence (oref context localargs) "-> Local Args: " )
+  (semantic-analyze-princ-sequence (oref context localvar) "-> Local Vars: " )
+  )
+
+(provide 'semantic/scope)
+
+;;; semantic/scope.el ends here