4 ;; SUMMARY: Support routines for C++ inheritance browsing.
5 ;; USAGE: GNU Emacs Lisp Library
6 ;; KEYWORDS: c, oop, tools
11 ;; ORIG-DATE: 7-Dec-89
12 ;; LAST-MOD: 9-Jun-99 at 18:03:29 by Bob Weiner
14 ;; Copyright (C) 1990-1999 BeOpen.com
15 ;; See the file BR-COPY for license information.
17 ;; This file is part of the OO-Browser.
22 ;;; ************************************************************************
23 ;;; Other required Elisp libraries
24 ;;; ************************************************************************
26 (mapcar 'require '(br-lib hypb br-c-ft))
28 ;;; ************************************************************************
29 ;;; User visible variables
30 ;;; ************************************************************************
32 (defconst c++-class-name-modifier
33 "\\([_a-zA-Z][_a-zA-Z0-9]*[ \t\n\r]+\\)?"
34 "Regexp for an optional #define keyword preceding the name of a class within a class declaration.
35 Some class libraries use this technique.")
37 (defvar c++-class-keyword
38 (concat "\\(class\\|struct\\|union\\)[ \t\n\r]+"
39 c++-class-name-modifier)
40 "*Keyword regexp preceding a C++ class declaration or definition.")
42 (defvar c++-lib-search-dirs nil
43 "List of directories below which C++ Library source files are found.
44 Subdirectories of Library source are also searched. A Library is a stable
47 (defvar c++-sys-search-dirs nil
48 "List of directories below which C++ System source files are found.
49 Subdirectories of System source are also searched. A System class is one
50 that is not yet reusable and is likely to change before release.")
53 (defconst c++-narrow-view-to-class nil
54 "*Non-nil means narrow buffer to just the matching class definition when displayed.")
56 ;;; ************************************************************************
57 ;;; Internal functions
58 ;;; ************************************************************************
60 (defun c++-get-classes-from-source (filename &optional skip-tags
62 "Scans FILENAME and returns cons of class list with parents-class alist.
63 Handles multiple inheritance. Assumes file existence and readability have
65 With optional SKIP-TAGS non-nil, does not compute and store lookup tags
66 for member definitions. If SKIP-TAGS is nil, normally a cleanup
67 function is called after scanning the members. SKIP-TAGS-CLEANUP
68 non-nil suppresses this action."
69 (let (class-name-end classes class has-parents open-brace-point
70 parents parent-cons signatures)
71 (funcall br-view-file-function filename)
72 (setq buffer-read-only nil)
76 (br-buffer-delete-c-comments)
77 (goto-char (point-min))
79 (progn (setq signatures (c++-scan-features))
80 (goto-char (point-min))))
81 (while (re-search-forward c++-class-def-regexp nil t)
84 (match-beginning c++-class-def-derived-grpn)))
85 class-name-end (match-end c++-class-def-name-grpn)
87 ;; Now since we've saved all the match expressions we need
88 ;; from our last regexp match, we can call functions which
89 ;; change the match data below here.
90 class (c++-normalize-class-match t)
91 parent-cons (cons (if has-parents
92 ;; Return parents as a list.
95 (setq classes (cons class classes)
96 parents (cons parent-cons parents))
98 ;; Scan members defined within class
99 (progn (goto-char class-name-end)
100 (if (search-forward "\{" nil t)
101 (progn (setq open-brace-point (point))
103 ;; Move to class close brace but ignore
104 ;; any error if braces are unbalanced.
105 ;; Let the compiler tell the user about
107 (if (condition-case ()
108 (progn (forward-sexp) t)
113 (c++-scan-features-in-class
114 class open-brace-point
118 (c++-output-feature-tags filename signatures)
119 (or skip-tags-cleanup (br-feature-build-htables)))
120 (set-buffer-modified-p nil)
121 (cons classes (delq nil parents))))
123 (defun c++-class-definition-regexp (class &optional regexp-flag)
124 "Return regexp to uniquely match the definition of CLASS name.
125 Optional REGEXP-FLAG non-nil means CLASS has already been quoted for use in a
127 (let ((template-args-regexp (c++-template-args-regexp class)))
129 (if template-args-regexp
130 ;; Only match to a class definition with the same number of
131 ;; template parameters as <class> since some modules use #ifdef
132 ;; to define classes with the same name but a different number
133 ;; of template parameters.
134 (format "\\(template[ \t\n\r]*%s[ \t\n\r]*\\)"
135 template-args-regexp))
137 c++-class-name-modifier
139 (c++-class-non-template-name class)
140 (regexp-quote (c++-class-non-template-name class)))
141 c++-class-name-after)))
143 (defun c++-template-args-regexp (class)
144 "Return a regexp matching the number of template args in CLASS or nil when there are no such arguments."
145 (if (string-match "\<[^!]+\>\\'" class)
146 (let* ((param "[^,<>]+")
147 (comma (concat "," param)))
150 (function (lambda (c) (if (= c ?\,) comma)))
151 (substring class (1+ (match-beginning 0))
155 ;; Remove only *trailing* template identifiers when class name is looked up.
156 (defun c++-class-non-template-name (class)
157 "Return CLASS name sans any trailing <template> component.
158 Does not remove whitespace from CLASS."
159 (if (and (stringp class) (string-match "\<[^!]+\>\\'" class))
160 (substring class 0 (match-beginning 0))
163 (defun c++-get-class-name (class-name template-signature rename-arguments-flag)
164 "Return a possibly parameterized class identifier built from CLASS-NAME and TEMPLATE-SIGNATURE.
165 If RENAME-ARGUMENTS-FLAG is non-nil, template class argument names are
166 normalized also to T1,T2,T3, etc.
167 TEMPLATE-SIGNATURE may be of any of the following forms:
169 template <class T> => class-name<T>
170 template <class T1, class T2> => class-name<T1,T2>
171 <class T1, class T2> => class-name<T1,T2>
172 <int = 0> => class-name<int>
173 <int size = 0> => class-name<size>."
174 (cond ((null template-signature)
176 ((stringp template-signature)
177 (setq template-signature
178 (if rename-arguments-flag
180 ;; Remove any text prior to template arguments.
181 (if (string-match "\<" template-signature)
182 (setq template-signature
183 (substring template-signature
184 (match-beginning 0))))
185 (c++-normalize-template-arguments template-signature))
186 (c++-template-argument-names template-signature)))
187 (if (null template-signature)
190 (format "%s%s" class-name template-signature))))
191 (t (error "(c++-get-class-name): Second argument, `%s', must be a string or nil."
192 template-signature))))
194 (defun c++-template-argument-names (template-signature)
195 "Return a delimited string of the template argument names from TEMPLATE-SIGNATURE."
196 (if (or (null template-signature)
197 (not (string-match "\<" template-signature)))
198 ;; No type parameters.
200 (setq template-signature (br-delete-space template-signature))
201 (let ((depth 0) (args) (arg ""))
206 (setq depth (1+ depth))
208 (setq args (concat args "\<")))
210 (setq arg (concat arg (char-to-string c))))))
213 (cond ((memq c '(?, ?\>))
215 c++-template-parameter-regexp arg)
216 (setq arg (substring arg
218 c++-template-parameter-grpn)
220 c++-template-parameter-grpn))))
221 (setq args (concat args (br-delete-space arg)
224 (if (eq c ?\>) (setq depth (1- depth))))
225 (t (setq arg (concat arg (char-to-string c))))))
227 (setq depth (1- depth)
228 arg (concat arg (char-to-string c))))
229 (t (setq arg (concat arg (char-to-string c)))))))
233 (defun c++-list-template-arguments (template-signature)
234 "Return a list of the template arguments within TEMPLATE-SIGNATURE."
235 (if (or (null template-signature)
236 (not (string-match "\<" template-signature)))
237 ;; No type parameters.
239 (setq template-signature (br-delete-space template-signature))
240 (let ((depth 0) (args) (arg ""))
245 (setq depth (1+ depth))
247 (setq arg (concat arg (char-to-string c)))))
251 (setq args (cons (br-delete-space arg) args)
254 (setq args (cons (br-delete-space arg) args)
257 (t (setq arg (concat arg (char-to-string c))))))
259 (setq depth (1- depth)
260 arg (concat arg (char-to-string c))))
261 (t (setq arg (concat arg (char-to-string c)))))))
265 (defun c++-normalize-class-match (rename-arguments-flag)
266 "After a regexp match to a class definition, return the matching class name.
267 Class name is normalized for use in OO-Browser lookups.
268 If RENAME-ARGUMENTS-FLAG is non-nil, template class argument names are
269 normalized also to T1,T2,T3, etc."
271 (br-buffer-substring (match-beginning c++-class-def-name-grpn)
272 (match-end c++-class-def-name-grpn))
273 (if (match-beginning c++-class-def-template-grpn)
275 (match-beginning c++-class-def-template-grpn)
276 (match-end c++-class-def-template-grpn)))
277 rename-arguments-flag))
279 (defun c++-normalize-template-arguments (class)
280 "Return CLASS with any template arguments renamed to <T> or <T1,T2,T3>."
281 (cond ((null class) nil)
282 ((not (string-match "\<" class))
283 ;; No type parameters.
284 (br-delete-space class))
285 (t (setq class (br-delete-space class))
286 (let ((depth 0) (arg-num 0))
291 (setq depth (1+ depth))
292 (if (= depth 1) "<"))
293 ((zerop depth) (char-to-string c))
296 (setq arg-num (1+ arg-num))
297 (format "T%d," arg-num))
299 (setq arg-num (1+ arg-num)
303 (format "T%d>" arg-num)))))
305 (setq depth (1- depth))
310 (defun c++-scan-parents ()
311 "Return list of parents names from a C++ class definition.
312 Point must be after the colon that begins the parent list and before the
313 first parent entry when this function is called."
314 (let ((parent-list) (again t)
316 (while (and again (re-search-forward c++-parent-regexp nil t))
318 (c++-parse-buffer-template-arguments
320 (br-buffer-substring (match-beginning c++-parent-name-grpn)
321 (match-end c++-parent-name-grpn)))))
322 (if (looking-at (concat c++-comment-regexp "[#,\{\;]"))
323 (goto-char (match-end 0)))
324 (setq again (eq ?, (preceding-char))
325 parent-list (cons parent parent-list)))
326 (nreverse parent-list)))
328 (defun c++-parse-buffer-template-arguments (class)
329 "Return CLASS with any template arguments following point renamed to <T> or <T1,T2,T3>.
330 Leaves point after the closing angle bracket."
331 ;; We need to handle class definitions like this:
332 ;; template <class T> class PtrList : private List<type-name> {}
333 ;; where the parent class is an instantiation of a parameterized class.
334 ;; For now, we change the type name to <T> or <T1,T2,T3> when there are 3
335 ;; parameters, for purposes of class name matching.
339 ;; '("par <class _T1=myclass , class _T2 = you >" "parent"
340 ;; "class<_T1,T2>" "class< __me , int>" "" "<template>"
343 ;; ("par<T1,T2>" "parent" "class<T1,T2>" "class<T1,T2>" "" "<template>"
346 (if (not (eq (following-char) ?\<))
348 (let ((depth 1) (arg-num 0) (args "\<")
352 (setq c (following-char))
354 (setq depth (1+ depth)))
357 (setq arg-num (1+ arg-num)
358 args (concat args (format "T%d," arg-num))))
360 (setq arg-num (1+ arg-num)
363 (setq args (concat args
366 (format "T%d>" arg-num)))))))
368 (setq depth (1- depth)))
370 (setq continue nil))))
371 ;; Move past closing angle bracket.
373 ;; Return class with normalized args.
374 (concat class args))))
376 (defun c++-get-parents-from-source (filename class-name)
377 "Scan source in FILENAME and return list of parents of CLASS-NAME.
378 Assume file existence has already been checked."
379 (or (null class-name)
382 (cdr (c++-get-classes-from-source filename t)))))))
384 (defun c++-select-path (paths-htable-elt &optional feature-p)
385 "Select proper pathname from PATHS-HTABLE-ELT based upon value of optional FEATURE-P.
386 Selection is between path of class definition and path for features associated
388 (let ((elt (cdr paths-htable-elt)))
390 (if feature-p (cdr elt) (car elt))
391 ;; Both paths are the same.
394 (defun c++-set-case (type)
395 "Return string TYPE identifier for use as a class name."
398 (defun c++-set-case-type (class-name)
399 "Return string CLASS-NAME for use as a type identifier."
402 (defun c++-to-class-end ()
403 "Assuming point is at start of class, move to start of line after end of class."
407 (error (progn (or (re-search-forward "^}" nil t)
408 (goto-char (point-max))))))
411 (defalias 'c++-to-comments-begin 'br-c-to-comments-begin)
413 ;;; ************************************************************************
414 ;;; Internal variables
415 ;;; ************************************************************************
417 (defconst c++-template-prefix
418 "\\(template[ \t\n\r]*\<[^\>\;.{}]+\>[ \t\n\r]*\\)?"
419 "Regexp matching a template class or element definition or declaration.
420 Entire expression is an optional match, so it may be added as a conditional
421 expression to other regexps.")
423 (defconst c++-class-name-before
424 (concat "^[ \t]*" c++-template-prefix c++-class-keyword)
425 "Regexp preceding the class name in a class definition.")
427 (defconst c++-comment-regexp "\\([ \t\n\r]*//.*[\n\r]\\|[ \t\n\r]*/\\*.*\\*/\\)*[ \t\n\r]*")
429 (defconst c++-class-name-after
430 (concat c++-comment-regexp "\\([\{:]\\)")
431 "Regexp following the class name in a class definition.
432 Last character matched is either the colon preceding the list of class
433 parents, or the curly brace beginning the class body definition.")
435 (defconst c++-identifier-chars "_~<>a-zA-Z0-9"
436 "String of chars and char ranges that may be used within a C++ or G++ identifier.")
438 (defconst c++-template-identifier-chars "_a-zA-Z0-9"
439 "String of chars and char ranges that may be used within a standard C++ template identifier.
440 This excludes the template arguments.")
442 (defconst c++-return-type-chars "_<>a-zA-Z0-9"
443 "String of chars and char ranges that may be used within a C++ or G++ return type identifier.")
445 ;; Modified on 3/28/95 to handle C++ names with multiple template
446 ;; parameters, e.g. class<T1,T2,T3>.
447 (defconst c++-identifier (concat
448 "\\([_~\<a-zA-Z][" c++-template-identifier-chars "]*"
449 "[ \t\n\r]*\<[^\>\;{}]+[ \t\n\r\>]*\>\\|[_~\<a-zA-Z]["
450 c++-identifier-chars "]*\\)")
451 "Regular expression matching a C++ or G++ identifier.")
453 (defconst c++-class-def-regexp
454 (concat c++-class-name-before c++-identifier c++-class-name-after)
455 "Regular expression used to match to class definitions in source text.
456 Class name identifier is grouping `c++-class-def-name-grpn'. Optional
457 class template parameter signature is grouping `c++-class-def-template-grpn'.
458 `:' derived class indicator begins grouping `c++-class-def-derived-grpn,'
459 unless the class is not derived, in which case this grouping begins with
462 (defconst c++-class-def-template-grpn 1)
463 (defconst c++-class-def-name-grpn 4)
464 (defconst c++-class-def-derived-grpn 6)
466 (defconst c++-lang-prefix "c++-"
467 "Prefix string that starts \"br-c++.el\" symbol names.")
469 (defconst c++-non-template-identifier
470 (concat "\\([_~\<a-zA-Z][" c++-template-identifier-chars "]*"
471 "[ \t\n\r]*\\|[_~\<a-zA-Z][" c++-identifier-chars "]*\\)")
472 "Match a C++ identifier up until the start of any template arguments.")
474 (defconst c++-parent-regexp
475 (concat c++-comment-regexp
476 "\\(\\(public\\|private\\|protected\\|virtual\\)[ \t\n\r]+"
477 "\\(\\(public\\|private\\|protected\\|virtual\\)[ \t\n\r]+\\)?\\)?"
478 ;; match c++-identifier up until start of any template arguments
479 c++-non-template-identifier)
480 "Parent identifier (sans any template arguments) is group `c++-parent-name-grpn'.")
482 (defconst c++-parent-name-grpn 6)
484 (defconst c++-template-parameter-regexp
485 "\\([^= \t\n\r]+\\)[ \t\n\r]*\\(=[^,\>]+\\)?\\'"
486 "Regexp matching a single C++ <template> specifier argument name within a
487 single template argument. For example in `class T', T is the parameter name
488 and in `int size = 0', size is the parameter name. The parameter name is
489 grouping `c++-template-parameter-grpn'.")
491 (defconst c++-template-parameter-grpn 1)
493 ;; Ellemtel C++ recommendations specify that inline definition files should
494 ;; use the suffix ".icc" and other people use ".I" for such files, so those
495 ;; suffixes are included here.
496 (defconst c++-src-file-regexp
497 "[^.]\\.\\([chCH][xX][xX]\\|[chCH][chpCHP]?[pP]?\\|[iI][cC][cC]\\|I\\|[iI][nN][cC]\\)$"
498 "Regular expression matching a unique part of C++ source or header file name and no others.")
500 (defconst c++-header-file-regexp
501 "\\.\\([hH][xX][xX]\\|[hH][hpHP]?[pP]?\\|[iI][nN][cC]\\)$"
502 "Regular expression matching the . and suffix of a C++ or C header file.")
504 (defvar c++-children-htable nil
505 "Htable whose elements are of the form: (LIST-OF-CHILD-CLASSES . CLASS-NAME).
506 Used to traverse C++ inheritance graph. `br-build-children-htable' builds
508 (defvar c++-parents-htable nil
509 "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
510 Used to traverse C++ inheritance graph. `br-build-parents-htable' builds
512 (defvar c++-paths-htable nil
513 "Htable whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
514 FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
515 `br-build-paths-htable' builds this list.")
518 (defvar c++-lib-parents-htable nil
519 "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
520 Only classes from stable software libraries are used to build the list.")
521 (defvar c++-lib-paths-htable nil
522 "Htable whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
523 FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
524 Only classes from stable software libraries are used to build the list.")
526 (defvar c++-sys-parents-htable nil
527 "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
528 Only classes from systems that are likely to change are used to build the list.")
529 (defvar c++-sys-paths-htable nil
530 "Alist whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
531 FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
532 Only classes from systems that are likely to change are used to build the
535 (defvar c++-lib-prev-search-dirs nil
536 "Used to check if `c++-lib-classes-htable' must be regenerated.")
537 (defvar c++-sys-prev-search-dirs nil
538 "Used to check if `c++-sys-classes-htable' must be regenerated.")
540 (defvar c++-env-spec nil
541 "Non-nil value means Environment specification has been given but not yet built.
542 Nil means current Environment has been built, though it may still require updating.")