Mercurial > emacs
diff lisp/cedet/semantic/scope.el @ 104435:52067a6bf088
semantic/cedet/db-global.el, semantic/cedet/ia-sb.el,
semantic/cedet/sb.el, semantic/cedet/scope.el: New files.
author | Chong Yidong <cyd@stupidchicken.com> |
---|---|
date | Sun, 30 Aug 2009 14:36:00 +0000 |
parents | |
children | df08b7ab0ba0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/cedet/semantic/scope.el Sun Aug 30 14:36:00 2009 +0000 @@ -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