tag.el 50.6 KB
Newer Older
1
;;; semantic/tag.el --- tag creation and access
2

Paul Eggert's avatar
Paul Eggert committed
3
;; Copyright (C) 1999-2005, 2007-2015 Free Software Foundation, Inc.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

;; Author: Eric M. Ludlam <zappo@gnu.org>

;; This file is part of GNU Emacs.

;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:
;;
;; I.  The core production of semantic is the list of tags produced by the
;;    different parsers.  This file provides 3 APIs related to tag access:
;;
;;    1) Primitive Tag Access
;;       There is a set of common features to all tags.  These access
;;       functions can get these values.
;;    2) Standard Tag Access
;;       A Standard Tag should be produced by most traditional languages
;;       with standard styles common to typed object oriented languages.
;;       These functions can access these data elements from a tag.
;;    3) Generic Tag Access
;;       Access to tag structure in a more direct way.
;;         ** May not be forward compatible.
;;
;; II.  There is also an API for tag creation.  Use `semantic-tag' to create
;;     a new tag.
;;
Glenn Morris's avatar
Glenn Morris committed
41
;; III.  Tag Comparison.  Allows explicit or comparative tests to see
42 43 44 45 46 47 48
;;      if two tags are the same.

;;; Code:
;;

;; Keep this only so long as we have obsolete fcns.
(require 'semantic/fw)
49 50 51 52 53
(require 'semantic/lex)

(declare-function semantic-analyze-split-name "semantic/analyze/fcn")
(declare-function semantic-fetch-tags "semantic")
(declare-function semantic-clear-toplevel-cache "semantic")
Chong Yidong's avatar
Chong Yidong committed
54
(declare-function semantic-tag-similar-p "semantic/tag-ls")
55

Chong Yidong's avatar
Chong Yidong committed
56
(defconst semantic-tag-version "2.0"
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
  "Version string of semantic tags made with this code.")

(defconst semantic-tag-incompatible-version "1.0"
  "Version string of semantic tags which are not currently compatible.
These old style tags may be loaded from a file with semantic db.
In this case, we must flush the old tags and start over.")

;;; Primitive Tag access system:
;;
;; Raw tags in semantic are lists of 5 elements:
;;
;;   (NAME CLASS ATTRIBUTES PROPERTIES OVERLAY)
;;
;; Where:
;;
;;   - NAME is a string that represents the tag name.
;;
;;   - CLASS is a symbol that represent the class of the tag (for
;;     example, usual classes are `type', `function', `variable',
;;     `include', `package', `code').
;;
;;   - ATTRIBUTES is a public list of attributes that describes
;;     language data represented by the tag (for example, a variable
;;     can have a `:constant-flag' attribute, a function an `:arguments'
;;     attribute, etc.).
;;
;;   - PROPERTIES is a private list of properties used internally.
;;
;;   - OVERLAY represent the location of data described by the tag.
;;

(defsubst semantic-tag-name (tag)
  "Return the name of TAG.
For functions, variables, classes, typedefs, etc., this is the identifier
that is being defined.  For tags without an obvious associated name, this
may be the statement type, e.g., this may return @code{print} for python's
print statement."
  (car tag))

(defsubst semantic-tag-class (tag)
  "Return the class of TAG.
98
This is a symbol like `variable', `function', or `type'.
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
There is no limit to the symbols that may represent the class of a tag.
Each parser generates tags with classes defined by it.

For functional languages, typical tag classes are:

@table @code
@item type
Data types, named map for a memory block.
@item function
A function or method, or named execution location.
@item variable
A variable, or named storage for data.
@item include
Statement that represents a file from which more tags can be found.
@item package
Glenn Morris's avatar
Glenn Morris committed
114
Statement that declares this file's package name.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
@item code
Code that has not name or binding to any other symbol, such as in a script.
@end table
"
  (nth 1 tag))

(defsubst semantic-tag-attributes (tag)
  "Return the list of public attributes of TAG.
That is a property list: (ATTRIBUTE-1 VALUE-1 ATTRIBUTE-2 VALUE-2...)."
  (nth 2 tag))

(defsubst semantic-tag-properties (tag)
  "Return the list of private properties of TAG.
That is a property list: (PROPERTY-1 VALUE-1 PROPERTY-2 VALUE-2...)."
  (nth 3 tag))

(defsubst semantic-tag-overlay (tag)
  "Return the OVERLAY part of TAG.
That is, an overlay or an unloaded buffer representation.
This function can also return an array of the form [ START END ].
This occurs for tags that are not currently linked into a buffer."
  (nth 4 tag))

(defsubst semantic--tag-overlay-cdr (tag)
  "Return the cons cell whose car is the OVERLAY part of TAG.
That function is for internal use only."
  (nthcdr 4 tag))

(defsubst semantic--tag-set-overlay (tag overlay)
  "Set the overlay part of TAG with OVERLAY.
That function is for internal use only."
  (setcar (semantic--tag-overlay-cdr tag) overlay))

(defsubst semantic-tag-start (tag)
  "Return the start location of TAG."
  (let ((o (semantic-tag-overlay tag)))
    (if (semantic-overlay-p o)
        (semantic-overlay-start o)
      (aref o 0))))

(defsubst semantic-tag-end (tag)
  "Return the end location of TAG."
  (let ((o (semantic-tag-overlay tag)))
    (if (semantic-overlay-p o)
        (semantic-overlay-end o)
      (aref o 1))))

(defsubst semantic-tag-bounds (tag)
  "Return the location (START END) of data TAG describes."
  (list (semantic-tag-start tag)
        (semantic-tag-end tag)))

(defun semantic-tag-set-bounds (tag start end)
  "In TAG, set the START and END location of data it describes."
  (let ((o (semantic-tag-overlay tag)))
    (if (semantic-overlay-p o)
        (semantic-overlay-move o start end)
      (semantic--tag-set-overlay tag (vector start end)))))

(defun semantic-tag-in-buffer-p (tag)
Glenn Morris's avatar
Glenn Morris committed
175
  "Return the buffer TAG resides in, if tag is already in a buffer.
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
If a tag is not in a buffer, return nil."
  (let ((o (semantic-tag-overlay tag)))
     ;; TAG is currently linked to a buffer, return it.
    (when (and (semantic-overlay-p o)
	       (semantic-overlay-live-p o))
      (semantic-overlay-buffer o))))

(defsubst semantic--tag-get-property (tag property)
  "From TAG, extract the value of PROPERTY.
Return the value found, or nil if PROPERTY is not one of the
properties of TAG.
That function is for internal use only."
  (plist-get (semantic-tag-properties tag) property))

