1;;; semantic/tag-ls.el --- Language Specific override functions for tags  -*- lexical-binding: t; -*-
2
3;; Copyright (C) 1999-2004, 2006-2021 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 <https://www.gnu.org/licenses/>.
21
22;;; Commentary:
23;;
24;; There are some features of tags that are too language dependent to
25;; put in the core `semantic-tag' functionality.  For instance, the
26;; protection of a tag (as specified by UML) could be almost anything.
27;; In Java, it is a type specifier.  In C, there is a label.  This
28;; information can be derived, and thus should not be stored in the tag
29;; itself.  These are the functions that languages can use to derive
30;; the information.
31
32(require 'semantic)
33(require 'semantic/find)
34
35;;; Code:
36
37;;; TAG SIMILARITY:
38;;
39;; Two tags that represent the same thing are "similar", but not the "same".
40;; Similar tags might have the same name, but one is a :prototype, while
41;; the other is an implementation.
42;;
43;; Each language will have different things that can be ignored
44;; between two "similar" tags, so similarity checks involve a series
45;; of mode overridable features.  Some are "internal" features.
46(defvar semantic-tag-similar-ignorable-attributes '(:prototype-flag)
47  "The tag attributes that can be ignored during a similarity test.")
48
49(define-overloadable-function semantic--tag-similar-names-p (tag1 tag2 blankok)
50  "Compare the names of TAG1 and TAG2.
51If BLANKOK is false, then the names must exactly match.
52If BLANKOK is true, then if either of TAG1 or TAG2 has blank
53names, then that is ok, and this returns true, but if they both
54have values, they must still match.")
55
56(defun semantic--tag-similar-names-p-default (tag1 tag2 blankok)
57  "Compare the names of TAG1 and TAG2.
58If BLANKOK is false, then the names must exactly match.
59If BLANKOK is true, then if either of TAG1 or TAG2 has blank
60names, then that is ok, and this returns true, but if they both
61have values, they must still match."
62  (let ((n1 (semantic-tag-name tag1))
63	(n2 (semantic-tag-name tag2)))
64    (or (and blankok (or (null n1) (null n2) (string= n1 "") (string= n2 "")))
65	(string= n1 n2))))
66
67(define-overloadable-function semantic--tag-similar-types-p (tag1 tag2)
68  "Compare the types of TAG1 and TAG2.
69This function can be overridden, for example to compare a fully
70qualified with an unqualified type."
71  (cond
72   ((and (null (semantic-tag-type tag1))
73	 (null (semantic-tag-type tag2)))
74    t)
75   ((or (null (semantic-tag-type tag1))
76	(null (semantic-tag-type tag2)))
77    nil)
78   (t
79    (:override))))
80
81(defun semantic--tag-similar-types-p-default (tag1 tag2)
82  "Compare the types of TAG1 and TAG2.
83This function can be overridden, for example to compare a fully
84qualified with an unqualified type."
85  (semantic-tag-of-type-p tag1 (semantic-tag-type tag2)))
86
87(define-overloadable-function semantic--tag-attribute-similar-p (attr value1 value2 ignorable-attributes)
88  "Test to see if attribute ATTR is similar for VALUE1 and VALUE2.
89IGNORABLE-ATTRIBUTES is described in `semantic-tag-similar-p'.
90This function is internal, but allows customization of `semantic-tag-similar-p'
91for a given mode at a more granular level.
92
93Note that :type, :name, and anything in IGNORABLE-ATTRIBUTES will
94not be passed to this function.
95
96Modes that override this function can call
97`semantic--tag-attribute-similar-p-default' to do the default equality tests if
98ATTR is not special for that mode.")
99
100(defun semantic--tag-attribute-similar-p-default (_attr value1 value2 ignorable-attributes)
101  "For ATTR, VALUE1, VALUE2 and IGNORABLE-ATTRIBUTES, test for similarity."
102  (cond
103   ;; Tag sublists require special testing.
104   ((and (listp value1) (semantic-tag-p (car value1))
105	 (listp value2) (semantic-tag-p (car value2)))
106    (let ((ans t)
107	  (taglist1 value1)
108	  (taglist2 value2))
109      (when (not (eq (length taglist1) (length taglist2)))
110	(setq ans nil))
111      (while (and ans taglist1 taglist2)
112	(setq ans (apply #'semantic-tag-similar-p
113			 (car taglist1) (car taglist2)
114			 ignorable-attributes)
115	      taglist1 (cdr taglist1)
116	      taglist2 (cdr taglist2)))
117      ans))
118
119   ;; The attributes are not the same?
120   ((not (equal value1 value2))
121    nil)
122
123   (t t))
124  )
125
126(define-overloadable-function semantic-tag-similar-p (tag1 tag2 &rest ignorable-attributes)
127  "Test to see if TAG1 and TAG2 are similar.
128Two tags are similar if their name, datatype, and various attributes
129are the same.
130
131Similar tags that have sub-tags such as arg lists or type members,
132are similar w/out checking the sub-list of tags.
133
134Optional argument IGNORABLE-ATTRIBUTES are attributes to ignore while comparing
135similarity.
136
137By default, `semantic-tag-similar-ignorable-attributes' is referenced for
138attributes, and IGNORABLE-ATTRIBUTES will augment this list.
139
140Note that even though :name is not an attribute, it can be used to
141indicate lax comparison of names via `semantic--tag-similar-names-p'")
142
143;; Note: optional thing is because overloadable fcns don't handle this
144;; quite right.
145(defun semantic-tag-similar-p-default (tag1 tag2 &optional ignorable-attributes)
146  "Test to see if TAG1 and TAG2 are similar.
147Two tags are similar if their name, datatype, and various attributes
148are the same.
149
150IGNORABLE-ATTRIBUTES are tag attributes that can be ignored.
151
152See `semantic-tag-similar-p' for details."
153  (or
154   ;; Tags are similar if they have the exact same lisp object
155   ;; Added for performance when testing a relatively common case in some uses
156   ;; of this code.
157   (eq tag1 tag2)
158   ;; More complex similarity test.
159   (let* ((ignore (append ignorable-attributes semantic-tag-similar-ignorable-attributes))
160	  (A1 (and (semantic--tag-similar-names-p tag1 tag2 (memq :name ignore))
161		   (semantic--tag-similar-types-p tag1 tag2)
162		   (semantic-tag-of-class-p tag1 (semantic-tag-class tag2))))
163	  (attr1 (semantic-tag-attributes tag1))
164	  (attr2 (semantic-tag-attributes tag2))
165	  (A2 t)
166	  (A3 t)
167	  )
168     ;; Test if there are non-ignorable attributes in A2 which are not present in A1
169     (while (and A2 attr2)
170       (let ((a (car attr2)))
171	 (unless (or (eq a :type) (memq a ignore))
172	   (setq A2 (semantic-tag-get-attribute tag1 a)))
173	 (setq attr2 (cdr (cdr attr2)))))
174     (while (and A2 attr1 A3)
175       (let ((a (car attr1)))
176
177	 (cond ((or (eq a :type)	;; already tested above.
178		    (memq a ignore))	;; Ignore them...
179		nil)
180
181	       (t
182		(setq A3
183		      (semantic--tag-attribute-similar-p
184		       a (car (cdr attr1)) (semantic-tag-get-attribute tag2 a)
185		       ignorable-attributes)))
186	       ))
187       (setq attr1 (cdr (cdr attr1))))
188     (and A1 A2 A3))))
189
190;;; FULL NAMES
191;;
192;; For programmer convenience, a full name is not specified in source
193;; code.  Instead some abbreviation is made, and the local environment
194;; will contain the info needed to determine the full name.
195(define-overloadable-function semantic-tag-full-package (tag &optional stream-or-buffer)
196  "Return the fully qualified package name of TAG in a package hierarchy.
197STREAM-OR-BUFFER can be anything convertible by
198`semantic-something-to-tag-table', but must be a toplevel
199semantic tag stream that contains TAG.
200
201A Package Hierarchy is defined in UML by the way classes and methods
202are organized on disk.  Some languages use this concept such that a
203class can be accessed via it's fully qualified name, (such as Java.)
204
205Other languages qualify names within a Namespace (such as C++) which
206result in a different package like structure.
207
208Languages which do not override this function will just search the
209stream for a tag of class `package', and return that."
210  (let ((stream (semantic-something-to-tag-table
211                 (or stream-or-buffer tag))))
212    (:override-with-args (tag stream))))
213
214(defun semantic-tag-full-package-default (_tag stream)
215  "Default method for `semantic-tag-full-package' for TAG.
216Return the name of the first tag of class `package' in STREAM."
217  (let ((pack (car-safe (semantic-find-tags-by-class 'package stream))))
218    (when (and pack (semantic-tag-p pack))
219      (semantic-tag-name pack))))
220
221(define-overloadable-function semantic-tag-full-name (tag &optional stream-or-buffer)
222  "Return the fully qualified name of TAG in the package hierarchy.
223STREAM-OR-BUFFER can be anything convertible by
224`semantic-something-to-tag-table', but must be a toplevel
225semantic tag stream that contains TAG.
226
227A Package Hierarchy is defined in UML by the way classes and methods
228are organized on disk.  Some languages use this concept such that a
229class can be accessed via it's fully qualified name, (such as Java.)
230
231Other languages qualify names within a Namespace (such as C++) which
232result in a different package like structure.
233
234Languages which do not override this function with
235`tag-full-name' will combine `semantic-tag-full-package' and
236`semantic-tag-name', separated with language separator character.
237Override functions only need to handle STREAM-OR-BUFFER with a
238tag stream value, or nil.
239
240TODO - this function should probably also take a PARENT to TAG to
241resolve issues where a method in a class in a package is present."
242  (let ((stream (semantic-something-to-tag-table
243                 (or stream-or-buffer tag))))
244    (:override-with-args (tag stream))))
245
246(defun semantic-tag-full-name-default (tag stream)
247  "Default method for `semantic-tag-full-name'.
248Return the name of TAG found in the toplevel STREAM."
249  (let ((pack (semantic-tag-full-package tag stream))
250	(name (semantic-tag-name tag)))
251    (if pack
252	(concat pack
253		(car semantic-type-relation-separator-character)
254		name)
255      name)))
256
257;;; UML features:
258;;
259;; UML can represent several types of features of a tag
260;; such as the `protection' of a symbol, or if it is abstract,
261;; leaf, etc.  Learn about UML to catch onto the lingo.
262
263(define-overloadable-function semantic-tag-calculate-parent (tag)
264  "Attempt to calculate the parent of TAG.
265The default behavior (if not overridden with `tag-calculate-parent')
266is to search a buffer found with TAG, and if externally defined,
267search locally, then semanticdb for that tag (when enabled.)")
268
269(defun semantic-tag-calculate-parent-default (tag)
270  "Attempt to calculate the parent of TAG."
271  (when (semantic-tag-in-buffer-p tag)
272    (with-current-buffer (semantic-tag-buffer tag)
273      (save-excursion
274	(goto-char (semantic-tag-start tag))
275	(semantic-current-tag-parent))
276      )))
277
278(define-overloadable-function semantic-tag-protection (tag &optional parent)
279  "Return protection information about TAG with optional PARENT.
280This function returns on of the following symbols:
281   nil         - No special protection.  Language dependent.
282   `public'    - Anyone can access this TAG.
283   `private'   - Only methods in the local scope can access TAG.
284   `protected' - Like private for outside scopes, like public for child
285                 classes.
286Some languages may choose to provide additional return symbols specific
287to themselves.  Use of this function should allow for this.
288
289The default behavior (if not overridden with `tag-protection'
290is to return a symbol based on type modifiers."
291  (and (not parent)
292       (semantic-tag-overlay tag)
293       (semantic-tag-in-buffer-p tag)
294       (setq parent (semantic-tag-calculate-parent tag)))
295  (:override))
296
297(defun semantic-tag-protection-default (tag &optional _parent)
298  "Return the protection of TAG as a child of PARENT default action.
299See `semantic-tag-protection'."
300  (let ((mods (semantic-tag-modifiers tag))
301	(prot nil))
302    (while (and (not prot) mods)
303      (if (stringp (car mods))
304	  (let ((s (car mods)))
305	    (setq prot
306		  ;; A few silly defaults to get things started.
307		  (cond ((member s '("public" "extern" "export"))
308			 'public)
309			((string= s "private")
310			 'private)
311			((string= s "protected")
312			 'protected)
313			((string= s "package")
314			 'package)
315			))))
316      (setq mods (cdr mods)))
317    prot))
318
319(defun semantic-tag-package-protected-p (tag &optional parent currentpackage)
320  "Non-nil if TAG is not available via package access control.
321For languages (such as Java) where a method is package protected,
322this method will return nil if TAG, as found in PARENT is available
323for access from a file in CURRENTPACKAGE.
324If TAG is not protected by PACKAGE, also return t.  Use
325`semantic-tag-protected-p' instead.
326If PARENT is not provided, it will be derived when passed to
327`semantic-tag-protection'.
328If CURRENTPACKAGE is not provided, it will be derived from the current
329buffer."
330  (let ((tagpro (semantic-tag-protection tag parent)))
331    (if (not (eq tagpro 'package))
332	t ;; protected
333
334      ;; package protection, so check currentpackage.
335      ;; Deriving the package is better from the parent, as TAG is
336      ;; probably a field or method.
337      (if (not currentpackage)
338	  (setq currentpackage (semantic-tag-full-package nil (current-buffer))))
339      (let ((tagpack (semantic-tag-full-package (or parent tag))))
340	(if (string= currentpackage tagpack)
341	    nil
342	  t)) )))
343
344(defun semantic-tag-protected-p (tag protection &optional parent)
345  "Non-nil if TAG is protected.
346PROTECTION is a symbol which can be returned by the method
347`semantic-tag-protection'.
348PARENT is the parent data type which contains TAG.
349
350For these PROTECTIONs, true is returned if TAG is:
351@table @asis
352@item nil
353  Always true.
354@item  private
355  True if nil.
356@item protected
357  True if private or nil.
358@item public
359  True if private, protected, or nil.
360@end table"
361  (if (null protection)
362      t
363    (let ((tagpro (semantic-tag-protection tag parent)))
364      (or (and (eq protection 'private)
365	       (null tagpro))
366	  (and (eq protection 'protected)
367	       (or (null tagpro)
368		   (eq tagpro 'private)))
369	  (and (eq protection 'public)
370	       (not (eq tagpro 'public)))))
371    ))
372
373(define-overloadable-function semantic-tag-abstract-p (tag &optional parent)
374  "Return non-nil if TAG is abstract.
375Optional PARENT is the parent tag of TAG.
376In UML, abstract methods and classes have special meaning and behavior
377in how methods are overridden.  In UML, abstract methods are italicized.
378
379The default behavior (if not overridden with `tag-abstract-p'
380is to return true if `abstract' is in the type modifiers.")
381
382(defun semantic-tag-abstract-p-default (tag &optional _parent)
383  "Return non-nil if TAG is abstract as a child of PARENT default action.
384See `semantic-tag-abstract-p'."
385  (let ((mods (semantic-tag-modifiers tag))
386	(abs nil))
387    (while (and (not abs) mods)
388      (if (stringp (car mods))
389	  (setq abs (member (car mods) '("abstract" "virtual"))))
390      (setq mods (cdr mods)))
391    abs))
392
393(define-overloadable-function semantic-tag-leaf-p (tag &optional parent)
394  "Return non-nil if TAG is leaf.
395Optional PARENT is the parent tag of TAG.
396In UML, leaf methods and classes have special meaning and behavior.
397
398The default behavior (if not overridden with `tag-leaf-p'
399is to return true if `leaf' is in the type modifiers.")
400
401(defun semantic-tag-leaf-p-default (tag &optional _parent)
402  "Return non-nil if TAG is leaf as a child of PARENT default action.
403See `semantic-tag-leaf-p'."
404  (let ((mods (semantic-tag-modifiers tag))
405	(leaf nil))
406    (while (and (not leaf) mods)
407      (if (stringp (car mods))
408	  ;; Use java FINAL as example default.  There is none
409	  ;; for C/C++
410	  (setq leaf (string= (car mods) "final")))
411      (setq mods (cdr mods)))
412    leaf))
413
414(define-overloadable-function semantic-tag-static-p (tag &optional parent)
415  "Return non-nil if TAG is static.
416Optional PARENT is the parent tag of TAG.
417In UML, static methods and attributes mean that they are allocated
418in the parent class, and are not instance specific.
419UML notation specifies that STATIC entries are underlined.")
420
421(defun semantic-tag-static-p-default (tag &optional _parent)
422  "Return non-nil if TAG is static as a child of PARENT default action.
423See `semantic-tag-static-p'."
424  (let ((mods (semantic-tag-modifiers tag))
425	(static nil))
426    (while (and (not static) mods)
427      (if (stringp (car mods))
428	  (setq static (string= (car mods) "static")))
429      (setq mods (cdr mods)))
430    static))
431
432;;;###autoload
433(define-overloadable-function semantic-tag-prototype-p (tag)
434  "Return non-nil if TAG is a prototype.
435For some languages, such as C, a prototype is a declaration of
436something without an implementation."
437  )
438
439(defun semantic-tag-prototype-p-default (tag)
440  "Non-nil if TAG is a prototype."
441  (let ((p (semantic-tag-get-attribute tag :prototype-flag)))
442    (cond
443     ;; Trust the parser author.
444     (p p)
445     ;; Empty types might be a prototype.
446     ;; @todo - make this better.
447     ((eq (semantic-tag-class tag) 'type)
448      (not (semantic-tag-type-members tag)))
449     ;; No other heuristics.
450     (t nil))
451    ))
452
453(provide 'semantic/tag-ls)
454
455;; Local variables:
456;; generated-autoload-file: "loaddefs.el"
457;; generated-autoload-load-name: "semantic/tag-ls"
458;; End:
459
460;;; semantic/tag-ls.el ends here
461