1 ;;; db-typecache.el --- Manage Datatypes
3 ;; Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
5 ;; Author: Eric M. Ludlam <eric@siege-engine.com>
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24 ;; Manage a datatype cache.
26 ;; For typed languages like C++ collect all known types from various
27 ;; headers, merge namespaces, and expunge duplicates.
29 ;; It is likely this feature will only be needed for C/C++.
32 (require 'semantic
/db
)
33 (require 'semantic
/db-find
)
34 (require 'semantic
/analyze
/fcn
)
36 ;; For semantic-find-tags-by-* macros
37 (eval-when-compile (require 'semantic
/find
))
39 (declare-function data-debug-insert-thing
"data-debug")
40 (declare-function data-debug-new-buffer
"data-debug")
41 (declare-function semantic-sort-tags-by-name-then-type-increasing
"semantic/sort")
42 (declare-function semantic-scope-tag-clone-with-scope
"semantic/scope")
49 (defclass semanticdb-typecache
()
50 ((filestream :initform nil
52 "Fully sorted/merged list of tags within this buffer.")
53 (includestream :initform nil
55 "Fully sorted/merged list of tags from this file's includes list.")
58 "The searchable tag stream for this cache.
59 NOTE: Can I get rid of this? Use a hashtable instead?")
60 (dependants :initform nil
62 "Any other object that is dependent on typecache results.
63 Said object must support `semantic-reset' methods.")
64 ;; @todo - add some sort of fast-hash.
65 ;; @note - Rebuilds in large projects already take a while, and the
66 ;; actual searches are pretty fast. Really needed?
68 "Structure for maintaining a typecache.")
70 (defmethod semantic-reset ((tc semanticdb-typecache
))
71 "Reset the object IDX."
72 (oset tc filestream nil
)
73 (oset tc includestream nil
)
77 (mapc 'semantic-reset
(oref tc dependants
))
78 (oset tc dependants nil
)
81 (defmethod semanticdb-typecache-notify-reset ((tc semanticdb-typecache
))
82 "Do a reset from a notify from a table we depend on."
83 (oset tc includestream nil
)
84 (mapc 'semantic-reset
(oref tc dependants
))
85 (oset tc dependants nil
)
88 (defmethod semanticdb-partial-synchronize ((tc semanticdb-typecache
)
90 "Reset the typecache based on a partial reparse."
91 (when (semantic-find-tags-by-class 'include new-tags
)
92 (oset tc includestream nil
)
93 (mapc 'semantic-reset
(oref tc dependants
))
94 (oset tc dependants nil
)
97 (when (semantic-find-tags-by-class 'type new-tags
)
99 (oset tc filestream nil
)
100 t
;; Return true, our core file tags have changed in a relavant way.
106 (defun semanticdb-typecache-add-dependant (dep)
107 "Add into the local typecache a dependant DEP."
108 (let* ((table semanticdb-current-table
)
109 ;;(idx (semanticdb-get-table-index table))
110 (cache (semanticdb-get-typecache table
))
112 (object-add-to-list cache
'dependants dep
)))
114 (defun semanticdb-typecache-length (thing)
117 (cond ((semanticdb-typecache-child-p thing
)
118 (length (oref thing stream
)))
119 ((semantic-tag-p thing
)
120 (length (semantic-tag-type-members thing
)))
121 ((and (listp thing
) (semantic-tag-p (car thing
)))
128 (defmethod semanticdb-get-typecache ((table semanticdb-abstract-table
))
129 "Retrieve the typecache from the semanticdb TABLE.
130 If there is no table, create one, and fill it in."
131 (semanticdb-refresh-table table
)
132 (let* ((idx (semanticdb-get-table-index table
))
133 (cache (oref idx type-cache
))
136 ;; Make sure we have a cache object in the DB index.
138 ;; The object won't change as we fill it with stuff.
139 (setq cache
(semanticdb-typecache (semanticdb-full-filename table
)))
140 (oset idx type-cache cache
))
144 (defmethod semanticdb-have-typecache-p ((table semanticdb-abstract-table
))
145 "Return non-nil (the typecache) if TABLE has a pre-calculated typecache."
146 (let* ((idx (semanticdb-get-table-index table
)))
147 (oref idx type-cache
)))
150 ;;; DATABASE TYPECACHE
152 ;; A full database can cache the types across its files.
154 ;; Unlike file based caches, this one is a bit simpler, and just needs
155 ;; to get reset when a table gets updated.
158 (defclass semanticdb-database-typecache
(semanticdb-abstract-db-cache)
159 ((stream :initform nil
161 "The searchable tag stream for this cache.")
163 "Structure for maintaining a typecache.")
165 (defmethod semantic-reset ((tc semanticdb-database-typecache
))
166 "Reset the object IDX."
170 (defmethod semanticdb-synchronize ((cache semanticdb-database-typecache
)
172 "Synchronize a CACHE with some NEW-TAGS."
175 (defmethod semanticdb-partial-synchronize ((cache semanticdb-database-typecache
)
177 "Synchronize a CACHE with some changed NEW-TAGS."
180 (defmethod semanticdb-get-typecache ((db semanticdb-project-database
))
181 "Retrieve the typecache from the semantic database DB.
182 If there is no table, create one, and fill it in."
183 (semanticdb-cache-get db semanticdb-database-typecache
)
187 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
191 ;; Managing long streams of tags representing data types.
193 (defun semanticdb-typecache-apply-filename (file stream
)
194 "Apply the filename FILE to all tags in STREAM."
197 (setq new
(cons (semantic-tag-copy (car stream
) nil file
)
199 ;The below is handled by the tag-copy fcn.
200 ;(semantic--tag-put-property (car new) :filename file)
201 (setq stream
(cdr stream
)))
205 (defsubst semanticdb-typecache-safe-tag-members
(tag)
206 "Return a list of members for TAG that are safe to permute."
207 (let ((mem (semantic-tag-type-members tag
))
208 (fname (semantic-tag-file-name tag
)))
210 (setq mem
(semanticdb-typecache-apply-filename fname mem
))
211 (copy-sequence mem
))))
213 (defsubst semanticdb-typecache-safe-tag-list
(tags table
)
214 "Make the tag list TAGS found in TABLE safe for the typecache.
215 Adds a filename and copies the tags."
216 (semanticdb-typecache-apply-filename
217 (semanticdb-full-filename table
)
220 (defun semanticdb-typecache-faux-namespace (name members
)
221 "Create a new namespace tag with NAME and a set of MEMBERS.
222 The new tag will be a faux tag, used as a placeholder in a typecache."
223 (let ((tag (semantic-tag-new-type name
"namespace" members nil
)))
224 ;; Make sure we mark this as a fake tag.
225 (semantic-tag-set-faux tag
)
228 (defun semanticdb-typecache-merge-streams (cache1 cache2
)
229 "Merge into CACHE1 and CACHE2 together. The Caches will be merged in place."
230 (if (or (and (not cache1
) (not cache2
))
231 (and (not (cdr cache1
)) (not cache2
))
232 (and (not cache1
) (not (cdr cache2
))))
233 ;; If all caches are empty OR
234 ;; cache1 is length 1 and no cache2 OR
235 ;; no cache1 and length 1 cache2
237 ;; then just return the cache, and skip all this merging stuff.
240 ;; Assume we always have datatypes, as this typecache isn't really
241 ;; useful without a typed language.
242 (require 'semantic
/sort
)
243 (let ((S (semantic-sort-tags-by-name-then-type-increasing
244 ;; I used to use append, but it copied cache1 but not cache2.
245 ;; Since sort was permuting cache2, I already had to make sure
246 ;; the caches were permute-safe. Might as well use nconc here.
247 (nconc cache1 cache2
)))
252 ;; With all the tags in order, we can loop over them, and when
253 ;; two have the same name, we can either throw one away, or construct
254 ;; a fresh new tag merging the items together.
256 (setq prev
(car ans
))
259 ;; CASE 1 - First item
262 (not (string= (semantic-tag-name next
)
263 (semantic-tag-name prev
))))
264 (setq ans
(cons next ans
))
265 ;; ELSE - We have a NAME match.
266 (setq type
(semantic-tag-type next
))
267 (if (or (semantic-tag-of-type-p prev type
) ; Are they the same datatype
268 (semantic-tag-faux-p prev
)
269 (semantic-tag-faux-p next
) ; or either a faux tag?
271 ;; Same Class, we can do a merge.
273 ((and (semantic-tag-of-class-p next
'type
)
274 (string= type
"namespace"))
275 ;; Namespaces - merge the children together.
277 (semanticdb-typecache-faux-namespace
278 (semantic-tag-name prev
) ; - they are the same
279 (semanticdb-typecache-merge-streams
280 (semanticdb-typecache-safe-tag-members prev
)
281 (semanticdb-typecache-safe-tag-members next
))
284 ((semantic-tag-prototype-p next
)
285 ;; NEXT is a prototype... so keep previous.
286 nil
; - keep prev, do nothing
288 ((semantic-tag-prototype-p prev
)
289 ;; PREV is a prototype, but not next.. so keep NEXT.
290 ;; setcar - set by side-effect on top of prev
294 ;;(message "Don't know how to merge %s. Keeping first entry." (semantic-tag-name next))
296 ;; Not same class... but same name
297 ;(message "Same name, different type: %s, %s!=%s"
298 ; (semantic-tag-name next)
299 ; (semantic-tag-type next)
300 ; (semantic-tag-type prev))
301 (setq ans
(cons next ans
))
306 ;;; Refresh / Query API
308 ;; Queries that can be made for the typecache.
309 (define-overloadable-function semanticdb-expand-nested-tag
(tag)
310 "Expand TAG from fully qualified names.
311 If TAG has fully qualified names, expand it to a series of nested
315 (defmethod semanticdb-typecache-file-tags ((table semanticdb-abstract-table
))
316 "No tags available from non-file based tables."
319 (defmethod semanticdb-typecache-file-tags ((table semanticdb-table
))
320 "Update the typecache for TABLE, and return the file-tags.
321 File-tags are those that belong to this file only, and excludes
323 (let* (;(idx (semanticdb-get-table-index table))
324 (cache (semanticdb-get-typecache table
))
327 ;; Make sure our file-tags list is up to date.
328 (when (not (oref cache filestream
))
329 (let ((tags (semantic-find-tags-by-class 'type table
))
332 (setq tags
(semanticdb-typecache-safe-tag-list tags table
))
334 (push (semanticdb-expand-nested-tag T
) exptags
))
335 (oset cache filestream
(semanticdb-typecache-merge-streams exptags nil
)))))
338 (oref cache filestream
)
341 (defmethod semanticdb-typecache-include-tags ((table semanticdb-abstract-table
))
342 "No tags available from non-file based tables."
345 (defmethod semanticdb-typecache-include-tags ((table semanticdb-table
))
346 "Update the typecache for TABLE, and return the merged types from the include tags.
347 Include-tags are the tags brought in via includes, all merged together into
349 (let* ((cache (semanticdb-get-typecache table
))
352 ;; Make sure our file-tags list is up to date.
353 (when (not (oref cache includestream
))
354 (let (;; Calc the path first. This will have a nice side -effect of
355 ;; getting the cache refreshed if a refresh is needed. Most of the
356 ;; time this value is itself cached, so the query is fast.
357 (incpath (semanticdb-find-translate-path table nil
))
359 ;; Get the translated path, and extract all the type tags, then merge
360 ;; them all together.
362 ;; don't include ourselves in this crazy list.
363 (when (and i
(not (eq i table
))
364 ;; @todo - This eieio fcn can be slow! Do I need it?
365 ;; (semanticdb-table-child-p i)
368 (semanticdb-typecache-merge-streams
370 ;; Getting the cache from this table will also cause this
371 ;; file to update it's cache from it's decendants.
373 ;; In theory, caches are only built for most includes
374 ;; only once (in the loop before this one), so this ends
375 ;; up being super fast as we edit our file.
377 (semanticdb-typecache-file-tags i
))))
381 (oset cache includestream incstream
)))
384 (oref cache includestream
)
388 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
393 (define-overloadable-function semanticdb-typecache-find
(type &optional path find-file-match
)
394 "Search the typecache for TYPE in PATH.
395 If type is a string, split the string, and search for the parts.
396 If type is a list, treat the type as a pre-split string.
397 PATH can be nil for the current buffer, or a semanticdb table.
398 FIND-FILE-MATCH is non-nil to force all found tags to be loaded into a buffer.")
400 (defun semanticdb-typecache-find-default (type &optional path find-file-match
)
401 "Default implementation of `semanticdb-typecache-find'.
402 TYPE is the datatype to find.
403 PATH is the search path, which should be one table object.
404 If FIND-FILE-MATCH is non-nil, then force the file belonging to the
405 found tag to be loaded."
406 (if (not (and (featurep 'semantic
/db
) semanticdb-current-database
))
407 nil
;; No DB, no search
409 (semanticdb-typecache-find-method (or path semanticdb-current-table
)
410 type find-file-match
))))
412 (defun semanticdb-typecache-find-by-name-helper (name table
)
413 "Find the tag with NAME in TABLE, which is from a typecache.
414 If more than one tag has NAME in TABLE, we will prefer the tag that
416 (let* ((names (semantic-find-tags-by-name name table
))
417 (nmerge (semanticdb-typecache-merge-streams names nil
))
418 (types (semantic-find-tags-by-class 'type nmerge
)))
419 (or (car-safe types
) (car-safe nmerge
))))
421 (defmethod semanticdb-typecache-find-method ((table semanticdb-abstract-table
)
422 type find-file-match
)
423 "Search the typecache in TABLE for the datatype TYPE.
424 If type is a string, split the string, and search for the parts.
425 If type is a list, treat the type as a pre-split string.
426 If FIND-FILE-MATCH is non-nil, then force the file belonging to the
427 found tag to be loaded."
428 ;; convert string to a list.
429 (when (stringp type
) (setq type
(semantic-analyze-split-name type
)))
430 (when (stringp type
) (setq type
(list type
)))
432 ;; Search for the list in our typecache.
433 (let* ((file (semanticdb-typecache-file-tags table
))
434 (inc (semanticdb-typecache-include-tags table
))
443 (calculated-scope nil
)
445 ;; 1) Find first symbol in the two master lists and then merge
446 ;; the found streams.
448 ;; We stripped duplicates, so these will be super-fast!
449 (setq f-ans
(semantic-find-first-tag-by-name (car type
) file
))
450 (setq i-ans
(semantic-find-first-tag-by-name (car type
) inc
))
451 (if (and f-ans i-ans
)
453 ;; This trick merges the two identified tags, making sure our lists are
454 ;; complete. The second find then gets the new 'master' from the list of 2.
455 (setq ans
(semanticdb-typecache-merge-streams (list f-ans
) (list i-ans
)))
456 (setq ans
(semantic-find-first-tag-by-name (car type
) ans
))
459 ;; The answers are already sorted and merged, so if one misses,
460 ;; no need to do any special work.
461 (setq ans
(or f-ans i-ans
)))
463 ;; 2) Loop over the remaining parts.
464 (while (and type notdone
)
466 ;; For pass > 1, stream will be non-nil, so do a search, otherwise
467 ;; ans is from outside the loop.
469 (setq ans
(semanticdb-typecache-find-by-name-helper (car type
) stream
))
471 ;; NOTE: The below test to make sure we get a type is only relevant
472 ;; for the SECOND pass or later. The first pass can only ever
473 ;; find a type/namespace because everything else is excluded.
475 ;; If this is not the last entry from the list, then it
476 ;; must be a type or a namespace. Lets double check.
479 ;; From above, there is only one tag in ans, and we prefer
481 (when (not (semantic-tag-of-class-p ans
'type
))
486 (push ans calculated-scope
)
488 ;; Track most recent file.
489 (setq thisfile
(semantic-tag-file-name ans
))
490 (when (and thisfile
(stringp thisfile
))
491 (setq lastfile thisfile
))
493 ;; If we have a miss, exit, otherwise, update the stream to
494 ;; the next set of members.
497 (setq stream
(semantic-tag-type-members ans
)))
503 (if (or type
(not notdone
))
504 ;; If there is stuff left over, then we failed. Just return
508 ;; We finished, so return everything.
510 (if (and find-file-match lastfile
)
511 ;; This won't liven up the tag since we have a copy, but
512 ;; we ought to be able to get there and go to the right line.
513 (find-file-noselect lastfile
)
514 ;; We don't want to find-file match, so instead lets
515 ;; push the filename onto the return tag.
517 (setq lastans
(semantic-tag-copy lastans nil lastfile
))
518 ;; We used to do the below, but we would erroneously be putting
519 ;; attributes on tags being shred with other lists.
520 ;;(semantic--tag-put-property lastans :filename lastfile)
524 (if (and lastans calculated-scope
)
526 ;; Put our discovered scope into the tag if we have a tag
528 (require 'semantic
/scope
)
529 (semantic-scope-tag-clone-with-scope
530 lastans
(reverse (cdr calculated-scope
))))
536 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
538 ;;; BRUTISH Typecache
540 ;; Routines for a typecache that crosses all tables in a given database
541 ;; for a matching major-mode.
542 (defmethod semanticdb-typecache-for-database ((db semanticdb-project-database
)
544 "Return the typecache for the project database DB.
545 If there isn't one, create it.
547 (let ((lmode (or mode major-mode
))
548 (cache (semanticdb-get-typecache db
))
551 (dolist (table (semanticdb-get-database-tables db
))
552 (when (eq lmode
(oref table
:major-mode
))
554 (semanticdb-typecache-merge-streams
557 (semanticdb-typecache-file-tags table
))))
559 (oset cache stream stream
)
562 (defun semanticdb-typecache-refresh-for-buffer (buffer)
563 "Refresh the typecache for BUFFER."
564 (with-current-buffer buffer
565 (let* ((tab semanticdb-current-table
)
566 ;(idx (semanticdb-get-table-index tab))
567 (tc (semanticdb-get-typecache tab
)))
568 (semanticdb-typecache-file-tags tab
)
569 (semanticdb-typecache-include-tags tab
)
575 (defun semanticdb-typecache-complete-flush ()
576 "Flush all typecaches referenced by the current buffer."
578 (let* ((path (semanticdb-find-translate-path nil nil
)))
580 (oset P pointmax nil
)
581 (semantic-reset (semanticdb-get-typecache P
)))))
583 (defun semanticdb-typecache-dump ()
584 "Dump the typecache for the current buffer."
586 (require 'data-debug
)
587 (let* ((start (current-time))
588 (tc (semanticdb-typecache-refresh-for-buffer (current-buffer)))
591 (data-debug-new-buffer "*TypeCache ADEBUG*")
592 (message "Calculating Cache took %.2f seconds."
593 (semantic-elapsed-time start end
))
595 (data-debug-insert-thing tc
"]" "")
599 (defun semanticdb-db-typecache-dump ()
600 "Dump the typecache for the current buffer's database."
602 (require 'data-debug
)
603 (let* ((tab semanticdb-current-table
)
604 (idx (semanticdb-get-table-index tab
))
605 (junk (oset idx type-cache nil
)) ;; flush!
606 (start (current-time))
607 (tc (semanticdb-typecache-for-database (oref tab parent-db
)))
610 (data-debug-new-buffer "*TypeCache ADEBUG*")
611 (message "Calculating Cache took %.2f seconds."
612 (semantic-elapsed-time start end
))
614 (data-debug-insert-thing tc
"]" "")
618 (provide 'semantic
/db-typecache
)
621 ;; generated-autoload-file: "loaddefs.el"
622 ;; generated-autoload-load-name: "semantic/db-typecache"
625 ;; arch-tag: cd7c37a8-2006-4ead-a037-977ffe7e7624
626 ;;; semanticdb-typecache.el ends here