(defun semantic-tag-buffer (tag)
  "Return the buffer TAG resides in.
If TAG has an originating file, read that file into a (maybe new)
buffer, and return it.
Return nil if there is no buffer for this tag."
  (let ((buff (semantic-tag-in-buffer-p tag)))
    (if buff
	buff
      ;; TAG has an originating file, read that file into a buffer, and
      ;; return it.
     (if (semantic--tag-get-property tag :filename)
201 202
	 (save-match-data
	   (find-file-noselect (semantic--tag-get-property tag :filename)))
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
       ;; TAG is not in Emacs right now, no buffer is available.
       ))))

(defun semantic-tag-mode (&optional tag)
  "Return the major mode active for TAG.
TAG defaults to the tag at point in current buffer.
If TAG has a :mode property return it.
If point is inside TAG bounds, return the major mode active at point.
Return the major mode active at beginning of TAG otherwise.
See also the function `semantic-ctxt-current-mode'."
  (or tag (setq tag (semantic-current-tag)))
  (or (semantic--tag-get-property tag :mode)
      (let ((buffer (semantic-tag-buffer tag))
            (start (semantic-tag-start tag))
            (end   (semantic-tag-end tag)))
        (save-excursion
          (and buffer (set-buffer buffer))
          ;; Unless point is inside TAG bounds, move it to the
          ;; beginning of TAG.
          (or (and (>= (point) start) (< (point) end))
              (goto-char start))
Chong Yidong's avatar
Chong Yidong committed
224
          (require 'semantic/ctxt)
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
          (semantic-ctxt-current-mode)))))

(defsubst semantic--tag-attributes-cdr (tag)
  "Return the cons cell whose car is the ATTRIBUTES part of TAG.
That function is for internal use only."
  (nthcdr 2 tag))

(defsubst semantic-tag-put-attribute (tag attribute value)
  "Change value in TAG of ATTRIBUTE to VALUE.
If ATTRIBUTE already exists, its value is set to VALUE, otherwise the
new ATTRIBUTE VALUE pair is added.
Return TAG.
Use this function in a parser when not all attributes are known at the
same time."
  (let* ((plist-cdr (semantic--tag-attributes-cdr tag)))
    (when (consp plist-cdr)
      (setcar plist-cdr
              (semantic-tag-make-plist
               (plist-put (car plist-cdr) attribute value))))
    tag))

(defun semantic-tag-put-attribute-no-side-effect (tag attribute value)
  "Change value in TAG of ATTRIBUTE to VALUE without side effects.
All cons cells in the attribute list are replicated so that there
are no side effects if TAG is in shared lists.
If ATTRIBUTE already exists, its value is set to VALUE, otherwise the
new ATTRIBUTE VALUE pair is added.
Return TAG."
  (let* ((plist-cdr (semantic--tag-attributes-cdr tag)))
    (when (consp plist-cdr)
      (setcar plist-cdr
              (semantic-tag-make-plist
               (plist-put (copy-sequence (car plist-cdr))
                          attribute value))))
    tag))

(defsubst semantic-tag-get-attribute (tag attribute)
  "From TAG, return the value of ATTRIBUTE.
ATTRIBUTE is a symbol whose specification value to get.
Return the value found, or nil if ATTRIBUTE is not one of the
attributes of TAG."
  (plist-get (semantic-tag-attributes tag) attribute))

;; These functions are for internal use only!
(defsubst semantic--tag-properties-cdr (tag)
  "Return the cons cell whose car is the PROPERTIES part of TAG.
That function is for internal use only."
  (nthcdr 3 tag))

(defun semantic--tag-put-property (tag property value)
  "Change value in TAG of PROPERTY to VALUE.
If PROPERTY already exists, its value is set to VALUE, otherwise the
new PROPERTY VALUE pair is added.
Return TAG.
That function is for internal use only."
  (let* ((plist-cdr (semantic--tag-properties-cdr tag)))
    (when (consp plist-cdr)
      (setcar plist-cdr
              (semantic-tag-make-plist
               (plist-put (car plist-cdr) property value))))
    tag))

(defun semantic--tag-put-property-no-side-effect (tag property value)
  "Change value in TAG of PROPERTY to VALUE without side effects.
All cons cells in the property list are replicated so that there
are no side effects if TAG is in shared lists.
If PROPERTY already exists, its value is set to VALUE, otherwise the
new PROPERTY VALUE pair is added.
Return TAG.
That function is for internal use only."
  (let* ((plist-cdr (semantic--tag-properties-cdr tag)))
    (when (consp plist-cdr)
      (setcar plist-cdr
              (semantic-tag-make-plist
               (plist-put (copy-sequence (car plist-cdr))
                          property value))))
    tag))

(defun semantic-tag-file-name (tag)
  "Return the name of the file from which TAG originated.
Return nil if that information can't be obtained.
If TAG is from a loaded buffer, then that buffer's filename is used.
If TAG is unlinked, but has a :filename property, then that is used."
  (let ((buffer (semantic-tag-in-buffer-p tag)))
    (if buffer
        (buffer-file-name buffer)
      (semantic--tag-get-property tag :filename))))

;;; Tag tests and comparisons.
(defsubst semantic-tag-p (tag)
  "Return non-nil if TAG is most likely a semantic tag."
  (condition-case nil
      (and (consp tag)
	   (stringp (car tag))                ; NAME
	   (symbolp (nth 1 tag)) (nth 1 tag)  ; TAG-CLASS
	   (listp (nth 2 tag))                ; ATTRIBUTES
	   (listp (nth 3 tag))                ; PROPERTIES
	   )
    ;; If an error occurs, then it most certainly is not a tag.
    (error nil)))

(defsubst semantic-tag-of-class-p (tag class)
  "Return non-nil if class of TAG is CLASS."
  (eq (semantic-tag-class tag) class))

(defsubst semantic-tag-type-members (tag)
  "Return the members of the type that TAG describes.
That is the value of the `:members' attribute."
  (semantic-tag-get-attribute tag :members))

335 336 337 338 339 340 341 342
(defsubst semantic-tag-type (tag)
  "Return the value of the `:type' attribute of TAG.
For a function it would be the data type of the return value.
For a variable, it is the storage type of that variable.
For a data type, the type is the style of datatype, such as
struct or union."
  (semantic-tag-get-attribute tag :type))

343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
(defun semantic-tag-with-position-p (tag)
  "Return non-nil if TAG has positional information."
  (and (semantic-tag-p tag)
       (let ((o (semantic-tag-overlay tag)))
	 (or (and (semantic-overlay-p o)
		  (semantic-overlay-live-p o))
             (arrayp o)))))

