cedet/semantic/debug.el,
[bpt/emacs.git] / lisp / cedet / semantic / analyze / debug.el
CommitLineData
a6de3d1a
CY
1;;; semantic/analyze/debug.el --- Debug the analyzer
2
3;;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.
4
5;; Author: Eric M. Ludlam <zappo@gnu.org>
6
7;; This file is part of GNU Emacs.
8
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.
13
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.
18
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/>.
21
22;;; Commentary:
23;;
24;; Provide a top-order debugging tool for figuring out what's going on with
25;; smart completion and analyzer mode.
26
27(require 'semantic/analyze)
28(require 'semantic/db-typecache)
29
30;;; Code:
31
32(defun semantic-analyze-debug-assist ()
33 "Debug semantic analysis at the current point."
34 (interactive)
35 (let ((actualfcn (fetch-overload 'semantic-analyze-current-context))
36 (ctxt (semantic-analyze-current-context))
37 )
38 ;; What to show.
39 (if actualfcn
40 (message "Mode %s does not use the default analyzer."
41 major-mode)
42 ;; Debug our context.
43 )
44 (or (semantic-analyzer-debug-test-local-context)
45 (and ctxt (semantic-analyzer-debug-found-prefix ctxt))
46 )
47
48 ))
49
50(defun semantic-analyzer-debug-found-prefix (ctxt)
51 "Debug the prefix found by the analyzer output CTXT."
52 (let* ((pf (oref ctxt prefix))
53 (pft (oref ctxt prefixtypes))
54 (idx 0)
55 (stop nil)
56 (comp (condition-case nil
57 (semantic-analyze-possible-completions ctxt)
58 (error nil)))
59 )
60 (while (and (nth idx pf) (not stop))
61 (let ((pentry (nth idx pf))
62 (ptentry (nth idx pft)))
63 (if (or (stringp pentry) (not ptentry))
64 ;; Found someting ok. stop
65 (setq stop t)
66 (setq idx (1+ idx)))))
67 ;; We found the first non-tag entry. What is the situation?
68 (cond
69 ((and (eq idx 0) (stringp (car pf)))
70 ;; First part, we couldn't find it.
71 (semantic-analyzer-debug-global-symbol ctxt (car pf) comp))
72 ((not (nth (1- idx) pft)) ;; idx can't be 0 here.
73 ;; The previous entry failed to have an identifiable data
74 ;; type, which is a global search.
75 (semantic-analyzer-debug-missing-datatype ctxt idx comp))
76 ((and (nth (1- idx) pft) (stringp (nth idx pf)))
77 ;; Non-first search, didn't find string in known data type.
78 (semantic-analyzer-debug-missing-innertype ctxt idx comp))
79 (t
80 ;; Things are ok?
81 (message "Things look ok."))
82 )))
83
84(defun semantic-analyzer-debug-global-symbol (ctxt prefix comp)
85 "Debug why we can't find the first entry in the CTXT PREFIX.
86Argument COMP are possible completions here."
87 (let ((tab semanticdb-current-table)
88 (finderr nil)
89 (origbuf (current-buffer))
90 )
91 (with-output-to-temp-buffer (help-buffer)
92 (with-current-buffer standard-output
93 (princ "Unable to find prefix ")
94 (princ prefix)
95 (princ ".\n\n")
96
97 ;; NOTE: This line is copied from semantic-analyze-current-context.
98 ;; You will need to update both places.
99 (condition-case err
100 (save-excursion
101 (set-buffer origbuf)
102 (let* ((position (or (cdr-safe (oref ctxt bounds)) (point)))
103 (prefixtypes nil) ; Used as type return
104 (scope (semantic-calculate-scope position))
105 )
106 (semantic-analyze-find-tag-sequence
107 (list prefix "") scope 'prefixtypes)
108 )
109 )
110 (error (setq finderr err)))
111
112 (if finderr
113 (progn
114 (princ "The prefix lookup code threw the following error:\n ")
115 (prin1 finderr)
116 (princ "\n\nTo debug this error you can do this:
117 M-x toggle-debug-on-error RET
118and then re-run the debug analyzer.\n")
119 )
120 ;; No find error, just not found
121 (princ "The prefix ")
122 (princ prefix)
123 (princ " could not be found in the local scope,
124nor in any search tables.\n")
125 )
126 (princ "\n")
127
128 ;; Describe local scope, and why we might not be able to
129 ;; find it.
130 (semantic-analyzer-debug-describe-scope ctxt)
131
132 (semantic-analyzer-debug-show-completions comp)
133
134 (princ "When Semantic cannot find a symbol, it could be because the include
135path was setup incorrectly.\n")
136
137 (semantic-analyzer-debug-insert-include-summary tab)
138
139 ))
140 (semantic-analyzer-debug-add-buttons)
141 ))
142
143(defun semantic-analyzer-debug-missing-datatype (ctxt idx comp)
144 "Debug why we can't find a datatype entry for CTXT prefix at IDX.
145Argument COMP are possible completions here."
146 (let* ((prefixitem (nth idx (oref ctxt prefix)))
147 (dt (nth (1- idx) (oref ctxt prefixtypes)))
148 (tt (semantic-tag-type prefixitem))
149 (tab semanticdb-current-table)
150 )
151 (when dt (error "Missing Datatype debugger is confused"))
152 (with-output-to-temp-buffer (help-buffer)
153 (with-current-buffer standard-output
154 (princ "Unable to find datatype for: \"")
155 (princ (semantic-format-tag-prototype prefixitem))
156 (princ "\".
157Declared type is: ")
158 (when (semantic-tag-p tt)
159 (semantic-analyzer-debug-insert-tag tt)
160 (princ "\nRaw data type is: "))
161 (princ (format "%S" tt))
162 (princ "
163
164Semantic could not find this data type in any of its global tables.
165
166Semantic locates datatypes through either the local scope, or the global
167typecache.
168")
169
170 ;; Describe local scope, and why we might not be able to
171 ;; find it.
172 (semantic-analyzer-debug-describe-scope ctxt '(type))
173
174 ;; Describe the typecache.
175 (princ "\nSemantic creates and maintains a type cache for each buffer.
176If the type is a global type, then it should appear in they typecache.
177To examine the typecache, type:
178
179 M-x semanticdb-typecache-dump RET
180
181Current typecache Statistics:\n")
182 (princ (format " %4d types global in this file\n %4d types from includes.\n"
183 (length (semanticdb-typecache-file-tags tab))
184 (length (semanticdb-typecache-include-tags tab))))
185
186 (princ "\nIf the datatype is not in the typecache, then your include
187path may be incorrect. ")
188
189 (semantic-analyzer-debug-insert-include-summary tab)
190
191 ;; End with-buffer
192 ))
193 (semantic-analyzer-debug-add-buttons)
194 ))
195
196(defun semantic-analyzer-debug-missing-innertype (ctxt idx comp)
197 "Debug why we can't find an entry for CTXT prefix at IDX for known type.
198We need to see if we have possible completions against the entry before
199being too vocal about it.
200Argument COMP are possible completions here."
201 (let* ((prefixitem (nth idx (oref ctxt prefix)))
202 (prevprefix (nth (1- idx) (oref ctxt prefix)))
203 (dt (nth (1- idx) (oref ctxt prefixtypes)))
204 (desired-type (semantic-analyze-type-constraint ctxt))
205 (orig-buffer (current-buffer))
206 (ots (semantic-analyze-tag-type prevprefix
207 (oref ctxt scope)
208 t ; Don't deref
209 ))
210 )
211 (when (not dt) (error "Missing Innertype debugger is confused"))
212 (with-output-to-temp-buffer (help-buffer)
213 (with-current-buffer standard-output
214 (princ "Cannot find prefix \"")
215 (princ prefixitem)
216 (princ "\" in datatype:
217 ")
218 (semantic-analyzer-debug-insert-tag dt)
219 (princ "\n")
220
221 (cond
222 ;; Any language with a namespace.
223 ((string= (semantic-tag-type dt) "namespace")
224 (princ "Semantic may not have found all possible namespaces with
225the name ")
226 (princ (semantic-tag-name dt))
227 (princ ". You can debug the entire typecache, including merged namespaces
228with the command:
229
230 M-x semanticdb-typecache-dump RET")
231 )
232
233 ;; @todo - external declarations??
234 (nil
235 nil)
236
237 ;; A generic explanation
238 (t
239 (princ "\nSemantic has found the datatype ")
240 (semantic-analyzer-debug-insert-tag dt)
241 (if (or (not (semantic-equivalent-tag-p ots dt))
242 (not (save-excursion
243 (set-buffer orig-buffer)
244 (car (semantic-analyze-dereference-metatype
245 ots (oref ctxt scope))))))
246 (let ((lasttype ots)
247 (nexttype (save-excursion
248 (set-buffer orig-buffer)
249 (car (semantic-analyze-dereference-metatype
250 ots (oref ctxt scope))))))
251 (if (eq nexttype lasttype)
252 (princ "\n [ Debugger error trying to help with metatypes ]")
253
254 (if (eq ots dt)
255 (princ "\nwhich is a metatype")
256 (princ "\nwhich is derived from metatype ")
257 (semantic-analyzer-debug-insert-tag lasttype)))
258
259 (princ ".\nThe Metatype stack is:\n")
260 (princ " ")
261 (semantic-analyzer-debug-insert-tag lasttype)
262 (princ "\n")
263 (while (and nexttype
264 (not (eq nexttype lasttype)))
265 (princ " ")
266 (semantic-analyzer-debug-insert-tag nexttype)
267 (princ "\n")
268 (setq lasttype nexttype
269 nexttype
270 (save-excursion
271 (set-buffer orig-buffer)
272 (car (semantic-analyze-dereference-metatype
273 nexttype (oref ctxt scope)))))
274 )
275 (when (not nexttype)
276 (princ " nil\n\n")
277 (princ
278 "Last metatype is nil. This means that semantic cannot derive
279the list of members because the type referred to cannot be found.\n")
280 )
281 )
282 (princ "\nand its list of members.")
283
284 (if (not comp)
285 (progn
286 (princ " Semantic does not know what
287possible completions there are for \"")
288 (princ prefixitem)
289 (princ "\". Examine the known
290members below for more."))
291 (princ " Semantic knows of some
292possible completions for \"")
293 (princ prefixitem)
294 (princ "\".")))
295 )
296 ;; end cond
297 )
298
299 (princ "\n")
300 (semantic-analyzer-debug-show-completions comp)
301
302 (princ "\nKnown members of ")
303 (princ (semantic-tag-name dt))
304 (princ ":\n")
305 (dolist (M (semantic-tag-type-members dt))
306 (princ " ")
307 ;;(princ (semantic-format-tag-prototype M))
308 (semantic-analyzer-debug-insert-tag M)
309 (princ "\n"))
310
311 ;; This doesn't refer to in-type completions.
312 ;;(semantic-analyzer-debug-global-miss-text prefixitem)
313
314 ;; More explanation
315 (when desired-type
316 (princ "\nWhen there are known members that would make good completion
317candidates that are not in the completion list, then the most likely
318cause is a type constraint. Semantic has determined that there is a
319type constraint looking for the type ")
320 (if (semantic-tag-p desired-type)
321 (semantic-analyzer-debug-insert-tag desired-type)
322 (princ (format "%S" desired-type)))
323 (princ "."))
324 ))
325 (semantic-analyzer-debug-add-buttons)
326
327 ))
328
329
330(defun semantic-analyzer-debug-test-local-context ()
331 "Test the local context parsed from the file."
332 (let* ((prefixandbounds (semantic-ctxt-current-symbol-and-bounds (point)))
333 (prefix (car prefixandbounds))
334 (bounds (nth 2 prefixandbounds))
335 )
336 (when (and (or (not prefixandbounds)
337 (not prefix)
338 (not bounds))
339 )
340 (with-output-to-temp-buffer (help-buffer)
341 (with-current-buffer standard-output
342 (princ "Local Context Parser Failed.
343
344If this is unexpected, then there is likely a bug in the Semantic
345local context parser.
346
347Consider debugging the function ")
348 (let ((lcf (fetch-overload 'semantic-ctxt-current-symbol-and-bounds)))
349 (if lcf
350 (princ (symbol-name lcf))
351 (princ "semantic-ctxt-current-symbol-and-bounds,
352or implementing a version specific to ")
353 (princ (symbol-name major-mode))
354 )
355 (princ ".\n"))
356 (semantic-analyzer-debug-add-buttons)
357 t)))
358 ))
359
360;;; General Inserters with help
361;;
362(defun semantic-analyzer-debug-show-completions (comp)
363 "Show the completion list COMP."
364 (if (not comp)
365 (princ "\nNo known possible completions.\n")
366
367 (princ "\nPossible completions are:\n")
368 (dolist (C comp)
369 (princ " ")
370 (cond ((stringp C)
371 (princ C)
372 )
373 ((semantic-tag-p C)
374 (semantic-analyzer-debug-insert-tag C)))
375 (princ "\n"))
376 (princ "\n")))
377
378(defun semantic-analyzer-debug-insert-include-summary (table)
379 "Display a summary of includes for the semanticdb TABLE."
380 (semantic-fetch-tags)
381 (let ((inc (semantic-find-tags-by-class 'include table))
382 ;;(path (semanticdb-find-test-translate-path-no-loading))
383 (unk
384 (save-excursion
385 (set-buffer (semanticdb-get-buffer table))
386 semanticdb-find-lost-includes))
387 (ip
388 (save-excursion
389 (set-buffer (semanticdb-get-buffer table))
390 semantic-dependency-system-include-path))
391 (edeobj
392 (save-excursion
393 (set-buffer (semanticdb-get-buffer table))
394 ede-object))
395 (edeproj
396 (save-excursion
397 (set-buffer (semanticdb-get-buffer table))
398 ede-object-project))
399 )
400
401 (princ "\n\nInclude Path Summary:")
402 (when edeobj
403 (princ "\n\nThis file's project include search is handled by the EDE object:\n")
404 (princ " Buffer Target: ")
405 (princ (object-print edeobj))
406 (princ "\n")
407 (when (not (eq edeobj edeproj))
408 (princ " Buffer Project: ")
409 (princ (object-print edeproj))
410 (princ "\n"))
411 (when edeproj
412 (let ((loc (ede-get-locator-object edeproj)))
413 (princ " Backup Locator: ")
414 (princ (object-print loc))
415 (princ "\n")))
416 )
417
418 (princ "\n\nThe system include path is:\n")
419 (dolist (dir ip)
420 (princ " ")
421 (princ dir)
422 (princ "\n"))
423
424 (princ "\n\nInclude Summary: ")
425 (princ (semanticdb-full-filename table))
426 (princ "\n\n")
427 (princ (format "%s contains %d includes.\n"
428 (file-name-nondirectory
429 (semanticdb-full-filename table))
430 (length inc)))
431 (let ((ok 0)
432 (unknown 0)
433 (unparsed 0)
434 (all 0))
435 (dolist (i inc)
436 (let* ((fileinner (semantic-dependency-tag-file i))
437 (tableinner (when fileinner
438 (semanticdb-file-table-object fileinner t))))
439 (cond ((not fileinner)
440 (setq unknown (1+ unknown)))
441 ((number-or-marker-p (oref tableinner pointmax))
442 (setq ok (1+ ok)))
443 (t
444 (setq unparsed (1+ unparsed))))))
445 (setq all (+ ok unknown unparsed))
446 (when (not (= 0 all))
447 (princ (format " Unknown Includes: %d\n" unknown))
448 (princ (format " Unparsed Includes: %d\n" unparsed))
449 (princ (format " Parsed Includes: %d\n" ok)))
450 )
451
452 ;; Unknowns...
453 (if unk
454 (progn
455 (princ "\nA likely cause of an unfound tag is missing include files.")
456 (semantic-analyzer-debug-insert-tag-list
457 "The following includes were not found" unk)
458
459 (princ "\nYou can fix the include path for ")
460 (princ (symbol-name (oref table major-mode)))
461 (princ " by using this function:
462
463M-x semantic-customize-system-include-path RET
464
465which customizes the mode specific variable for the mode-local
466variable `semantic-dependency-system-include-path'.")
467 )
468
469 (princ "\n No unknown includes.\n"))
470 ))
471
472(defun semantic-analyzer-debug-describe-scope (ctxt &optional classconstraint)
473 "Describe the scope in CTXT for finding a global symbol.
474Optional argument CLASSCONSTRAINT says to output to tags of that class."
475 (let* ((scope (oref ctxt :scope))
476 (parents (oref scope parents))
477 (cc (or classconstraint (oref ctxt prefixclass)))
478 )
479 (princ "\nLocal Scope Information:")
480 (princ "\n * Tag Class Constraint against SCOPE: ")
481 (princ (format "%S" classconstraint))
482
483 (if parents
484 (semantic-analyzer-debug-insert-tag-list
485 " >> Known parent types with possible in scope symbols"
486 parents)
487 (princ "\n * No known parents in current scope."))
488
489 (let ((si (semantic-analyze-tags-of-class-list
490 (oref scope scope) cc))
491 (lv (semantic-analyze-tags-of-class-list
492 (oref scope localvar) cc))
493 )
494 (if si
495 (semantic-analyzer-debug-insert-tag-list
496 " >> Known symbols within the current scope"
497 si)
498 (princ "\n * No known symbols currently in scope."))
499
500 (if lv
501 (semantic-analyzer-debug-insert-tag-list
502 " >> Known symbols that are declared locally"
503 lv)
504 (princ "\n * No known symbols declared locally."))
505 )
506 )
507 )
508
509(defun semantic-analyzer-debug-global-miss-text (name-in)
510 "Use 'princ' to show text describing not finding symbol NAME-IN.
511NAME is the name of the unfound symbol."
512 (let ((name (cond ((stringp name-in)
513 name-in)
514 ((semantic-tag-p name-in)
515 (semantic-format-tag-name name-in))
516 (t (format "%S" name-in)))))
517 (when (not (string= name ""))
518 (princ "\nIf ")
519 (princ name)
520 (princ " is a local variable, argument, or symbol in some
521namespace or class exposed via scoping statements, then it should
522appear in the scope.
523
524Debugging the scope can be done with:
525 M-x semantic-calculate-scope RET
526
527If the prefix is a global symbol, in an included file, then
528your search path may be incomplete.
529"))))
530
531;;; Utils
532;;
533(defun semantic-analyzer-debug-insert-tag-list (text taglist)
534 "Prefixing with TEXT, dump TAGLIST in a help buffer."
535 (princ "\n") (princ text) (princ ":\n")
536
537 (dolist (M taglist)
538 (princ " ")
539 ;;(princ (semantic-format-tag-prototype M))
540 (semantic-analyzer-debug-insert-tag M)
541 (princ "\n"))
542 )
543
544(defun semantic-analyzer-debug-insert-tag (tag &optional parent)
545 "Display a TAG by name, with possible jumpitude.
546PARENT is a possible parent (by nesting) tag."
547 (let ((str (semantic-format-tag-prototype tag parent)))
548 (if (and (semantic-tag-with-position-p tag)
549 (semantic-tag-file-name tag))
550 (insert-button str
551 'mouse-face 'custom-button-pressed-face
552 'tag tag
553 'action
554 `(lambda (button)
555 (let ((buff nil)
556 (pnt nil))
557 (save-excursion
558 (semantic-go-to-tag
559 (button-get button 'tag))
560 (setq buff (current-buffer))
561 (setq pnt (point)))
562 (if (get-buffer-window buff)
563 (select-window (get-buffer-window buff))
564 (pop-to-buffer buff t))
565 (goto-char pnt)
566 (pulse-line-hook-function)))
567 )
568 (princ "\"")
569 (princ str)
570 (princ "\""))
571 ))
572
573(defvar semantic-analyzer-debug-orig nil
574 "The originating buffer for a help button.")
575
576(defun semantic-analyzer-debug-add-buttons ()
577 "Add push-buttons to the *Help* buffer.
578Look for key expressions, and add push-buttons near them."
579 (let ((orig-buffer (make-marker)))
580 (set-marker orig-buffer (point) (current-buffer))
581 (save-excursion
582 ;; Get a buffer ready.
583 (set-buffer "*Help*")
584 (toggle-read-only -1)
585 (goto-char (point-min))
586 (set (make-local-variable 'semantic-analyzer-debug-orig) orig-buffer)
587 ;; First, add do-in buttons to recommendations.
588 (while (re-search-forward "^\\s-*M-x \\(\\(\\w\\|\\s_\\)+\\) " nil t)
589 (let ((fcn (match-string 1)))
590 (when (not (fboundp (intern-soft fcn)))
591 (error "Help Err: Can't find %s" fcn))
592 (end-of-line)
593 (insert " ")
594 (insert-button "[ Do It ]"
595 'mouse-face 'custom-button-pressed-face
596 'do-fcn fcn
597 'action `(lambda (arg)
598 (let ((M semantic-analyzer-debug-orig))
599 (set-buffer (marker-buffer M))
600 (goto-char M))
601 (call-interactively (quote ,(intern-soft fcn))))
602 )
603 ))
604 ;; Do something else?
605
606 ;; Clean up the mess
607 (toggle-read-only 1)
608 (set-buffer-modified-p nil)
609 )))
610
611(provide 'semantic/analyze/debug)
612
613;;; semantic/analyze/debug.el ends here