123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798 |
- (eval-when-compile (require 'cl))
- (require 'semantic)
- (require 'semantic/format)
- (require 'semantic/ctxt)
- (require 'semantic/scope)
- (require 'semantic/sort)
- (require 'semantic/analyze/fcn)
- (eval-when-compile (require 'semantic/find))
- (declare-function data-debug-new-buffer "data-debug")
- (declare-function data-debug-insert-object-slots "eieio-datadebug")
- (defvar semantic-analyze-error-stack nil
- "Collection of any errors thrown during analysis.")
- (defun semantic-analyze-push-error (err)
- "Push the error in ERR-DATA onto the error stack.
- Argument ERR."
- (push err semantic-analyze-error-stack))
- (defclass semantic-analyze-context ()
- ((bounds :initarg :bounds
- :type list
- :documentation "The bounds of this context.
- Usually bound to the dimension of a single symbol or command.")
- (prefix :initarg :prefix
- :type list
- :documentation "List of tags defining local text.
- This can be nil, or a list where the last element can be a string
- representing text that may be incomplete. Preceding elements
- must be semantic tags representing variables or functions
- called in a dereference sequence.")
- (prefixclass :initarg :prefixclass
- :type list
- :documentation "Tag classes expected at this context.
- These are classes for tags, such as 'function, or 'variable.")
- (prefixtypes :initarg :prefixtypes
- :type list
- :documentation "List of tags defining types for :prefix.
- This list is one shorter than :prefix. Each element is a semantic
- tag representing a type matching the semantic tag in the same
- position in PREFIX.")
- (scope :initarg :scope
- :type (or null semantic-scope-cache)
- :documentation "List of tags available in scopetype.
- See `semantic-analyze-scoped-tags' for details.")
- (buffer :initarg :buffer
- :type buffer
- :documentation "The buffer this context is derived from.")
- (errors :initarg :errors
- :documentation "Any errors thrown an caught during analysis.")
- )
- "Base analysis data for any context.")
- (defclass semantic-analyze-context-assignment (semantic-analyze-context)
- ((assignee :initarg :assignee
- :type list
- :documentation "A sequence of tags for an assignee.
- This is a variable into which some value is being placed. The last
- item in the list is the variable accepting the value. Earlier
- tags represent the variables being dereferenced to get to the
- assignee."))
- "Analysis class for a value in an assignment.")
- (defclass semantic-analyze-context-functionarg (semantic-analyze-context)
- ((function :initarg :function
- :type list
- :documentation "A sequence of tags for a function.
- This is a function being called. The cursor will be in the position
- of an argument.
- The last tag in :function is the function being called. Earlier
- tags represent the variables being dereferenced to get to the
- function.")
- (index :initarg :index
- :type integer
- :documentation "The index of the argument for this context.
- If a function takes 4 arguments, this value should be bound to
- the values 1 through 4.")
- (argument :initarg :argument
- :type list
- :documentation "A sequence of tags for the :index argument.
- The argument can accept a value of some type, and this contains the
- tag for that definition. It should be a tag, but might
- be just a string in some circumstances.")
- )
- "Analysis class for a value as a function argument.")
- (defclass semantic-analyze-context-return (semantic-analyze-context)
- ()
- "Analysis class for return data.
- Return data methods identify the required type by the return value
- of the parent function.")
- (defmethod semantic-analyze-type-constraint
- ((context semantic-analyze-context) &optional desired-type)
- "Return a type constraint for completing :prefix in CONTEXT.
- Optional argument DESIRED-TYPE may be a non-type tag to analyze."
- (when (semantic-tag-p desired-type)
-
- (if (not (eq (semantic-tag-class desired-type) 'type))
- (setq desired-type (semantic-tag-type desired-type)))
-
- (cond ((stringp desired-type)
- (setq desired-type (list desired-type 'type)))
- ((and (stringp (car desired-type))
- (not (semantic-tag-p desired-type)))
- (setq desired-type (list (car desired-type) 'type)))
- ((semantic-tag-p desired-type)
-
- nil)
- (t (setq desired-type nil))
- )
- desired-type))
- (defmethod semantic-analyze-type-constraint
- ((context semantic-analyze-context-functionarg))
- "Return a type constraint for completing :prefix in CONTEXT."
- (call-next-method context (car (oref context argument))))
- (defmethod semantic-analyze-type-constraint
- ((context semantic-analyze-context-assignment))
- "Return a type constraint for completing :prefix in CONTEXT."
- (call-next-method context (car (reverse (oref context assignee)))))
- (defmethod semantic-analyze-interesting-tag
- ((context semantic-analyze-context))
- "Return a tag from CONTEXT that would be most interesting to a user."
- (let ((prefix (reverse (oref context :prefix))))
-
- (while (and prefix (not (semantic-tag-p (car prefix))))
- (setq prefix (cdr prefix)))
-
- (car prefix)))
- (defmethod semantic-analyze-interesting-tag
- ((context semantic-analyze-context-functionarg))
- "Try the base, and if that fails, return what we are assigning into."
- (or (call-next-method) (car-safe (oref context :function))))
- (defmethod semantic-analyze-interesting-tag
- ((context semantic-analyze-context-assignment))
- "Try the base, and if that fails, return what we are assigning into."
- (or (call-next-method) (car-safe (oref context :assignee))))
- (define-overloadable-function semantic-analyze-find-tag-sequence (sequence &optional
- scope typereturn throwsym)
- "Attempt to find all tags in SEQUENCE.
- Optional argument LOCALVAR is the list of local variables to use when
- finding the details on the first element of SEQUENCE in case
- it is not found in the global set of tables.
- Optional argument SCOPE are additional terminals to search which are currently
- scoped. These are not local variables, but symbols available in a structure
- which doesn't need to be dereferenced.
- Optional argument TYPERETURN is a symbol in which the types of all found
- will be stored. If nil, that data is thrown away.
- Optional argument THROWSYM specifies a symbol the throw on non-recoverable error.")
- (defun semantic-analyze-find-tag-sequence-default (sequence &optional
- scope typereturn
- throwsym)
- "Attempt to find all tags in SEQUENCE.
- SCOPE are extra tags which are in scope.
- TYPERETURN is a symbol in which to place a list of tag classes that
- are found in SEQUENCE.
- Optional argument THROWSYM specifies a symbol the throw on non-recoverable error."
- (let ((s sequence)
- (tmp nil)
- (tag nil)
- (tagtype nil)
- (fname nil)
- (miniscope (when scope (clone scope)))
- )
-
- (setq tmp (semanticdb-typecache-find sequence))
- (if tmp
- (progn
-
- (setq s nil)
- (setq tag (list tmp)))
-
-
-
- (setq tmp (or
-
-
- (and scope (semantic-scope-find (car s) nil scope))
-
- (semantic-analyze-find-tag (car s))
- ))
- (if (and (listp tmp) (semantic-tag-p (car tmp)))
- (setq tmp (semantic-analyze-select-best-tag tmp)))
- (if (not (semantic-tag-p tmp))
- (if throwsym
- (throw throwsym "Cannot find definition")
- (error "Cannot find definition for \"%s\"" (car s))))
- (setq s (cdr s))
- (setq tag (cons tmp tag))
- (setq fname (semantic-tag-file-name tmp))
- )
-
- (while s
-
-
-
-
- (let* ((tmptype
-
-
- (cond ((semantic-tag-of-class-p tmp 'type)
-
- (when miniscope
- (let ((rawscope
- (apply 'append
- (mapcar 'semantic-tag-type-members
- tagtype))))
- (oset miniscope fullscope rawscope)))
-
- (or (semantic-analyze-type tmp miniscope)
- tmp))
- (t
- (semantic-analyze-tag-type tmp scope))))
- (typefile
- (when tmptype
- (semantic-tag-file-name tmptype)))
- (slots nil))
-
- (setq slots (semantic-analyze-scoped-type-parts tmptype scope))
-
- (setq tmp (semantic-find-tags-by-name (car s) slots))
-
- (if (and (listp tmp) (semantic-tag-p (car tmp)))
- (setq tmp (semantic-analyze-select-best-tag tmp)))
-
- (if (not (semantic-tag-p tmp))
- (if (cdr s)
-
- (error "Cannot find definition for \"%s\"" (car s))
-
- (setq tmp (car s))))
- (setq fname (or typefile fname))
- (when (and fname (semantic-tag-p tmp)
- (not (semantic-tag-in-buffer-p tmp)))
- (semantic--tag-put-property tmp :filename fname))
- (setq tag (cons tmp tag))
- (setq tagtype (cons tmptype tagtype))
- )
- (setq s (cdr s)))
- (if typereturn (set typereturn (nreverse tagtype)))
-
- (nreverse tag)))
- (defun semantic-analyze-find-tag (name &optional tagclass scope)
- "Return the first tag found with NAME or nil if not found.
- Optional argument TAGCLASS specifies the class of tag to return,
- such as 'function or 'variable.
- Optional argument SCOPE specifies a scope object which has
- additional tags which are in SCOPE and do not need prefixing to
- find.
- This is a wrapper on top of semanticdb, semanticdb typecache,
- semantic-scope, and semantic search functions. Almost all
- searches use the same arguments."
- (let ((namelst (if (consp name) name
- (semantic-analyze-split-name name))))
- (cond
-
-
-
-
-
-
-
-
- ((listp namelst)
-
-
- (or (semanticdb-typecache-find namelst)
-
- (let ((seq (semantic-analyze-find-tag-sequence
- namelst scope nil)))
- (semantic-analyze-select-best-tag seq tagclass)
- )))
-
- ((stringp namelst)
- (let ((retlist (and scope (semantic-scope-find name tagclass scope))))
- (if retlist
- (semantic-analyze-select-best-tag
- retlist tagclass)
- (if (eq tagclass 'type)
- (semanticdb-typecache-find name)
-
-
- (setq retlist (semanticdb-typecache-find name))
- (if retlist
- retlist
- (semantic-analyze-select-best-tag
- (semanticdb-strip-find-results
- (semanticdb-find-tags-by-name name)
- 'name)
- tagclass)
- )))))
- )))
- (define-overloadable-function semantic-analyze-current-symbol
- (analyzehookfcn &optional position)
- "Call ANALYZEHOOKFCN after analyzing the symbol under POSITION.
- The ANALYZEHOOKFCN is called with the current symbol bounds, and the
- analyzed prefix. It should take the arguments (START END PREFIX).
- The ANALYZEHOOKFCN is only called if some sort of prefix with bounds was
- found under POSITION.
- The results of ANALYZEHOOKFCN is returned, or nil if there was nothing to
- call it with.
- For regular analysis, you should call `semantic-analyze-current-context'
- to calculate the context information. The purpose for this function is
- to provide a large number of non-cached analysis for filtering symbols."
-
- (when (not (semantic-active-p))
- (error "Cannot analyze buffers not supported by Semantic"))
-
-
- (semantic-refresh-tags-safe)
-
- (save-match-data
- (save-excursion
- (:override)))
- )
- (defun semantic-analyze-current-symbol-default (analyzehookfcn position)
- "Call ANALYZEHOOKFCN on the analyzed symbol at POSITION."
- (let* ((semantic-analyze-error-stack nil)
- (LLstart (current-time))
- (prefixandbounds (semantic-ctxt-current-symbol-and-bounds (or position (point))))
- (prefix (car prefixandbounds))
- (bounds (nth 2 prefixandbounds))
- (scope (semantic-calculate-scope position))
- (end nil)
- )
-
- (when bounds
- (if debug-on-error
- (catch 'unfindable
-
- (setq prefix (semantic-analyze-find-tag-sequence
- prefix scope 'prefixtypes 'unfindable)))
-
- (condition-case err
-
-
-
- (setq prefix (semantic-analyze-find-tag-sequence
- prefix scope 'prefixtypes))
- (error (semantic-analyze-push-error err))))
- (setq end (current-time))
-
- )
- (when prefix
- (prog1
- (funcall analyzehookfcn (car bounds) (cdr bounds) prefix)
-
-
- )
- )))
- (define-overloadable-function semantic-analyze-current-context (&optional position)
- "Analyze the current context at optional POSITION.
- If called interactively, display interesting information about POSITION
- in a separate buffer.
- Returns an object based on symbol `semantic-analyze-context'.
- This function can be overridden with the symbol `analyze-context'.
- When overriding this function, your override will be called while
- cursor is at POSITION. In addition, your function will not be called
- if a cached copy of the return object is found."
- (interactive "d")
-
- (when (not (semantic-active-p))
- (error "Cannot analyze buffers not supported by Semantic"))
-
-
- (semantic-refresh-tags-safe)
-
- (if (not position) (setq position (point)))
- (save-excursion
- (goto-char position)
- (let* ((answer (semantic-get-cache-data 'current-context)))
- (with-syntax-table semantic-lex-syntax-table
- (when (not answer)
- (setq answer (:override))
- (when (and answer (oref answer bounds))
- (with-slots (bounds) answer
- (semantic-cache-data-to-buffer (current-buffer)
- (car bounds)
- (cdr bounds)
- answer
- 'current-context
- 'exit-cache-zone)))
-
- (when (called-interactively-p 'any)
- (if answer
- (semantic-analyze-pop-to-context answer)
- (message "No Context."))
- ))
- answer))))
- (defun semantic-analyze-current-context-default (position)
- "Analyze the current context at POSITION.
- Returns an object based on symbol `semantic-analyze-context'."
- (let* ((semantic-analyze-error-stack nil)
- (context-return nil)
- (prefixandbounds (semantic-ctxt-current-symbol-and-bounds (or position (point))))
- (prefix (car prefixandbounds))
- (bounds (nth 2 prefixandbounds))
-
- (prefixclass (semantic-ctxt-current-class-list))
- (prefixtypes nil)
- (scope (semantic-calculate-scope position))
- (function nil)
- (fntag nil)
- arg fntagend argtag
- assign asstag
- )
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- (setq function (semantic-ctxt-current-function))
- (when function
-
- (setq arg (semantic-ctxt-current-argument))
-
- (condition-case err
- (setq fntag
- (semantic-analyze-find-tag-sequence function scope))
- (error (semantic-analyze-push-error err)))
-
-
-
- (when (stringp (car (last fntag)))
-
- (setcar (last fntag) (semantic-tag (car (last fntag)) 'function))
- )
- (when fntag
- (let ((fcn (semantic-find-tags-by-class 'function fntag)))
- (when (not fcn)
- (let ((ty (semantic-find-tags-by-class 'type fntag)))
- (when ty
-
-
- (setq fcn (semantic-find-tags-by-name
- (semantic-tag-name (car ty))
- (semantic-tag-type-members (car ty))))
- (if fcn
- (let ((lp fcn))
- (while lp
- (when (semantic-tag-get-attribute (car lp)
- :constructor)
- (setq fcn (cons (car lp) fcn)))
- (setq lp (cdr lp))))
-
- (setq fcn fntag))
- )))
- (setq fntagend (car (reverse fcn))
- argtag
- (when (semantic-tag-p fntagend)
- (nth (1- arg) (semantic-tag-function-arguments fntagend)))
- fntag fcn))))
-
-
- (when bounds
- (if debug-on-error
- (catch 'unfindable
-
- (setq prefix (semantic-analyze-find-tag-sequence
- prefix scope 'prefixtypes 'unfindable)))
-
- (condition-case err
-
-
-
- (setq prefix (semantic-analyze-find-tag-sequence
- prefix scope 'prefixtypes))
- (error (semantic-analyze-push-error err))))
- )
-
- (cond
- (fntag
-
-
-
- (setq context-return
- (semantic-analyze-context-functionarg
- "functionargument"
- :buffer (current-buffer)
- :function fntag
- :index arg
- :argument (list argtag)
- :scope scope
- :prefix prefix
- :prefixclass prefixclass
- :bounds bounds
- :prefixtypes prefixtypes
- :errors semantic-analyze-error-stack)))
-
- ((and (setq assign (semantic-ctxt-current-assignment))
-
- (condition-case err
- (setq asstag (semantic-analyze-find-tag-sequence
- assign scope))
- (error (semantic-analyze-push-error err)
- nil)))
- (setq context-return
- (semantic-analyze-context-assignment
- "assignment"
- :buffer (current-buffer)
- :assignee asstag
- :scope scope
- :bounds bounds
- :prefix prefix
- :prefixclass prefixclass
- :prefixtypes prefixtypes
- :errors semantic-analyze-error-stack)))
-
-
-
- (bounds
-
- (setq context-return
- (semantic-analyze-context
- "context"
- :buffer (current-buffer)
- :scope scope
- :bounds bounds
- :prefix prefix
- :prefixclass prefixclass
- :prefixtypes prefixtypes
- :errors semantic-analyze-error-stack)))
- (t (setq context-return nil))
- )
-
- context-return))
- (defun semantic-adebug-analyze (&optional ctxt)
- "Perform `semantic-analyze-current-context'.
- Display the results as a debug list.
- Optional argument CTXT is the context to show."
- (interactive)
- (require 'data-debug)
- (let ((start (current-time))
- (ctxt (or ctxt (semantic-analyze-current-context)))
- (end (current-time)))
- (if (not ctxt)
- (message "No Analyzer Results")
- (message "Analysis took %.2f seconds."
- (semantic-elapsed-time start end))
- (semantic-analyze-pulse ctxt)
- (if ctxt
- (progn
- (data-debug-new-buffer "*Analyzer ADEBUG*")
- (data-debug-insert-object-slots ctxt "]"))
- (message "No Context to analyze here.")))))
- (declare-function pulse-momentary-highlight-region "pulse")
- (defmethod semantic-analyze-pulse ((context semantic-analyze-context))
- "Pulse the region that CONTEXT affects."
- (require 'pulse)
- (with-current-buffer (oref context :buffer)
- (let ((bounds (oref context :bounds)))
- (when bounds
- (pulse-momentary-highlight-region (car bounds) (cdr bounds))))))
- (defcustom semantic-analyze-summary-function 'semantic-format-tag-prototype
- "Function to use when creating items in Imenu.
- Some useful functions are found in `semantic-format-tag-functions'."
- :group 'semantic
- :type semantic-format-tag-custom-list)
- (defun semantic-analyze-princ-sequence (sequence &optional prefix buff)
- "Send the tag SEQUENCE to standard out.
- Use PREFIX as a label.
- Use BUFF as a source of override methods."
- (while sequence
- (princ prefix)
- (cond
- ((semantic-tag-p (car sequence))
- (princ (funcall semantic-analyze-summary-function
- (car sequence))))
- ((stringp (car sequence))
- (princ "\"")
- (princ (semantic--format-colorize-text (car sequence) 'variable))
- (princ "\""))
- (t
- (princ (format "'%S" (car sequence)))))
- (princ "\n")
- (setq sequence (cdr sequence))
- (setq prefix (make-string (length prefix) ? ))
- ))
- (defmethod semantic-analyze-show ((context semantic-analyze-context))
- "Insert CONTEXT into the current buffer in a nice way."
- (semantic-analyze-princ-sequence (oref context prefix) "Prefix: " )
- (semantic-analyze-princ-sequence (oref context prefixclass) "Prefix Classes: ")
- (semantic-analyze-princ-sequence (oref context prefixtypes) "Prefix Types: ")
- (semantic-analyze-princ-sequence (oref context errors) "Encountered Errors: ")
- (princ "--------\n")
-
-
-
- (when (oref context scope)
- (semantic-analyze-show (oref context scope)))
- )
- (defmethod semantic-analyze-show ((context semantic-analyze-context-assignment))
- "Insert CONTEXT into the current buffer in a nice way."
- (semantic-analyze-princ-sequence (oref context assignee) "Assignee: ")
- (call-next-method))
- (defmethod semantic-analyze-show ((context semantic-analyze-context-functionarg))
- "Insert CONTEXT into the current buffer in a nice way."
- (semantic-analyze-princ-sequence (oref context function) "Function: ")
- (princ "Argument Index: ")
- (princ (oref context index))
- (princ "\n")
- (semantic-analyze-princ-sequence (oref context argument) "Argument: ")
- (call-next-method))
- (defun semantic-analyze-pop-to-context (context)
- "Display CONTEXT in a temporary buffer.
- CONTEXT's content is described in `semantic-analyze-current-context'."
- (semantic-analyze-pulse context)
- (with-output-to-temp-buffer "*Semantic Context Analysis*"
- (princ "Context Type: ")
- (princ (object-name context))
- (princ "\n")
- (princ "Bounds: ")
- (princ (oref context bounds))
- (princ "\n")
- (semantic-analyze-show context)
- )
- (shrink-window-if-larger-than-buffer
- (get-buffer-window "*Semantic Context Analysis*"))
- )
- (provide 'semantic/analyze)
|