(defun semantic-equivalent-tag-p (tag1 tag2)
  "Compare TAG1 and TAG2 and return non-nil if they are equivalent.
Use `equal' on elements the name, class, and position.
Use this function if tags are being copied and regrouped to test
for if two tags represent the same thing, but may be constructed
of different cons cells."
  (and (equal (semantic-tag-name tag1) (semantic-tag-name tag2))
       (semantic-tag-of-class-p tag1 (semantic-tag-class tag2))
       (or (and (not (semantic-tag-overlay tag1))
		(not (semantic-tag-overlay tag2)))
	   (and (semantic-tag-overlay tag1)
		(semantic-tag-overlay tag2)
		(equal (semantic-tag-bounds tag1)
		       (semantic-tag-bounds tag2))))))


(defun semantic-tag-similar-with-subtags-p (tag1 tag2 &rest ignorable-attributes)
  "Test to see if TAG1 and TAG2 are similar.
Uses `semantic-tag-similar-p' but also recurses through sub-tags, such
as argument lists and type members.
Optional argument IGNORABLE-ATTRIBUTES is passed down to
`semantic-tag-similar-p'."
Chong Yidong's avatar
Chong Yidong committed
373 374
  ;; DEPRECATE THIS.
  (semantic-tag-similar-p tag1 tag2 ignorable-attributes))
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472

(defun semantic-tag-of-type-p (tag type)
  "Compare TAG's type against TYPE.  Non nil if equivalent.
TYPE can be a string, or a tag of class 'type.
This can be complex since some tags might have a :type that is a tag,
while other tags might just have a string.  This function will also be
return true of TAG's type is compared directly to the declaration of a
data type."
  (let* ((tagtype (semantic-tag-type tag))
	 (tagtypestring (cond ((stringp tagtype)
			       tagtype)
			      ((and (semantic-tag-p tagtype)
				    (semantic-tag-of-class-p tagtype 'type))
			       (semantic-tag-name tagtype))
			      (t "")))
	 (typestring (cond ((stringp type)
			    type)
			   ((and (semantic-tag-p type)
				 (semantic-tag-of-class-p type 'type))
			    (semantic-tag-name type))
			   (t "")))
	 )
    (and
     tagtypestring
     (or
      ;; Matching strings (input type is string)
      (and (stringp type)
	   (string= tagtypestring type))
      ;; Matching strings (tag type is string)
      (and (stringp tagtype)
	   (string= tagtype typestring))
      ;; Matching tokens, and the type of the type is the same.
      (and (string= tagtypestring typestring)
	   (if (and (semantic-tag-type tagtype) (semantic-tag-type type))
	       (equal (semantic-tag-type tagtype) (semantic-tag-type type))
	     t))
      ))
    ))

(defun semantic-tag-type-compound-p (tag)
  "Return non-nil the type of TAG is compound.
Compound implies a structure or similar data type.
Returns the list of tag members if it is compound."
  (let* ((tagtype (semantic-tag-type tag))
	 )
    (when (and (semantic-tag-p tagtype)
	       (semantic-tag-of-class-p tagtype 'type))
      ;; We have the potential of this being a nifty compound type.
      (semantic-tag-type-members tagtype)
      )))

(defun semantic-tag-faux-p (tag)
  "Return non-nil if TAG is a FAUX tag.
FAUX tags are created to represent a construct that is
not known to exist in the code.

Example: When the class browser sees methods to a class, but
cannot find the class, it will create a faux tag to represent the
class to store those methods."
  (semantic--tag-get-property tag :faux-flag))

;;; Tag creation
;;

;; Is this function still necessary?
(defun semantic-tag-make-plist (args)
  "Create a property list with ARGS.
Args is a property list of the form (KEY1 VALUE1 ... KEYN VALUEN).
Where KEY is a symbol, and VALUE is the value for that symbol.
The return value will be a new property list, with these KEY/VALUE
pairs eliminated:

  - KEY associated to nil VALUE.
  - KEY associated to an empty string VALUE.
  - KEY associated to a zero VALUE."
  (let (plist key val)
    (while args
      (setq key  (car args)
            val  (nth 1 args)
            args (nthcdr 2 args))
      (or (member val '("" nil))
          (and (numberp val) (zerop val))
          (setq plist (cons key (cons val plist)))))
    ;; It is not useful to reverse the new plist.
    plist))

(defsubst semantic-tag (name class &rest attributes)
  "Create a generic semantic tag.
NAME is a string representing the name of this tag.
CLASS is the symbol that represents the class of tag this is,
such as 'variable, or 'function.
ATTRIBUTES is a list of additional attributes belonging to this tag."
  (list name class (semantic-tag-make-plist attributes) nil nil))

(defsubst semantic-tag-new-variable (name type &optional default-value &rest attributes)
  "Create a semantic tag of class 'variable.
NAME is the name of this variable.
TYPE is a string or semantic tag representing the type of this variable.
Glenn Morris's avatar
Glenn Morris committed
473 474 475
Optional DEFAULT-VALUE is a string representing the default value of this
variable.  ATTRIBUTES is a list of additional attributes belonging to this
tag."
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
  (apply 'semantic-tag name 'variable
         :type type
         :default-value default-value
         attributes))

(defsubst semantic-tag-new-function (name type arg-list &rest attributes)
  "Create a semantic tag of class 'function.
NAME is the name of this function.
TYPE is a string or semantic tag representing the type of this function.
ARG-LIST is a list of strings or semantic tags representing the
arguments of this function.
ATTRIBUTES is a list of additional attributes belonging to this tag."
  (apply 'semantic-tag name 'function
         :type type
         :arguments arg-list
         attributes))

(defsubst semantic-tag-new-type (name type members parents &rest attributes)
  "Create a semantic tag of class 'type.
NAME is the name of this type.
TYPE is a string or semantic tag representing the type of this type.
MEMBERS is a list of strings or semantic tags representing the
elements that make up this type if it is a composite type.
PARENTS is a cons cell.  (EXPLICIT-PARENTS . INTERFACE-PARENTS)
EXPLICIT-PARENTS can be a single string (Just one parent) or a
list of parents (in a multiple inheritance situation).  It can also
be nil.
INTERFACE-PARENTS is a list of strings representing the names of
all INTERFACES, or abstract classes inherited from.  It can also be
nil.
This slot can be interesting because the form:
     ( nil \"string\")
is a valid parent where there is no explicit parent, and only an
interface.
ATTRIBUTES is a list of additional attributes belonging to this tag."
  (apply 'semantic-tag name 'type
         :type type
         :members members
         :superclasses (car parents)
         :interfaces (cdr parents)
         attributes))

(defsubst semantic-tag-new-include (name system-flag &rest attributes)
  "Create a semantic tag of class 'include.
NAME is the name of this include.
SYSTEM-FLAG represents that we were able to identify this include as belonging
to the system, as opposed to belonging to the local project.
ATTRIBUTES is a list of additional attributes belonging to this tag."
  (apply 'semantic-tag name 'include
         :system-flag system-flag
         attributes))

(defsubst semantic-tag-new-package (name detail &rest attributes)
  "Create a semantic tag of class 'package.
NAME is the name of this package.
DETAIL is extra information about this package, such as a location where
it can be found.
ATTRIBUTES is a list of additional attributes belonging to this tag."
  (apply 'semantic-tag name 'package
         :detail detail
         attributes))

(defsubst semantic-tag-new-code (name detail &rest attributes)
  "Create a semantic tag of class 'code.
NAME is a name for this code.
DETAIL is extra information about the code.
ATTRIBUTES is a list of additional attributes belonging to this tag."
  (apply 'semantic-tag name 'code
         :detail detail
         attributes))

(defsubst semantic-tag-set-faux (tag)
  "Set TAG to be a new FAUX tag.
FAUX tags represent constructs not found in the source code.
You can identify a faux tag with `semantic-tag-faux-p'"
  (semantic--tag-put-property tag :faux-flag t))

