Skip to content

Commit 0b4b2d0

Browse files
committed
document final extensions in the language reference
1 parent 133de56 commit 0b4b2d0

File tree

1 file changed

+68
-4
lines changed

1 file changed

+68
-4
lines changed

docs/codeql/ql-language-reference/types.rst

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,13 @@ the supertypes (that is, they are in the :ref:`class domain type <domain-types>`
112112
A class inherits all member predicates from its base types.
113113

114114
A class can extend multiple types. For more information, see ":ref:`multiple-inheritance`."
115+
A class can extend final types (or final aliases of types), see ":ref:`final-extensions`."
115116
Classes can also specialise other types without extending the class interface via `instanceof`,
116117
see ":ref:`instanceof-extensions`.".
117118

118119
To be valid, a class:
119120
- Must not extend itself.
120-
- Must not extend a :ref:`final` class.
121+
- Must not (transitively) extend a non-final type and a final alias of that same type.
121122
- Must not extend types that are incompatible. For more information, see ":ref:`type-compatibility`."
122123

123124
You can also annotate a class. See the list of :ref:`annotations <annotations-overview>`
@@ -242,6 +243,7 @@ A class :ref:`annotated <abstract>` with ``abstract``, known as an **abstract**
242243
the values in a larger type. However, an abstract class is defined as the union of its
243244
subclasses. In particular, for a value to be in an abstract class, it must satisfy the
244245
characteristic predicate of the class itself **and** the characteristic predicate of a subclass.
246+
Note that final extensions are not considered subclasses in this context.
245247

246248
An abstract class is useful if you want to group multiple existing classes together
247249
under a common name. You can then define member predicates on all those classes. You can also
@@ -281,9 +283,9 @@ there is no need to update the queries that rely on it.
281283
Overriding member predicates
282284
============================
283285

284-
If a class inherits a member predicate from a supertype, you can **override** the inherited
285-
definition. You do this by defining a member predicate with the same name and arity as the
286-
inherited predicate, and by adding the ``override`` :ref:`annotation <override>`.
286+
If a class inherits a member predicate from a non-final supertype, you can **override** the
287+
inherited definition. You do this by defining a member predicate with the same name and arity
288+
as the inherited predicate, and by adding the ``override`` :ref:`annotation <override>`.
287289
This is useful if you want to refine the predicate to give a more specific result for the
288290
values in the subclass.
289291

@@ -382,6 +384,68 @@ from ``OneTwoThree`` and ``int``.
382384
must :ref:`override <overriding-member-predicates>` those definitions to avoid ambiguity.
383385
:ref:`Super expressions <super>` are often useful in this situation.
384386

387+
.. _final-extensions:
388+
389+
Final extensions
390+
================
391+
392+
A class can extend final types or final aliases of types. In that case, it inherits final
393+
versions of all the member predicates and fields of those supertypes.
394+
Member predicates that are inherited through final extensions cannot be overridden,
395+
but they can be shadowed.
396+
397+
For example, extending the class from the :ref:`first example <defining-a-class>`:
398+
399+
.. code-block:: ql
400+
401+
final class FinalOneTwoThree = OneTwoThree;
402+
403+
class OneTwo extends FinalOneTwoThree {
404+
OneTwo() {
405+
this = 1 or this = 2
406+
}
407+
408+
string getAString() {
409+
result = "One or two: " + this.toString()
410+
}
411+
}
412+
413+
The member predicate ``getAString()`` shadows the original definition of ``getAString()``
414+
from ``OneTwoThree``.
415+
416+
Different to overriding (see ":ref:`overriding-member-predicates`"),
417+
final extensions leave the extended type unchanged:
418+
419+
.. code-block:: ql
420+
421+
from OneTwoTree o
422+
select o, o.getAString()
423+
424+
+---+-------------------------+
425+
| o | ``getAString()`` result |
426+
+===+=========================+
427+
| 1 | One, two or three: 1 |
428+
+---+-------------------------+
429+
| 2 | One, two or three: 2 |
430+
+---+-------------------------+
431+
| 3 | One, two or three: 3 |
432+
+---+-------------------------+
433+
434+
However, when calling ``getAString()`` on ``OneTwo``, the original definition is shadowed:
435+
436+
.. code-block:: ql
437+
438+
from OneTwo o
439+
select o, o.getAString()
440+
441+
+---+-------------------------+
442+
| o | ``getAString()`` result |
443+
+===+=========================+
444+
| 1 | One or two: 1 |
445+
+---+-------------------------+
446+
| 2 | One or two: 2 |
447+
+---+-------------------------+
448+
385449
.. _instanceof-extensions:
386450

387451
Non-extending subtypes

0 commit comments

Comments
 (0)