diff lisp/oobr/br-c++.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 4103f0995bd7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/oobr/br-c++.el	Mon Aug 13 08:45:50 2007 +0200
@@ -0,0 +1,459 @@
+;;!emacs
+;;
+;; FILE:         br-c++.el
+;; SUMMARY:      Support routines for C++ inheritance browsing.
+;; USAGE:        GNU Emacs Lisp Library
+;; KEYWORDS:     c, oop, tools
+;;
+;; AUTHOR:       Bob Weiner
+;; ORG:          Motorola Inc.
+;;
+;; ORIG-DATE:     7-Dec-89
+;; LAST-MOD:     21-Sep-95 at 12:28:56 by Bob Weiner
+;;
+;; Copyright (C) 1989-1995  Free Software Foundation, Inc.
+;; See the file BR-COPY for license information.
+;;
+;; This file is part of the OO-Browser.
+;;
+;; DESCRIPTION:  
+;;
+;;   Properly supports C++ multiple inheritance.
+;;
+;;   See 'c++-class-def-regexp' for regular expression that matches class
+;;   definitions.  You may want to modify it to your own tastes, for
+;;   example if you do not want to consider 'struct' definitions as classes
+;;   even though grammatically, they are.
+;;
+;; DESCRIP-END.
+
+;;; ************************************************************************
+;;; Other required Elisp libraries
+;;; ************************************************************************
+
+(mapcar 'require '(br-lib hypb br-c-ft))
+
+;;; ************************************************************************
+;;; User visible variables
+;;; ************************************************************************
+
+(defvar c++-class-keyword
+  "\\(class\\|struct\\|union\\)[ \t\n]+"
+  "*Keyword regexp preceding a C++ class declaration or definition.")
+
+(defvar   c++-lib-search-dirs nil
+  "List of directories below which C++ Library source files are found.
+Subdirectories of Library source are also searched.  A Library is a stable
+group of classes.")
+
+(defvar   c++-sys-search-dirs nil
+  "List of directories below which C++ System source files are found.
+Subdirectories of System source are also searched.  A System class is one
+that is not yet reusable and is likely to change before release.")
+
+
+(defconst c++-narrow-view-to-class nil
+ "*Non-nil means narrow buffer to just the matching class definition when displayed.")
+
+;;; ************************************************************************
+;;; Internal functions
+;;; ************************************************************************
+
+(defun c++-get-classes-from-source (filename &optional skip-tags
+					     skip-tags-cleanup)
+  "Scans FILENAME and returns cons of class list with parents-class alist.
+Handles multiple inheritance.  Assumes file existence and readability have
+already been checked.
+   With optional SKIP-TAGS non-nil, does not compute and store lookup tags
+for member definitions.  If SKIP-TAGS is nil, normally a cleanup
+function is called after scanning the members.  SKIP-TAGS-CLEANUP
+non-nil suppresses this action."
+  (let ((no-kill (get-file-buffer filename))
+	class-name-end classes class has-parents open-brace-point
+	parents parent-cons signatures)
+    (if no-kill
+	(set-buffer no-kill)
+      (funcall br-view-file-function filename))
+    (save-excursion
+      (save-restriction
+	(widen)
+	(goto-char (point-min))
+	(or skip-tags
+	    (progn (setq signatures (c++-scan-features))
+		   (goto-char (point-min))))
+	(while (re-search-forward c++-class-def-regexp nil t)
+	  (setq has-parents
+		(= ?: (char-after
+		       (match-beginning c++-class-def-derived-grpn)))
+		class-name-end (match-end c++-class-def-name-grpn)
+		;;
+		;; Now since we've saved all the match expressions we need
+		;; from our last regexp match, we can call functions which
+		;; change the match data below here.
+		class (c++-normalize-class-match t)
+		parent-cons (cons (if has-parents
+				      ;; Return parents as a list.
+				      (c++-scan-parents))
+				  class))
+	  ;; Ensure class name not found within a comment
+	  (if (c-within-comment-p)
+	      (progn (search-forward "*/" nil t)
+		     (setq class nil parent-cons nil))
+	    (setq classes (cons class classes)
+		  parents (cons parent-cons parents))
+	    (or skip-tags
+		;; Scan members defined within class
+		(progn (goto-char class-name-end)
+		       (if (search-forward "{" nil t)
+			   (progn (setq open-brace-point (point))
+				  (backward-char)
+				      ;; Move to class close brace but ignore
+				      ;; any error if braces are unbalanced.
+				      ;; Let the compiler tell the user about
+				      ;; this.
+				  (if (condition-case ()
+					  (progn (forward-sexp) t)
+					(error nil))
+				      (setq signatures
+					    (append
+					      signatures
+					      (c++-scan-features-in-class
+					       class open-brace-point
+					       (point)))))))))))))
+    (if skip-tags
+	nil
+      (c++-get-feature-tags buffer-file-name (c++-sort-features signatures))
+      (or skip-tags-cleanup (br-feature-tags-save)))
+    (or no-kill (kill-buffer (current-buffer)))
+    (cons classes (delq nil parents))))
+
+(defun c++-class-definition-regexp (class &optional regexp-flag)
+  "Return regexp to uniquely match the definition of CLASS name.
+Optional REGEXP-FLAG non-nil means CLASS has already been quoted for use in a
+regular expression."
+  (let ((template-args-regexp (c++-template-args-regexp class)))
+    (concat "^[ \t]*"
+	    (if template-args-regexp
+		;; Only match to a class definition with the same number of
+		;; template parameters as <class> since some modules use #ifdef
+		;; to define classes with the same name but a different number
+		;; of template parameters.
+		(format "\\(template[ \t\n\^M]*%s[ \t\n\^M]*\\)"
+			template-args-regexp))
+	    c++-class-keyword
+	    (if regexp-flag
+		(c++-class-non-template-name class)
+	      (regexp-quote (c++-class-non-template-name class)))
+	    c++-class-name-after)))
+
+(defun c++-template-args-regexp (class)
+  "Return a regexp matching the number of template args in CLASS or nil when there are no such arguments."
+  (if (string-match "<[^!]+>\\'" class)
+      (let* ((param "[^,<>]+")
+	     (comma (concat "," param)))
+	(format "<%s%s>"
+		param (mapconcat
+		       (function (lambda (c) (if (= c ?\,) comma)))
+		       (substring class (1+ (match-beginning 0))
+				  (1- (match-end 0)))
+		       "")))))
+
+;; Remove only *trailing* template identifiers when class name is looked up.
+(defun c++-class-non-template-name (class)
+  "Return CLASS name sans any trailing <template> component.
+Does not remove whitespace from CLASS."
+  (if (and (stringp class) (string-match "<[^!]+>\\'" class))
+      (substring class 0 (match-beginning 0))
+    class))
+
+(defun c++-get-class-name (class-name template-signature rename-arguments-flag)
+  "Return a possibly, parameterized class identifier built from CLASS-NAME and TEMPLATE-SIGNATURE.
+If RENAME-ARGUMENTS-FLAG is non-nil, template class argument names are
+normalized also to T1,T2,T3, etc.
+TEMPLATE-SIGNATURE may be of any of the following forms:
+   nil
+   template <class T>
+   template <class T1, class T2>
+   <class T1, class T2>
+   <int = 0>."
+  (cond ((null template-signature)
+	 class-name)
+	((stringp template-signature)
+	 (let ((types) (start 0))
+	   (while (string-match
+		   c++-template-parameter-regexp
+		   template-signature start)
+	     (setq start (match-end 0)
+		   types (cons (substring
+				template-signature
+				(match-beginning c++-template-parameter-grpn)
+				(match-end c++-template-parameter-grpn))
+			       types)))
+	   (if (null types)
+	       class-name
+	     (setq class-name
+		   (format "%s<%s>" class-name
+			   (mapconcat 'identity (nreverse types) ",")))
+	     (if rename-arguments-flag
+		 (c++-normalize-template-arguments class-name)
+	       class-name))))
+	(t (error "(c++-get-class-name): Second argument, '%s', must be a string or nil."
+		  template-signature))))
+
+(defun c++-normalize-class-match (rename-arguments-flag)
+  "After a regexp match to a class definition, return the matching class name.
+Class name is normalized for use in OO-Browser lookups.
+If RENAME-ARGUMENTS-FLAG is non-nil, template class argument names are
+normalized also to T1,T2,T3, etc."
+ (c++-get-class-name
+  (buffer-substring (match-beginning c++-class-def-name-grpn)
+		    (match-end c++-class-def-name-grpn))
+  (if (match-beginning c++-class-def-template-grpn)
+      (buffer-substring
+       (match-beginning c++-class-def-template-grpn)
+       (match-end c++-class-def-template-grpn)))
+  rename-arguments-flag))
+
+(defun c++-normalize-template-arguments (class)
+  "Return class with any template arguments renamed to <T> or <T1,T2,T3>."
+  (setq class (br-delete-space class))
+  (cond ((not (string-match "[<,][ \t\n\^M]*[^,>]*[,>]" class))
+	 ;; No type parameters.
+	 class)
+	;;
+	;; Some type parameter.
+	((= ?> (aref class (1- (match-end 0))))
+	 ;; Class has only one type parameter.
+	 (hypb:replace-match-string c++-template-parameter-regexp
+				    class "<T>" t))
+	(t
+	 ;; Class has two or more type parameters.
+	 (let ((count 1) (start 0) before after)
+	   (while (string-match "[<,][ \t\n\^M]*[^,>]*" class start)
+	     (setq before (substring class
+				     0 (1+ (match-beginning 0)))
+		   after (substring class (match-end 0))
+		   class
+		   (format "%sT%d%s" before count after)
+		   ;; class may have just shrunk, so don't use
+		   ;; match-data from above string-match below here.
+		   start (- (length class) (length after))
+		   count (1+ count)))
+	   class))))
+
+(defun c++-scan-parents ()
+  "Return list of parents names from a C++ class definition.
+Point must be after the colon that begins the parent list and before the
+first parent entry when this function is called."
+  (let ((parent-list) (again t)
+	parent)
+    (while (and again (re-search-forward c++-parent-regexp nil t))
+      (setq again (= ?, (preceding-char))
+	    parent (c++-get-parent-name
+		    (buffer-substring (match-beginning c++-parent-name-grpn)
+				      (match-end c++-parent-name-grpn)))
+	    parent-list (cons parent parent-list)))
+    (nreverse parent-list)))
+
+(defun c++-get-parent-name (parent-name)
+  ;; We need to handle class definitions like this:
+  ;;   template <class T> class PtrList : private List<type-name> {}
+  ;; where the parent class is an instantiation of a parameterized class.
+  ;; For now, we change the type name to <T> or <T1,T2,T3> when there are 3
+  ;; parameters, for purposes of class name matching.
+  ;;	
+  ;; Test cases:
+  ;;
+  ;;   (mapcar 'c++-get-parent-name
+  ;;	'("par <class _T1=myclass , class _T2 = you >" "parent"
+  ;;	  "class<_T1,T2>" "class< __me , int>" "" "<template>"
+  ;;      "par<_template>")) 
+  ;;   Should yield:
+  ;;     ("par<T1,T2>" "parent" "class<T1,T2>" "class<T1,T2>" "" "<template>"
+  ;;      "par<T>")
+  ;;
+  (if (string-match "<\\(.\\|\n\\)+>\\'" parent-name)
+      (let ((parent (substring parent-name 0 (match-beginning 0)))
+	    (template (substring parent-name (match-beginning 0))))
+	(setq parent (hypb:replace-match-string "\\s " parent "" t)
+	      parent-name (c++-get-class-name parent template t)))
+    parent-name))
+
+(defun c++-get-parents-from-source (filename class-name)
+  "Scan source in FILENAME and return list of parents of CLASS-NAME.
+Assume file existence has already been checked."
+    (or (null class-name)
+	(car (car (br-rassoc
+		   class-name
+		   (cdr (c++-get-classes-from-source filename t)))))))
+
+(defun c++-select-path (paths-htable-elt &optional feature-p)
+  "Select proper pathname from PATHS-HTABLE-ELT based upon value of optional FEATURE-P.
+Selection is between path of class definition and path for features associated
+with the class."
+  (let ((elt (cdr paths-htable-elt)))
+    (if (consp elt) 
+	(if feature-p (cdr elt) (car elt))
+      ;; Both paths are the same.
+      elt)))
+
+(defun c++-set-case (type)
+  "Return string TYPE identifier for use as a class name."
+  type)
+
+(defun c++-set-case-type (class-name)
+  "Return string CLASS-NAME for use as a type identifier."
+  class-name)
+
+(defun c++-to-class-end ()
+  "Assuming point is at start of class, move to start of line after end of class."
+  (interactive)
+  (condition-case ()
+      (forward-list)
+    (error (progn (or (re-search-forward "^}" nil t)
+		      (goto-char (point-max))))))
+  (forward-line 1))
+
+(defun c++-to-comments-begin ()
+  "Skip back from current point past any preceding blank lines and comments.
+Presumes no \"/*\" strings are nested within multi-line comments."
+  (let ((opoint))
+    (while (progn (setq opoint (point))
+		  ;; To previous line
+		  (if (= 0 (forward-line -1))
+		      (cond
+		       ;; If begins with "//" or ends with "*/", then is a
+		       ;; comment.
+		       ((looking-at "[ \t]*\\(//\\|$\\)"))
+		       ((looking-at ".*\\*/[ \t]*$")
+			(end-of-line)
+			;; Avoid //*** single line comments here.
+			(re-search-backward "\\(^\\|[^/]\\)/\\*" nil t))
+		       ((looking-at "[ \t]*$"))))))
+    (goto-char opoint)
+    ;; Skip past whitespace
+    (skip-chars-forward " \t\n")
+    (beginning-of-line)))
+
+;;; ************************************************************************
+;;; Internal variables
+;;; ************************************************************************
+
+(defconst c++-template-prefix
+  "\\(template[ \t\n\^M]*<[^>;.{}]+>[ \t\n\^M]*\\)?"
+  "Regexp matching a template class or element definition or declaration.
+Entire expression is an optional match, so it may be added as a conditional
+expression to other regexps.")
+
+(defconst c++-class-name-before
+  (concat "^[ \t]*" c++-template-prefix c++-class-keyword)
+  "Regexp preceding the class name in a class definition.")
+
+(defconst c++-comment-regexp "\\([ \t\n]*//.*[\n]\\)*[ \t\n]*")
+
+(defconst c++-class-name-after
+  (concat c++-comment-regexp "\\([{:]\\)")
+  "Regexp following the class name in a class definition.
+Last character matched is either the colon preceding the list of class
+parents, or the curly brace beginning the class body definition.")
+
+(defconst c++-identifier-chars "_~<>a-zA-Z0-9"
+  "String of chars and char ranges that may be used within a C++ or G++ identifier.")
+
+(defconst c++-template-identifier-chars "_a-zA-Z0-9"
+  "String of chars and char ranges that may be used within a standard C++ template identifier.
+This excludes the template arguments.")
+
+(defconst c++-return-type-chars "_<>a-zA-Z0-9"
+  "String of chars and char ranges that may be used within a C++ or G++ return type identifier.")
+
+;; Modified on 3/28/95 to handle C++ names with multiple template
+;; parameters, e.g. class<T1,T2,T3>.
+(defconst c++-identifier (concat
+			  "\\([_~<a-zA-Z][" c++-template-identifier-chars "]*"
+			  "[ \t\n\^M]*<[^>;{}]+[ \t\n\^M>]*>\\|[_~<a-zA-Z]["
+			  c++-identifier-chars "]*\\)")
+  "Regular expression matching a C++ or G++ identifier.")
+
+(defconst c++-class-def-regexp
+  (concat c++-class-name-before c++-identifier c++-class-name-after)
+  "Regular expression used to match to class definitions in source text.
+Class name identifier is grouping 'c++-class-def-name-grpn'.  Optional
+class template parameter signature is grouping 'c++-class-def-template-grpn'.
+':' derived class indicator begins grouping 'c++-class-def-derived-grpn,'
+unless the class is not derived, in which case this grouping begins with
+'{'.")
+
+(defconst c++-class-def-template-grpn 1)
+(defconst c++-class-def-name-grpn 3)
+(defconst c++-class-def-derived-grpn 5)
+
+(defconst c++-lang-prefix "c++-"
+ "Prefix string that starts \"br-c++.el\" symbol names.")
+
+(defconst c++-parent-regexp
+  (concat c++-comment-regexp
+	  "\\(\\(public\\|private\\|protected\\|virtual\\)[ \t\n]+"
+	  "\\(\\(public\\|private\\|protected\\|virtual\\)[ \t\n]+\\)?\\)?"
+	  c++-identifier c++-comment-regexp "[,{;]")
+  "Parent identifier is group 'c++-parent-name-grpn'.")
+
+(defconst c++-parent-name-grpn 6)
+
+(defconst c++-template-parameter-regexp
+  "[< \t\n\^M]+\\([^=<> \t\n\^M]+\\)[ \t\n\^M]*\\(=[^,>]+\\)?[,>]"
+  "Regexp matching a single C++ <template> specifier argument name.
+For example in 'template <class T, int size = 0>', there are two parameter
+names, 'T' and 'size'.  The parameter name is grouping
+'c++-template-parameter-grpn'.")
+
+(defconst c++-template-parameter-grpn 1)
+
+;; Ellemtel C++ recommendations specify that inline definition files should
+;; use the suffix ".icc" and other people use ".I" for such files, so those
+;; suffixes are included here.
+(defconst c++-src-file-regexp
+  "[^.]\\.\\([ch]xx\\|[chCH][chpCHP]?[pP]?\\|icc\\|I\\)$"
+  "Regular expression matching a unique part of C++ source or header file name and no others.")
+
+(defvar c++-children-htable nil
+  "Htable whose elements are of the form: (LIST-OF-CHILD-CLASSES . CLASS-NAME).
+Used to traverse C++ inheritance graph.  'br-build-children-htable' builds
+this list.")
+(defvar c++-parents-htable nil
+  "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
+Used to traverse C++ inheritance graph.  'br-build-parents-htable' builds
+this list.")
+(defvar c++-paths-htable nil
+  "Htable whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
+FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
+'br-build-paths-htable' builds this list.")
+
+
+(defvar c++-lib-parents-htable nil
+  "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
+Only classes from stable software libraries are used to build the list.")
+(defvar c++-lib-paths-htable nil
+  "Htable whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
+FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
+Only classes from stable software libraries are used to build the list.")
+
+(defvar c++-sys-parents-htable nil
+  "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
+Only classes from systems that are likely to change are used to build the list.")
+(defvar c++-sys-paths-htable nil
+  "Alist whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
+FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
+Only classes from systems that are likely to change are used to build the
+list.")
+
+(defvar c++-lib-prev-search-dirs nil
+  "Used to check if 'c++-lib-classes-htable' must be regenerated.")
+(defvar c++-sys-prev-search-dirs nil
+  "Used to check if 'c++-sys-classes-htable' must be regenerated.")
+
+(defvar c++-env-spec nil
+  "Non-nil value means Environment specification has been given but not yet built.
+Nil means current Environment has been built, though it may still require updating.")
+
+(provide 'br-c++)