@@ -78,7 +78,7 @@ To define a class, you write:
78
78
#. The keyword ``class ``.
79
79
#. The name of the class. This is an `identifier <https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#identifiers >`_
80
80
starting with an uppercase letter.
81
- #. The types to extend.
81
+ #. The base types that the class is derived from via ` extends ` and/or ` instanceof `
82
82
#. The :ref: `body of the class <class-bodies >`, enclosed in braces.
83
83
84
84
For example:
@@ -112,6 +112,8 @@ the :ref:`class domain type <domain-types>`). A class inherits all member predic
112
112
base types.
113
113
114
114
A class can extend multiple types. For more information, see ":ref: `multiple-inheritance `."
115
+ Classes can also specialise other types without extending the class interface via `instanceof `,
116
+ see ":ref: `instanceof-extensions `.".
115
117
116
118
To be valid, a class:
117
119
- Must not extend itself.
@@ -380,6 +382,57 @@ from ``OneTwoThree`` and ``int``.
380
382
must :ref: `override <overriding-member-predicates >` those definitions to avoid ambiguity.
381
383
:ref: `Super expressions <super >` are often useful in this situation.
382
384
385
+
386
+ .. _instanceof-extensions :
387
+
388
+ Non-extending subtypes
389
+ ======================
390
+
391
+ Besides extending base types, classes can also declare `instanceof ` relationships with other types.
392
+
393
+ .. code-block :: ql
394
+ class Foo extends int {
395
+ Foo() { this in [1 .. 10] }
396
+
397
+ string foo_method() { result = "foo" }
398
+ }
399
+
400
+ class Bar extends int instanceof Foo {
401
+ string bar_method() { result = super.foo_method() }
402
+ }
403
+
404
+ In this example, the characteristic predicate from `Foo ` also applies to `Bar `.
405
+ However, `foo_method ` is not exposed in `Bar `, so the query `select any(Bar b).foo_method() `
406
+ results in a compile time error. Note from the example that it is still possible to access
407
+ methods from instanceof supertypes from within the specialising class with the `super ` keyword.
408
+
409
+ Crucially, the base class methods are not just hidden.
410
+ Instead, the extension relationship is sewered.
411
+ This has deep implications on method resolution when complex class hierarchies are involved.
412
+ The following example demonstrates this.
413
+
414
+
415
+ .. code-block :: ql
416
+ class Interface extends int {
417
+ Interface() { this in [1 .. 100] }
418
+ string foo() { result = "" }
419
+ }
420
+
421
+ class Foo extends Interface {
422
+ Foo() { this in [1 .. 10] }
423
+ override string foo() { result = "foo" }
424
+ }
425
+
426
+ class Bar extends Interface instanceof Foo {
427
+ override string foo() { result = "bar" }
428
+ }
429
+
430
+ Here, the method `Bar::foo ` does not override `Foo::foo `.
431
+ Instead, it overrides only `Interface::foo `.
432
+ This means that `select any(Foo b).foo() ` yields only `foo `.
433
+ Had `bar been defined as `extends Foo `, then `select any(Foo b).foo() ` would yield `bar `.
434
+
435
+
383
436
.. _character-types :
384
437
.. _domain-types :
385
438
0 commit comments