(defsubst semantic-tag-set-name (tag name)
  "Set TAG name to NAME."
  (setcar tag name))

Paul Eggert's avatar
Paul Eggert committed
557
;;; TAG Proxies
Chong Yidong's avatar
Chong Yidong committed
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
;;
;; A new kind of tag is a TAG PROXY.  These are tags that have some
;; minimal number of features set, such as name and class, but have a
;; marker in them that indicates how to complete them.
;;
;; To make the tags easier to view, the proxy is stored as custom
;; symbol that is not in the global obarray, but has properties set on
;; it.  This prevents saving of massive amounts of proxy data.
(defun semantic-create-tag-proxy (function data)
  "Create a tag proxy symbol.
FUNCTION will be used to resolve the proxy.  It should take 3
two arguments, DATA and TAG.  TAG is a proxy tag that needs
to be resolved, and DATA is the DATA passed into this function.
DATA is data to help resolve the proxy.  DATA can be an EIEIO object,
such that FUNCTION is a method.
Paul Eggert's avatar
Paul Eggert committed
573
FUNCTION should return a list of tags, preferably one tag."
Chong Yidong's avatar
Chong Yidong committed
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
  (let ((sym (make-symbol ":tag-proxy")))
    (put sym 'proxy-function function)
    (put sym 'proxy-data data)
    sym))

(defun semantic-tag-set-proxy (tag proxy &optional filename)
  "Set TAG to be a proxy.  The proxy can be resolved with PROXY.
This function will also make TAG be a faux tag with
`semantic-tag-set-faux', and possibly set the tag's
:filename with FILENAME.
To create a proxy, see `semantic-create-tag-proxy'."
  (semantic-tag-set-faux tag)
  (semantic--tag-put-property tag :proxy proxy)
  (when filename
    (semantic--tag-put-property tag :filename filename)))

(defun semantic-tag-resolve-proxy (tag)
  "Resolve the proxy in TAG.
The return value is whatever format the proxy was setup as.
It should be a list of complete tags.
If TAG has no proxy, then just return tag."
  (let* ((proxy (semantic--tag-get-property tag :proxy))
	 (function (get proxy 'proxy-function))
	 (data (get proxy 'proxy-data)))
    (if proxy
	(funcall function data tag)
      tag)))

602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
;;; Copying and cloning tags.
;;
(defsubst semantic-tag-clone (tag &optional name)
  "Clone TAG, creating a new TAG.
If optional argument NAME is not nil it specifies a new name for the
cloned tag."
  ;; Right now, TAG is a list.
  (list (or name (semantic-tag-name tag))
        (semantic-tag-class tag)
        (copy-sequence (semantic-tag-attributes tag))
        (copy-sequence (semantic-tag-properties tag))
        (semantic-tag-overlay tag)))

(defun semantic-tag-copy (tag &optional name keep-file)
  "Return a copy of TAG unlinked from the originating buffer.
If optional argument NAME is non-nil it specifies a new name for the
copied tag.
If optional argument KEEP-FILE is non-nil, and TAG was linked to a
buffer, the originating buffer file name is kept in the `:filename'
property of the copied tag.
Glenn Morris's avatar
Glenn Morris committed
622
If KEEP-FILE is a string, and the originating buffer is NOT available,
623
then KEEP-FILE is stored on the `:filename' property.
624
This runs the tag hook `unlink-copy-hook'."
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
  ;; Right now, TAG is a list.
  (let ((copy (semantic-tag-clone tag name)))

    ;; Keep the filename if needed.
    (when keep-file
      (semantic--tag-put-property
       copy :filename (or (semantic-tag-file-name copy)
			  (and (stringp keep-file)
			       keep-file)
			  )))

    (when (semantic-tag-with-position-p tag)
      ;; Convert the overlay to a vector, effectively 'unlinking' the tag.
      (semantic--tag-set-overlay
       copy (vector (semantic-tag-start copy) (semantic-tag-end copy)))

      ;; Force the children to be copied also.
      ;;(let ((chil (semantic--tag-copy-list
      ;;	     (semantic-tag-components-with-overlays tag)
      ;;	     keep-file)))
      ;;;; Put the list into TAG.
      ;;)

      ;; Call the unlink-copy hook.  This should tell tools that
      ;; this tag is not part of any buffer.
      (when (semantic-overlay-p (semantic-tag-overlay tag))
	(semantic--tag-run-hooks copy 'unlink-copy-hook))
      )
    copy))

;;(defun semantic--tag-copy-list (tags &optional keep-file)
;;  "Make copies of TAGS and return the list of TAGS."
;;  (let ((out nil))
;;    (dolist (tag tags out)
;;      (setq out (cons (semantic-tag-copy tag nil keep-file)
;;		      out))
;;      )))

(defun semantic--tag-copy-properties (tag1 tag2)
  "Copy private properties from TAG1 to TAG2.
Return TAG2.
This function is for internal use only."
  (let ((plist (semantic-tag-properties tag1)))
    (while plist
      (semantic--tag-put-property tag2 (car plist) (nth 1 plist))
      (setq plist (nthcdr 2 plist)))
    tag2))

;;; DEEP COPIES
;;
(defun semantic-tag-deep-copy-one-tag (tag &optional filter)
  "Make a deep copy of TAG, applying FILTER to each child-tag.
Chong Yidong's avatar
Chong Yidong committed
677 678 679
No properties are copied except for :filename.
Overlay will be a vector.
FILTER takes TAG as an argument, and should return a `semantic-tag'.
680 681 682 683
It is safe for FILTER to modify the input tag and return it."
  (when (not filter) (setq filter 'identity))
  (when (not (semantic-tag-p tag))
    (signal 'wrong-type-argument (list tag 'semantic-tag-p)))
Chong Yidong's avatar
Chong Yidong committed
684 685 686 687 688 689 690 691 692 693 694
  (let ((ol (semantic-tag-overlay tag))
	(fn (semantic-tag-file-name tag)))
    (funcall filter (list (semantic-tag-name tag)
			  (semantic-tag-class tag)
			  (semantic--tag-deep-copy-attributes
			   (semantic-tag-attributes tag) filter)
			  ;; Only copy the filename property
			  (when fn (list :filename fn))
			  ;; Only setup a vector if we had an overlay.
			  (when ol (vector (semantic-tag-start tag)
					   (semantic-tag-end tag)))))))
695 696 697 698

(defun semantic--tag-deep-copy-attributes (attrs &optional filter)
  "Make a deep copy of ATTRS, applying FILTER to each child-tag.

Glenn Morris's avatar
Glenn Morris committed
699
It is safe to modify ATTR, and return a permutation of that list.
700 701 702 703 704 705 706 707 708 709 710 711

FILTER takes TAG as an argument, and should returns a semantic-tag.
It is safe for FILTER to modify the input tag and return it."
  (when (car attrs)
    (when (not (symbolp (car attrs))) (error "Bad Attribute List in tag"))
    (cons (car attrs)
          (cons (semantic--tag-deep-copy-value (nth 1 attrs) filter)
                (semantic--tag-deep-copy-attributes (nthcdr 2 attrs) filter)))))

(defun semantic--tag-deep-copy-value (value &optional filter)
  "Make a deep copy of VALUE, applying FILTER to each child-tag.

Glenn Morris's avatar
Glenn Morris committed
712
It is safe to modify VALUE, and return a permutation of that list.
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730

FILTER takes TAG as an argument, and should returns a semantic-tag.
It is safe for FILTER to modify the input tag and return it."
  (cond
   ;; Another tag.
   ((semantic-tag-p value)
    (semantic-tag-deep-copy-one-tag value filter))

   ;; A list of more tags
   ((and (listp value) (semantic-tag-p (car value)))
    (semantic--tag-deep-copy-tag-list value filter))

   ;; Some arbitrary data.
   (t value)))

(defun semantic--tag-deep-copy-tag-list (tags &optional filter)
  "Make a deep copy of TAGS, applying FILTER to each child-tag.

Glenn Morris's avatar
Glenn Morris committed
731
It is safe to modify the TAGS list, and return a permutation of that list.
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807

FILTER takes TAG as an argument, and should returns a semantic-tag.
It is safe for FILTER to modify the input tag and return it."
  (when (car tags)
    (if (semantic-tag-p (car tags))
        (cons (semantic-tag-deep-copy-one-tag (car tags) filter)
              (semantic--tag-deep-copy-tag-list (cdr tags) filter))
      (cons (car tags) (semantic--tag-deep-copy-tag-list (cdr tags) filter)))))


;;; Standard Tag Access
;;

;;; Common
;;
(defsubst semantic-tag-modifiers (tag)
  "Return the value of the `:typemodifiers' attribute of TAG."
  (semantic-tag-get-attribute tag :typemodifiers))

(defun semantic-tag-docstring (tag &optional buffer)
  "Return the documentation of TAG.
That is the value defined by the `:documentation' attribute.
Optional argument BUFFER indicates where to get the text from.
If not provided, then only the POSITION can be provided.

If you want to get documentation for languages that do not store
the documentation string in the tag itself, use
`semantic-documentation-for-tag' instead."
  (let ((p (semantic-tag-get-attribute tag :documentation)))
    (cond
     ((stringp p) p) ;; it is the doc string.

     ((semantic-lex-token-with-text-p p)
      (semantic-lex-token-text p))

     ((and (semantic-lex-token-without-text-p p)
	   buffer)
      (with-current-buffer buffer
	(semantic-lex-token-text (car (semantic-lex p (1+ p))))))

     (t nil))))

;;; Generic attributes for tags of any class.
;;
(defsubst semantic-tag-named-parent (tag)
  "Return the parent of TAG.
That is the value of the `:parent' attribute.
If a definition can occur outside an actual parent structure, but
refers to that parent by name, then the :parent attribute should be used."
  (semantic-tag-get-attribute tag :parent))

;;; Tags of class `type'

(defun semantic-tag-type-superclasses (tag)
  "Return the list of superclass names of the type that TAG describes."
  (let ((supers (semantic-tag-get-attribute tag :superclasses)))
    (cond ((stringp supers)
	   ;; If we have a string, make it a list.
	   (list supers))
	  ((semantic-tag-p supers)
	   ;; If we have one tag, return just the name.
	   (list (semantic-tag-name supers)))
	  ((and (consp supers) (semantic-tag-p (car supers)))
	   ;; If we have a tag list, then return the names.
	   (mapcar (lambda (s) (semantic-tag-name s))
		   supers))
	  ((consp supers)
	   ;; A list of something, return it.
	   supers))))

(defun semantic--tag-find-parent-by-name (name supers)
  "Find the superclass NAME in the list of SUPERS.
If a simple search doesn't do it, try splitting up the names
in SUPERS."
  (let ((stag nil))
    (setq stag (semantic-find-first-tag-by-name name supers))
808

809
    (when (not stag)
810
      (require 'semantic/analyze/fcn)
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
      (dolist (S supers)
	(let* ((sname (semantic-tag-name S))
	       (splitparts (semantic-analyze-split-name sname))
	       (parts (if (stringp splitparts)
			  (list splitparts)
			(nreverse splitparts))))
	  (when (string= name (car parts))
	    (setq stag S))
	  )))

    stag))

(defun semantic-tag-type-superclass-protection (tag parentstring)
  "Return the inheritance protection in TAG from PARENTSTRING.
PARENTSTRING is the name of the parent being inherited.
The return protection is a symbol, 'public, 'protection, and 'private."
  (let ((supers (semantic-tag-get-attribute tag :superclasses)))
    (cond ((stringp supers)
	   'public)
	  ((semantic-tag-p supers)
	   (let ((prot (semantic-tag-get-attribute supers :protection)))
	     (or (cdr (assoc prot '(("public" . public)
				    ("protected" . protected)
				    ("private" . private))))
		 'public)))
	  ((and (consp supers) (stringp (car supers)))
	   'public)
	  ((and (consp supers) (semantic-tag-p (car supers)))
	   (let* ((stag (semantic--tag-find-parent-by-name parentstring supers))
		  (prot (when stag
			  (semantic-tag-get-attribute stag :protection))))
	     (or (cdr (assoc prot '(("public" . public)
				    ("protected" . protected)
				    ("private" . private))))
		 (when (equal prot "unspecified")
		   (if (semantic-tag-of-type-p tag "class")
		       'private
		     'public))
		 'public))))
    ))

(defsubst semantic-tag-type-interfaces (tag)
  "Return the list of interfaces of the type that TAG describes."
  ;; @todo - make this as robust as the above.
  (semantic-tag-get-attribute tag :interfaces))

;;; Tags of class `function'
;;
(defsubst semantic-tag-function-arguments (tag)
  "Return the arguments of the function that TAG describes.
That is the value of the `:arguments' attribute."
  (semantic-tag-get-attribute tag :arguments))

(defsubst semantic-tag-function-throws (tag)
  "Return the exceptions the function that TAG describes can throw.
That is the value of the `:throws' attribute."
  (semantic-tag-get-attribute tag :throws))

(defsubst semantic-tag-function-parent (tag)
  "Return the parent of the function that TAG describes.
That is the value of the `:parent' attribute.
A function has a parent if it is a method of a class, and if the
Chong Yidong's avatar
Chong Yidong committed
873
function does not appear in body of its parent class."
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
  (semantic-tag-named-parent tag))

(defsubst semantic-tag-function-destructor-p (tag)
  "Return non-nil if TAG describes a destructor function.
That is the value of the `:destructor-flag' attribute."
  (semantic-tag-get-attribute tag :destructor-flag))

(defsubst semantic-tag-function-constructor-p (tag)
  "Return non-nil if TAG describes a constructor function.
That is the value of the `:constructor-flag' attribute."
  (semantic-tag-get-attribute tag :constructor-flag))

;;; Tags of class `variable'
;;
(defsubst semantic-tag-variable-default (tag)
  "Return the default value of the variable that TAG describes.
That is the value of the attribute `:default-value'."
  (semantic-tag-get-attribute tag :default-value))

(defsubst semantic-tag-variable-constant-p (tag)
  "Return non-nil if the variable that TAG describes is a constant.
That is the value of the attribute `:constant-flag'."
  (semantic-tag-get-attribute tag :constant-flag))

;;; Tags of class `include'
;;
(defsubst semantic-tag-include-system-p (tag)
  "Return non-nil if the include that TAG describes is a system include.
That is the value of the attribute `:system-flag'."
  (semantic-tag-get-attribute tag :system-flag))

(define-overloadable-function semantic-tag-include-filename (tag)
  "Return a filename representation of TAG.
The default action is to return the `semantic-tag-name'.
Some languages do not use full filenames in their include statements.
Paul Eggert's avatar
Paul Eggert committed
909
Override this method to translate the code representation
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
into a filename.  (A relative filename if necessary.)

See `semantic-dependency-tag-file' to expand an include
tag to a full file name.")

(defun semantic-tag-include-filename-default (tag)
  "Return a filename representation of TAG.
Returns `semantic-tag-name'."
  (semantic-tag-name tag))

;;; Tags of class `code'
;;
(defsubst semantic-tag-code-detail (tag)
  "Return detail information from code that TAG describes.
That is the value of the attribute `:detail'."
  (semantic-tag-get-attribute tag :detail))

;;; Tags of class `alias'
;;
(defsubst semantic-tag-new-alias (name meta-tag-class value &rest attributes)
  "Create a semantic tag of class alias.
NAME is a name for this alias.
META-TAG-CLASS is the class of the tag this tag is an alias.
VALUE is the aliased definition.
ATTRIBUTES is a list of additional attributes belonging to this tag."
  (apply 'semantic-tag name 'alias
         :aliasclass meta-tag-class
         :definition value
         attributes))

(defsubst semantic-tag-alias-class (tag)
  "Return the class of tag TAG is an alias."
  (semantic-tag-get-attribute tag :aliasclass))

(define-overloadable-function semantic-tag-alias-definition (tag)
  "Return the definition TAG is an alias.
The returned value is a tag of the class that
`semantic-tag-alias-class' returns for TAG.
The default is to return the value of the :definition attribute.
Return nil if TAG is not of class 'alias."
  (when (semantic-tag-of-class-p tag 'alias)
    (:override
     (semantic-tag-get-attribute tag :definition))))

;;; Language Specific Tag access via overload
;;
956
;;;###autoload
957 958 959 960
(define-overloadable-function semantic-tag-components (tag)
  "Return a list of components for TAG.
A Component is a part of TAG which itself may be a TAG.
Examples include the elements of a structure in a
961
tag of class 'type, or the list of arguments to a
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
tag of class 'function."
  )

(defun semantic-tag-components-default (tag)
  "Return a list of components for TAG.
Perform the described task in `semantic-tag-components'."
  (cond ((semantic-tag-of-class-p tag 'type)
	 (semantic-tag-type-members tag))
	((semantic-tag-of-class-p tag 'function)
	 (semantic-tag-function-arguments tag))
	(t nil)))

(define-overloadable-function semantic-tag-components-with-overlays (tag)
  "Return the list of top level components belonging to TAG.
Children are any sub-tags which contain overlays.

Default behavior is to get `semantic-tag-components' in addition
to the components of an anonymous types (if applicable.)

Note for language authors:
  If a mode defines a language tag that has tags in it with overlays
you should still return them with this function.
Ignoring this step will prevent several features from working correctly."
  )

(defun semantic-tag-components-with-overlays-default (tag)
  "Return the list of top level components belonging to TAG.
Children are any sub-tags which contain overlays.
The default action collects regular components of TAG, in addition
Glenn Morris's avatar
Glenn Morris committed
991
to any components belonging to an anonymous type."
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
  (let ((explicit-children (semantic-tag-components tag))
	(type (semantic-tag-type tag))
	(anon-type-children nil)
	(all-children nil))
    ;; Identify if this tag has an anonymous structure as
    ;; its type.  This implies it may have children with overlays.
    (when (and type (semantic-tag-p type))
      (setq anon-type-children (semantic-tag-components type))
      ;; Add anonymous children
      (while anon-type-children
	(when (semantic-tag-with-position-p (car anon-type-children))
	  (setq all-children (cons (car anon-type-children) all-children)))
	(setq anon-type-children (cdr anon-type-children))))
    ;; Add explicit children
    (while explicit-children
      (when (semantic-tag-with-position-p (car explicit-children))
	(setq all-children (cons (car explicit-children) all-children)))
      (setq explicit-children (cdr explicit-children)))
    ;; Return
    (nreverse all-children)))

(defun semantic-tag-children-compatibility (tag &optional positiononly)
  "Return children of TAG.
If POSITIONONLY is nil, use `semantic-tag-components'.
If POSITIONONLY is non-nil, use `semantic-tag-components-with-overlays'.
DO NOT use this fcn in new code.  Use one of the above instead."
  (if positiononly
      (semantic-tag-components-with-overlays tag)
    (semantic-tag-components tag)))

;;; Tag Region
;;
;; A Tag represents a region in a buffer.  You can narrow to that tag.
;;
(defun semantic-narrow-to-tag (&optional tag)
  "Narrow to the region specified by the bounds of TAG.
See `semantic-tag-bounds'."
  (interactive)
  (if (not tag) (setq tag (semantic-current-tag)))
  (narrow-to-region (semantic-tag-start tag)
		    (semantic-tag-end tag)))

(defmacro semantic-with-buffer-narrowed-to-current-tag (&rest body)
  "Execute BODY with the buffer narrowed to the current tag."
  `(save-restriction
     (semantic-narrow-to-tag (semantic-current-tag))
     ,@body))
(put 'semantic-with-buffer-narrowed-to-current-tag 'lisp-indent-function 0)
(add-hook 'edebug-setup-hook
	  (lambda ()
	    (def-edebug-spec semantic-with-buffer-narrowed-to-current-tag
	      (def-body))))

(defmacro semantic-with-buffer-narrowed-to-tag (tag &rest body)
  "Narrow to TAG, and execute BODY."
  `(save-restriction
     (semantic-narrow-to-tag ,tag)
     ,@body))
(put 'semantic-with-buffer-narrowed-to-tag 'lisp-indent-function 1)
(add-hook 'edebug-setup-hook
	  (lambda ()
	    (def-edebug-spec semantic-with-buffer-narrowed-to-tag
	      (def-body))))

;;; Tag Hooks
;;
;; Semantic may want to provide special hooks when specific operations
;; are about to happen on a given tag.  These routines allow for hook
;; maintenance on a tag.

;; Internal global variable used to manage tag hooks.  For example,
;; some implementation of `remove-hook' checks that the hook variable
;; is `default-boundp'.
(defvar semantic--tag-hook-value)

(defun semantic-tag-add-hook (tag hook function &optional append)
  "Onto TAG, add to the value of HOOK the function FUNCTION.
FUNCTION is added (if necessary) at the beginning of the hook list
unless the optional argument APPEND is non-nil, in which case
FUNCTION is added at the end.
HOOK should be a symbol, and FUNCTION may be any valid function.
See also the function `add-hook'."
  (let ((semantic--tag-hook-value (semantic--tag-get-property tag hook)))
    (add-hook 'semantic--tag-hook-value function append)
    (semantic--tag-put-property tag hook semantic--tag-hook-value)
    semantic--tag-hook-value))

(defun semantic-tag-remove-hook (tag hook function)
  "Onto TAG, remove from the value of HOOK the function FUNCTION.
HOOK should be a symbol, and FUNCTION may be any valid function.  If
FUNCTION isn't the value of HOOK, or, if FUNCTION doesn't appear in
the list of hooks to run in HOOK, then nothing is done.
See also the function `remove-hook'."
  (let ((semantic--tag-hook-value (semantic--tag-get-property tag hook)))
    (remove-hook 'semantic--tag-hook-value function)
    (semantic--tag-put-property tag hook semantic--tag-hook-value)
    semantic--tag-hook-value))

(defun semantic--tag-run-hooks (tag hook &rest args)
  "Run for TAG all expressions saved on the property HOOK.
Each hook expression must take at least one argument, the TAG.
For any given situation, additional ARGS may be passed."
  (let ((semantic--tag-hook-value (semantic--tag-get-property tag hook))
	(arglist (cons tag args)))
    (condition-case err
	;; If a hook bombs, ignore it!  Usually this is tied into
	;; some sort of critical system.
	(apply 'run-hook-with-args 'semantic--tag-hook-value arglist)
      (error (message "Error: %S" err)))))

;;; Tags and Overlays
;;
;; Overlays are used so that we can quickly identify tags from
;; buffer positions and regions using built in Emacs commands.
;;
(defsubst semantic--tag-unlink-list-from-buffer (tags)
  "Convert TAGS from using an overlay to using an overlay proxy.
This function is for internal use only."
  (mapcar 'semantic--tag-unlink-from-buffer tags))

(defun semantic--tag-unlink-from-buffer (tag)
  "Convert TAG from using an overlay to using an overlay proxy.
This function is for internal use only."
  (when (semantic-tag-p tag)
    (let ((o (semantic-tag-overlay tag)))
      (when (semantic-overlay-p o)
        (semantic--tag-set-overlay
         tag (vector (semantic-overlay-start o)
                     (semantic-overlay-end o)))
        (semantic-overlay-delete o))
      ;; Look for a link hook on TAG.
      (semantic--tag-run-hooks tag 'unlink-hook)
      ;; Fix the sub-tags which contain overlays.
      (semantic--tag-unlink-list-from-buffer
       (semantic-tag-components-with-overlays tag)))))

(defsubst semantic--tag-link-list-to-buffer (tags)
  "Convert TAGS from using an overlay proxy to using an overlay.
This function is for internal use only."
1131
  (mapc 'semantic--tag-link-to-buffer tags))
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151

(defun semantic--tag-link-to-buffer (tag)
  "Convert TAG from using an overlay proxy to using an overlay.
This function is for internal use only."
  (when (semantic-tag-p tag)
    (let ((o (semantic-tag-overlay tag)))
      (when (and (vectorp o) (= (length o) 2))
        (setq o (semantic-make-overlay (aref o 0) (aref o 1)
                                       (current-buffer)))
        (semantic--tag-set-overlay tag o)
        (semantic-overlay-put o 'semantic tag)
        ;; Clear the :filename property
        (semantic--tag-put-property tag :filename nil))
      ;; Look for a link hook on TAG.
      (semantic--tag-run-hooks tag 'link-hook)
      ;; Fix the sub-tags which contain overlays.
      (semantic--tag-link-list-to-buffer
       (semantic-tag-components-with-overlays tag)))))

(defun semantic--tag-unlink-cache-from-buffer ()
Paul Eggert's avatar
Paul Eggert committed
1152
  "Convert all tags in the current cache to use overlay proxies.
1153
This function is for internal use only."
1154
  (require 'semantic)
1155 1156 1157 1158 1159 1160 1161 1162 1163
  (semantic--tag-unlink-list-from-buffer
   ;; @todo- use fetch-tags-fast?
   (semantic-fetch-tags)))

(defvar semantic--buffer-cache)

(defun semantic--tag-link-cache-to-buffer ()
  "Convert all tags in the current cache to use overlays.
This function is for internal use only."
1164
  (require 'semantic)
1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339
  (condition-case nil
      ;; In this unique case, we cannot call the usual toplevel fn.
      ;; because we don't want a reparse, we want the old overlays.
      (semantic--tag-link-list-to-buffer
       semantic--buffer-cache)
    ;; Recover when there is an error restoring the cache.
    (error (message "Error recovering tag list")
           (semantic-clear-toplevel-cache)
           nil)))

;;; Tag Cooking
;;
;; Raw tags from a parser follow a different positional format than
;; those used in the buffer cache.  Raw tags need to be cooked into
;; semantic cache friendly tags for use by the masses.
;;
(defsubst semantic--tag-expanded-p (tag)
  "Return non-nil if TAG is expanded.
This function is for internal use only.
See also the function `semantic--expand-tag'."
  ;; In fact a cooked tag is actually a list of cooked tags
  ;; because a raw tag can be expanded in several cooked ones!
  (when (consp tag)
    (while (and (semantic-tag-p (car tag))
                (vectorp (semantic-tag-overlay (car tag))))
      (setq tag (cdr tag)))
    (null tag)))

(defvar semantic-tag-expand-function nil
  "Function used to expand a tag.
It is passed each tag production, and must return a list of tags
derived from it, or nil if it does not need to be expanded.

Languages with compound definitions should use this function to expand
from one compound symbol into several.  For example, in C or Java the
following definition is easily parsed into one tag:

  int a, b;

This function should take this compound tag and turn it into two tags,
one for A, and the other for B.")
(make-variable-buffer-local 'semantic-tag-expand-function)

(defun semantic--tag-expand (tag)
  "Convert TAG from a raw state to a cooked state, and expand it.
Returns a list of cooked tags.

  The parser returns raw tags with positional data START END at the
end of the tag data structure (a list for now).  We convert it from
that to a cooked state that uses an overlay proxy, that is, a vector
\[START END].

  The raw tag is changed with side effects and maybe expanded in
several derived tags when the variable `semantic-tag-expand-function'
is set.

This function is for internal use only."
  (if (semantic--tag-expanded-p tag)
      ;; Just return TAG if it is already expanded (by a grammar
      ;; semantic action), or if it isn't recognized as a valid
      ;; semantic tag.
      tag

    ;; Try to cook the tag.  This code will be removed when tag will
    ;; be directly created with the right format.
    (condition-case nil
        (let ((ocdr (semantic--tag-overlay-cdr tag)))
          ;; OCDR contains the sub-list of TAG whose car is the
          ;; OVERLAY part of TAG. That is, a list (OVERLAY START END).
          ;; Convert it into an overlay proxy ([START END]).
          (semantic--tag-set-overlay
           tag (vector (nth 1 ocdr) (nth 2 ocdr)))
          ;; Remove START END positions at end of tag.
          (setcdr ocdr nil)
          ;; At this point (length TAG) must be 5!
          ;;(unless (= (length tag) 5)
          ;;  (error "Tag expansion failed"))
          )
      (error
       (message "A Rule must return a single tag-line list!")
       (debug tag)
       nil))
    ;; Expand based on local configuration
    (if semantic-tag-expand-function
        (or (funcall semantic-tag-expand-function tag)
            (list tag))
      (list tag))))

;; Foreign tags
;;
(defmacro semantic-foreign-tag-invalid (tag)
  "Signal that TAG is an invalid foreign tag."
  `(signal 'wrong-type-argument '(semantic-foreign-tag-p ,tag)))

(defsubst semantic-foreign-tag-p (tag)
  "Return non-nil if TAG is a foreign tag.
That is, a tag unlinked from the originating buffer, which carries the
originating buffer file name, and major mode."
  (and (semantic-tag-p tag)
       (semantic--tag-get-property tag :foreign-flag)))

(defsubst semantic-foreign-tag-check (tag)
  "Check that TAG is a valid foreign tag.
Signal an error if not."
  (or (semantic-foreign-tag-p tag)
      (semantic-foreign-tag-invalid tag)))

(defun semantic-foreign-tag (&optional tag)
  "Return a copy of TAG as a foreign tag, or nil if it can't be done.
TAG defaults to the tag at point in current buffer.
See also `semantic-foreign-tag-p'."
  (or tag (setq tag (semantic-current-tag)))
  (when (semantic-tag-p tag)
    (let ((ftag (semantic-tag-copy tag nil t))
	  ;; Do extra work for the doc strings, since this is a
	  ;; common use case.
	  (doc (condition-case nil
		   (semantic-documentation-for-tag tag)
		 (error nil))))
      ;; A foreign tag must carry its originating buffer file name!
      (when (semantic--tag-get-property ftag :filename)
        (semantic--tag-put-property ftag :mode (semantic-tag-mode tag))
	(semantic--tag-put-property ftag :documentation doc)
        (semantic--tag-put-property ftag :foreign-flag t)
        ftag))))

;; High level obtain/insert foreign tag overloads
(define-overloadable-function semantic-obtain-foreign-tag (&optional tag)
  "Obtain a foreign tag from TAG.
TAG defaults to the tag at point in current buffer.
Return the obtained foreign tag or nil if failed."
  (semantic-foreign-tag tag))

(defun semantic-insert-foreign-tag-default (foreign-tag)
  "Insert FOREIGN-TAG into the current buffer.
The default behavior assumes the current buffer is a language file,
and attempts to insert a prototype/function call."
  ;; Long term goal: Have a mechanism for a tempo-like template insert
  ;; for the given tag.
  (insert (semantic-format-tag-prototype foreign-tag)))

(define-overloadable-function semantic-insert-foreign-tag (foreign-tag)
  "Insert FOREIGN-TAG into the current buffer.
Signal an error if FOREIGN-TAG is not a valid foreign tag.
This function is overridable with the symbol `insert-foreign-tag'."
  (semantic-foreign-tag-check foreign-tag)
  (:override)
  (message (semantic-format-tag-summarize foreign-tag)))

;;; Support log modes here
(define-mode-local-override semantic-insert-foreign-tag
  log-edit-mode (foreign-tag)
  "Insert foreign tags into log-edit mode."
  (insert (concat "(" (semantic-format-tag-name foreign-tag) "): ")))

(define-mode-local-override semantic-insert-foreign-tag
  change-log-mode (foreign-tag)
  "Insert foreign tags into log-edit mode."
  (insert (concat "(" (semantic-format-tag-name foreign-tag) "): ")))

;;; Compatibility
;;
(defconst semantic-token-version
  semantic-tag-version)
(defconst semantic-token-incompatible-version
  semantic-tag-incompatible-version)

(defsubst semantic-token-type-parent (tag)
  "Return the parent of the type that TAG describes.
The return value is a list.  A value of nil means no parents.
The `car' of the list is either the parent class, or a list
of parent classes.  The `cdr' of the list is the list of
interfaces, or abstract classes which are parents of TAG."
  (cons (semantic-tag-get-attribute tag :superclasses)
        (semantic-tag-type-interfaces tag)))
Chong Yidong's avatar
Chong Yidong committed
1340

1341 1342 1343
(make-obsolete 'semantic-token-type-parent
	       "\
use `semantic-tag-type-superclass' \
1344
and `semantic-tag-type-interfaces' instead" "23.2")
1345 1346

(semantic-alias-obsolete 'semantic-tag-make-assoc-list
1347
                         'semantic-tag-make-plist "23.2")
1348 1349

(semantic-varalias-obsolete 'semantic-expand-nonterminal
1350
                            'semantic-tag-expand-function "23.2")
1351 1352 1353

(provide 'semantic/tag)

1354 1355
;; Local variables:
;; generated-autoload-file: "loaddefs.el"
1356
;; generated-autoload-load-name: "semantic/tag"
1357 1358
;; End:

1359
;;; semantic/tag.el ends here