mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Merge branch 'main' into update-presentations
This commit is contained in:
@@ -23,7 +23,7 @@ If you want to run variant analysis on your repositories, you need to enable cod
|
||||
Setting a controller repository for variant analysis
|
||||
----------------------------------------------------
|
||||
|
||||
When you run variant analysis, the analysis is run entirely using GitHub Actions. You don't need to create any workflows, but you must specify which GitHub repository the CodeQL extension should use as the "controller repository." Controller repositories can be empty, but they must have at least one commit. The ``GITHUB_TOKEN`` must also have "Read and write permissions" to run workflows in that repository. For more information, see "`Managing GitHub Actions settings for a repository <https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#setting-the-permissions-of-the-github_token-for-your-repository>`__."
|
||||
When you run variant analysis, the analysis is run entirely using GitHub Actions. You don't need to create any workflows, but you must specify which GitHub repository the CodeQL extension should use as the "controller repository." Controller repositories can be empty, but they must have at least one commit.
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
@@ -153,6 +153,36 @@ For example, if you want to continue analyzing a set of repositories that had re
|
||||
|
||||
You can then insert the ``new-repo-list`` of repositories into your list of custom repository lists for easy access in the Variant Analysis Repositories panel.
|
||||
|
||||
Using GitHub code search to add repositories to a custom list
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can use code search directly in the CodeQL extension to add a subset of repositories from GitHub.com to a custom list.
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
This feature uses the legacy code search via the code search API. For more information on the syntax to use, see "`Searching code (legacy) <https://docs.github.com/en/search-github/searching-on-github/searching-code>`__."
|
||||
|
||||
For example, to add all repositories in the ``rails`` organization on GitHub, you can search ``org:rails``.
|
||||
|
||||
You can add a maximum of 1000 repositories to a custom list per search.
|
||||
|
||||
#. In the Variant Analysis Repositories panel, choose the list that you want to add repositories to. You can create a new list or choose an existing list that already contains repositories.
|
||||
|
||||
#. Right-click on the list you have chosen and then click **Add repositories with GitHub Code Search**.
|
||||
|
||||
#. In the pop-up that appears at the top of the application, under the search bar, select a language for your search from the choices in the dropdown.
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/variant-analysis-code-search-language.png
|
||||
:alt: Screenshot of the search bar for using code search to add repositories to a custom list. The search bar asks you to choose a language for your search and has a dropdown list of languages to choose from.
|
||||
|
||||
#. In the search bar, type the search query that you want to use and press **Enter**.
|
||||
|
||||
You can view the progress of your search in the bottom right corner of the application in a box with the text "Searching for repositories...". If you click **Cancel**, no repositories will be added to your list. Once complete, you will see the resulting repositories appear in the dropdown under your custom list in the Variant Analysis Repositories panel.
|
||||
|
||||
Some of the resulting repositories will not have CodeQL databases and some may not allow access by the CodeQL extension for Visual Studio Code. When you run an analysis on the list, the Variant Analysis Results view will show you which repositories were analyzed, which denied access, and which had no CodeQL database.
|
||||
|
||||
Troubleshooting variant analysis
|
||||
--------------------------------
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
.. pull-quote:: Note
|
||||
|
||||
The data flow library used in this article has been replaced with an improved library which is available from CodeQL 2.12.5 onwards, see :ref:`Analyzing data flow in C and C++ (new) <analyzing-data-flow-in-cpp-new>`. The old library will be deprecated in the near future and removed a year after deprecation.
|
||||
The data flow library used in this article has been replaced with an improved library which is available from CodeQL 2.12.5 onwards, see :ref:`Analyzing data flow in C and C++ (new) <analyzing-data-flow-in-cpp-new>`. The old library has been deprecated in CodeQL 2.14.1 and will be removed in a later release.
|
||||
|
||||
Analyzing data flow in C and C++
|
||||
================================
|
||||
|
||||
@@ -315,7 +315,7 @@ The following source kinds are supported:
|
||||
|
||||
Below is an enumeration of the remaining source kinds, but they are out of scope for this documentation:
|
||||
|
||||
- **contentprovider**, **android-widget**, **android-external-storage-dir**.
|
||||
- **contentprovider**, **android-external-storage-dir**.
|
||||
|
||||
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -327,18 +327,31 @@ Taint sink. As opposed to source kinds, there are many different kinds of sinks
|
||||
|
||||
The following sink kinds are supported:
|
||||
|
||||
- **sql**: A SQL injection vulnerability sink.
|
||||
- **xss**: A cross-site scripting vulnerability sink.
|
||||
- **logging**: A log output sink.
|
||||
|
||||
Below is an enumeration of the remaining sinks, but they are out of scope for this documentation:
|
||||
|
||||
- **open-url**, **jndi-injection**, **ldap**, **jdbc-url**
|
||||
- **mvel**, **xpath**, **groovy**, **ognl-injection**
|
||||
- **intent-start**, **pending-intent-sent**, **url-redirect**
|
||||
- **create-file**, **read-file**, **write-file**, **set-hostname-verifier**
|
||||
- **header-splitting**, **information-leak**, **xslt**, **jexl**
|
||||
- **bean-validation**, **ssti**, **fragment-injection**, **regex-use[**\ `arg`\ **]**
|
||||
- **bean-validation**: A sink that can be used for insecure bean validation, such as in calls to **ConstraintValidatorContext.buildConstraintViolationWithTemplate**.
|
||||
- **command-injection**: A sink that can be used to inject shell commands, such as in calls to **Runtime.exec**.
|
||||
- **file-content-store**: A sink that can be used to control the contents of a file, such as in a **Files.write** call.
|
||||
- **fragment-injection**: A sink that can be used for Android fragment injection, such as in a **FragmentTransaction.replace** call.
|
||||
- **groovy-injection**: A sink that can be used for Groovy injection, such as in a **GroovyShell.evaluate** call.
|
||||
- **hostname-verification**: A sink that can be used for unsafe hostname verification, such as in calls to **HttpsURLConnection.setHostnameVerifier**.
|
||||
- **html-injection**: A sink that can be used for XSS via HTML injection, such as in a **ResponseStream.write** call.
|
||||
- **information-leak**: A sink that can be used to leak information to an HTTP response, such as in calls to **HttpServletResponse.sendError**.
|
||||
- **intent-redirection**: A sink that can be used for Android intent redirection, such as in a **Context.startActivity** call.
|
||||
- **jexl-injection**: A sink that can be used for JEXL expression injection, such as in a **JexlExpression.evaluate** call.
|
||||
- **jndi-injection**: A sink that can be used for JNDI injection, such as in a **Context.lookup** call.
|
||||
- **js-injection**: A sink that can be used for XSS via JavaScript injection, such as in a **Webview.evaluateJavaScript** call.
|
||||
- **ldap-injection**: A sink that can be used for LDAP injection, such as in a **DirContext.search** call.
|
||||
- **log-injection**: A sink that can be used for log injection, such as in a **Logger.warn** call.
|
||||
- **mvel-injection**: A sink that can be used for MVEL expression injection, such as in a **MVEL.eval** call.
|
||||
- **ognl-injection**: A sink that can be used for OGNL injection, such as in an **Ognl.getValue** call.
|
||||
- **path-injection**: A sink that can be used for path injection in a file system access, such as in calls to **new FileReader**.
|
||||
- **pending-intents**: A sink that can be used to send an implicit and mutable `PendingIntent` to a third party, such as in an **Activity.setResult** call.
|
||||
- **request-forgery**: A sink that controls the URL of a request, such as in an **HttpRequest.newBuilder** call.
|
||||
- **response-splitting**: A sink that can be used for HTTP response splitting, such as in calls to **HttpServletResponse.setHeader**.
|
||||
- **sql-injection**: A sink that can be used for SQL injection, such as in a **Statement.executeQuery** call.
|
||||
- **template-injection**: A sink that can be used for server side template injection, such as in a **Velocity.evaluate** call.
|
||||
- **url-redirection**: A sink that can be used to redirect the user to a malicious URL, such as in a **Response.temporaryRedirect** call.
|
||||
- **xpath-injection**: A sink that can be used for XPath injection, such as in a **XPath.evaluate** call.
|
||||
- **xslt-injection**: A sink that can be used for XSLT injection, such as in a **Transformer.transform** call.
|
||||
|
||||
summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -53,7 +53,7 @@ Note that this sink is already recognized by the CodeQL JS analysis, but for thi
|
||||
pack: codeql/javascript-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["execa", "Member[shell].Argument[0]", "command-line-injection"]
|
||||
- ["execa", "Member[shell].Argument[0]", "command-injection"]
|
||||
|
||||
|
||||
- Since we're adding a new sink, we add a tuple to the **sinkModel** extensible predicate.
|
||||
@@ -64,7 +64,7 @@ Note that this sink is already recognized by the CodeQL JS analysis, but for thi
|
||||
- **Member[shell]** selects accesses to the **shell** member of the **execa** package.
|
||||
- **Argument[0]** selects the first argument to calls to that member.
|
||||
|
||||
- **command-line-injection** indicates that this is considered a sink for the command injection query.
|
||||
- **command-injection** indicates that this is considered a sink for the command injection query.
|
||||
|
||||
Example: Taint sources from window 'message' events
|
||||
---------------------------------------------------
|
||||
@@ -463,7 +463,7 @@ Sink kinds
|
||||
Unlike sources, sinks tend to be highly query-specific, rarely affecting more than one or two queries. Not every query supports customizable sinks. If the following sinks are not suitable for your use case, you should add a new query.
|
||||
|
||||
- **code-injection**: A sink that can be used to inject code, such as in calls to **eval**.
|
||||
- **command-line-injection**: A sink that can be used to inject shell commands, such as in calls to **child_process.spawn**.
|
||||
- **command-injection**: A sink that can be used to inject shell commands, such as in calls to **child_process.spawn**.
|
||||
- **path-injection**: A sink that can be used for path injection in a file system access, such as in calls to **fs.readFile**.
|
||||
- **sql-injection**: A sink that can be used for SQL injection, such as in a MySQL **query** call.
|
||||
- **nosql-injection**: A sink that can be used for NoSQL injection, such as in a MongoDB **findOne** call.
|
||||
|
||||
@@ -70,18 +70,22 @@ For example, we would like to flag this code:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
var data = JSON.parse(str);
|
||||
if (data.length > 0) { // problematic: `data` may be `null`
|
||||
...
|
||||
function test(str) {
|
||||
var data = JSON.parse(str);
|
||||
if (data.length > 0) { // problematic: `data` may be `null`
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
This code, on the other hand, should not be flagged:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
var data = JSON.parse(str);
|
||||
if (data && data.length > 0) { // unproblematic: `data` is first checked for nullness
|
||||
...
|
||||
function test(str) {
|
||||
var data = JSON.parse(str);
|
||||
if (data && data.length > 0) { // unproblematic: `data` is first checked for nullness
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
We will first try to write a query to find this kind of problem without flow labels, and use the
|
||||
@@ -168,11 +172,13 @@ checked for null-guardedness:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
var root = JSON.parse(str);
|
||||
if (root) {
|
||||
var payload = root.data; // unproblematic: `root` cannot be `null` here
|
||||
if (payload.length > 0) { // problematic: `payload` may be `null` here
|
||||
...
|
||||
function test(str) {
|
||||
var root = JSON.parse(str);
|
||||
if (root) {
|
||||
var payload = root.data; // unproblematic: `root` cannot be `null` here
|
||||
if (payload.length > 0) { // problematic: `payload` may be `null` here
|
||||
...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
@@ -126,7 +126,7 @@ body must also be annotated with ``cached``, otherwise a compiler error is repor
|
||||
``deprecated``
|
||||
==============
|
||||
|
||||
**Available for**: |classes|, |algebraic datatypes|, |member predicates|, |non-member predicates|, |fields|, |modules|, |aliases|
|
||||
**Available for**: |classes|, |algebraic datatypes|, |member predicates|, |non-member predicates|, |imports|, |fields|, |modules|, |aliases|
|
||||
|
||||
The ``deprecated`` annotation is applied to names that are outdated and scheduled for removal
|
||||
in a future release of QL.
|
||||
@@ -292,7 +292,7 @@ at the places where it is called.
|
||||
``pragma[inline_late]``
|
||||
-----------------------
|
||||
|
||||
**Available for**: |non-member predicates|
|
||||
**Available for**: |characteristic predicates|, |member predicates|, |non-member predicates|
|
||||
|
||||
The ``pragma[inline_late]`` annotation must be used in conjunction with a
|
||||
``bindingset[...]`` pragma. Together, they tell the QL optimiser to use the
|
||||
|
||||
@@ -164,6 +164,38 @@ If the call resolves to a predicate without result, then the call is a formula.
|
||||
It is also possible to call a predicate with result. This kind of call is an
|
||||
expression in QL, instead of a formula. For more information, see ":ref:`calls-with-result`."
|
||||
|
||||
Member predicates only apply to members of a particular class and calls to
|
||||
member predicates have a receiver of a matching type. Syntactically, if a call
|
||||
contains a dot, then the expression before the dot specifies the receiver of
|
||||
the call. For instance, ``x`` is the receiver for the call ``x.isEven()``.
|
||||
|
||||
For calls to member predicates of the enclosing class on the member itself
|
||||
(i.e., the value of ``this``), the receiver may be omitted syntactically. In
|
||||
this case we say the call has an implicit this receiver. For instance, in the
|
||||
following example the ``isEven()`` call in ``isOdd()`` is a member predicate
|
||||
call with an implicit this receiver and the call is equivalent to
|
||||
``this.isEven()``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class OneTwoThree extends int {
|
||||
OneTwoThree() { this = 1 or this = 2 or this = 3 }
|
||||
|
||||
predicate isEven() { this = 2 }
|
||||
|
||||
predicate isOdd() { not isEven() }
|
||||
}
|
||||
|
||||
Use of implicit this receivers can make it harder to spot predicates that introduce
|
||||
cartesian products by failing to relate the implicit ``this`` variable with
|
||||
other variables, which can negatively affect query performance. For more
|
||||
information on cartesian products, see ":ref:`Troubleshooting query performance
|
||||
<troubleshooting-query-performance>`".
|
||||
|
||||
It is possible to enable warnings about implicit this receivers for `CodeQL packs
|
||||
<https://docs.github.com/en/code-security/codeql-cli/codeql-cli-reference/about-codeql-packs#warnonimplicitthis>`__
|
||||
through the ``warnOnImplicitThis`` property.
|
||||
|
||||
.. _parenthesized-formulas:
|
||||
|
||||
Parenthesized formulas
|
||||
|
||||
@@ -139,7 +139,7 @@ Parameterized modules
|
||||
=====================
|
||||
|
||||
Parameterized modules are QL's approach to generic programming.
|
||||
Similar to explicit modules, parameterized modules are defined within other modules using the keywork ``module``.
|
||||
Similar to explicit modules, parameterized modules are defined within other modules using the keyword ``module``.
|
||||
In addition to the module name, parameterized modules declare one or more parameters between the name and the module body.
|
||||
|
||||
For example, consider the module ``M``, which takes two predicate parameters and defines a new predicate
|
||||
@@ -264,7 +264,12 @@ Import statements are used for importing modules. They are of the form:
|
||||
Import statements are usually listed at the beginning of the module. Each
|
||||
import statement imports one module. You can import multiple modules by
|
||||
including multiple import statements (one for each module you want to import).
|
||||
An import statement can also be :ref:`annotated <private>` with ``private``.
|
||||
|
||||
An import statement can also be :ref:`annotated <annotations-overview>` with
|
||||
``private`` or ``deprecated``. If an import statement is annotated with
|
||||
``private`` then the imported names are not reexported. If an imported name is
|
||||
only reachable through deprecated imports in a given context then usage of the
|
||||
name in that context will generate deprecation warnings.
|
||||
|
||||
You can import a module under a different name using the ``as`` keyword,
|
||||
for example ``import javascript as js``.
|
||||
|
||||
@@ -186,37 +186,50 @@ A QL module definition has the following syntax:
|
||||
|
||||
A module definition extends the current module's declared module environment with a mapping from the module name to the module definition.
|
||||
|
||||
QL files consist of simply a module body without a name and surrounding braces:
|
||||
QL files and QLL files consist of simply a module body without a name and surrounding braces:
|
||||
|
||||
::
|
||||
|
||||
ql ::= moduleBody
|
||||
|
||||
QL files define a module corresponding to the file, whose name is the same as the filename.
|
||||
QL files and QLL files define a module corresponding to the file, whose name is the same as the filename.
|
||||
|
||||
Kinds of modules
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
A module may be:
|
||||
|
||||
- A *file module*, if it is defined implicitly by a QL file.
|
||||
- A *query module*, if it is defined by a QL file.
|
||||
- A *declared module*, if it is defined by the ``module`` or ``ql`` grammar rules.
|
||||
- A *non-declared module*, if it is not a *declared module*.
|
||||
|
||||
A *declared module* may be:
|
||||
|
||||
- A *file module*, if it is defined implicitly by a QL file or a QLL file.
|
||||
- A *query module*, if it is defined implicitly by a QL file.
|
||||
- A *library module*, if it is not a query module.
|
||||
|
||||
A *non-declared module* may be:
|
||||
|
||||
- A *built-in module*.
|
||||
- An *instantiated module* (see :ref:`Parameterized modules`).
|
||||
- An *instantiation-nested module* (see :ref:`Parameterized modules`).
|
||||
|
||||
A query module must contain one or more queries.
|
||||
|
||||
Import directives
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
An import directive refers to a module identifier:
|
||||
An import directive refers to a module expression:
|
||||
|
||||
::
|
||||
|
||||
import ::= annotations "import" importModuleExpr ("as" modulename)?
|
||||
|
||||
qualId ::= simpleId | qualId "." simpleId
|
||||
importModuleExpr ::= importModuleId arguments?
|
||||
|
||||
importModuleExpr ::= qualId | importModuleExpr "::" modulename arguments?
|
||||
importModuleId ::= qualId | importModuleExpr "::" modulename
|
||||
|
||||
qualId ::= simpleId | qualId "." simpleId
|
||||
|
||||
arguments ::= "<" argument ("," argument)* ">"
|
||||
|
||||
@@ -249,6 +262,73 @@ For qualified identifiers (``a.b``):
|
||||
|
||||
A qualified module identifier is only valid within an import.
|
||||
|
||||
Module expressions contain a module identifier and optional arguments. If arguments are present, the module expression instantiates the module that the identifier resolves to (see :ref:`Parameterized modules`).
|
||||
|
||||
Module expressions cannot refer to :ref:`Parameterized modules`. Instead, parameterized modules must always be fully instantiated when they are referenced.
|
||||
|
||||
.. _Parameterized modules:
|
||||
|
||||
Parameterized modules
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Modules with parameters are called *parameterized modules*. A *declared module* has parameters if and only if it is a *library module* and its declaration uses the ``parameters`` syntax.
|
||||
|
||||
*Parameterized modules* can be instantiated with arguments that match the signatures of the parameters:
|
||||
|
||||
- Given a type signature, the corresponding argument must be a type that transitively extends the specified ``extends`` types and is a transitive subtype of the specified ``instanceof`` types.
|
||||
- Given a predicate signature, the corresponding argument must be a predicate with exactly matching relational types.
|
||||
- Given a module signature, the corresponding argument must be a module that exports all the specified type and predicate members. Furthermore, the module must be declared as matching the module signature via the ``implements`` syntax.
|
||||
|
||||
The result of instantiating a *parameterized module* is an *instantiated module*. The parameterized module is called the *underlying module* of the *instantiated module*.
|
||||
|
||||
Instantiation-relative and instantiation-nested entities
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Given an *instantiated module*, every entity has a corresponding entity called the *instantiation-relative* entity, which is determined as follows:
|
||||
|
||||
- If the entity is the *underlying module*, its *instantiation-relative* entity is the *instantiated module*.
|
||||
- If the entity is a parameter of the *underlying module*, its *instantiation-relative* entity is the corresponding argument.
|
||||
- If the entity is declared inside the *underlying module* or its nested modules, its *instantiation-relative* entity is an *instantiation-nested* entity that is generated by the module instantiation. Parameters of any modules that are nested inside the *underlying module* are considered declared inside the module for this purpose.
|
||||
- Otherwise, the entity's *instantiation-relative* entity is the initial entity itself.
|
||||
|
||||
When the *instantiation-relative* entity of an entity is an *instantiation-nested* entity, then the initial entity is called the *underlying nested* entity of the *instantiation-nested* entity*, the *instantiated module* is called the *instantiation root* of the *instantiation-nested* entity, and the *underlying module* is called the *underlying root* of the *instantiation-nested* entity.
|
||||
|
||||
The components of an *instantiation-nested* entity are the *instantiation-relative* entities of the components of its *underlying nested* entity. Among other things, this applies to:
|
||||
|
||||
- values in the exported environments of *instantiation-nested* modules,
|
||||
- relational types of *instantiation-nested* predicates and predicate signatures,
|
||||
- required signatures of *instantiation-nested* parameters,
|
||||
- parameters of an *instantiation-nested* *parameterized module*,
|
||||
- fields and member predicates of *instantiation-nested* dataclasses.
|
||||
|
||||
Given an *instantiated module*, any alias in the program has a corresponding alias called the *instantiation-relative* alias, which targets the *instantiation-relative* entity.
|
||||
|
||||
Applicative instantiation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Every entity has an *underlying completely uninstantiated* entity that is determined as follows:
|
||||
|
||||
- If the entity is an *instantiated module*, its *underlying completely uninstantiated* entity is the *underlying completely uninstantiated* entity of the *underlying module*.
|
||||
- If the entity is an *instantiation-nested* entity, its *underlying completely uninstantiated* entity is the *underlying completely uninstantiated* entity of the *underlying nested* entity.
|
||||
- Otherwise, its *underlying completely uninstantiated* entity is the entity itself.
|
||||
|
||||
An entity is called *completely uninstantiated* entity if it is its own *underlying completely uninstantiated* entity.
|
||||
|
||||
Every *completely uninstantiated* entity has a *relevant set of parameters*, which is the set of all parameters of all the modules that the entity is transitively nested inside. For entities that are not nested inside any modules, the *relevant set of parameters* is empty.
|
||||
|
||||
Note that the *relevant set of parameters* by construction contains only *completely uninstantiated* parameters.
|
||||
|
||||
For a *completely uninstantiated* parameter, the *bottom-up instantiation-resolution* relative to an entity is defined as:
|
||||
|
||||
- If the entity is an *instantiated module* or an *instantiation-nested* entity, the *bottom-up instantiation-resolution* is the *instantiation-relative* entity of the *bottom-up instantiation-resolution* relative to the *underlying module*.
|
||||
- Otherwise, the *bottom-up instantiation-resolution* is the parameter itself.
|
||||
|
||||
An entity is called *fully instantiated* if none of the *bottom-up instantiation-resolutions* of the parameters in the *relevant set of parameters* of the entity's *underlying completely uninstantiated* entity are parameters.
|
||||
|
||||
Two *instantiated modules* or two *instantiation-nested* entities are considered *equivalent* if they have the same *underlying completely uninstantiated* entity and each parameter in its *relevant set of parameters* has the same *bottom-up instantiation-resolution* relative to either *instantiated module*.
|
||||
|
||||
Module instantiation is applicative, meaning that *equivalent* *instantiated modules* and *equivalent* *instantiation-nested* entities are indistinguishable.
|
||||
|
||||
Module references and active modules
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -268,7 +348,7 @@ QL is a typed language. This section specifies the kinds of types available, the
|
||||
Kinds of types
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Types in QL are either *primitive* types, *database* types, *class* types, *character* types or *class domain* types.
|
||||
Types in QL are either *primitive* types, *database* types, *class* types, *character* types, *class domain* types, type *parameters*, or *instantiation-nested* types.
|
||||
|
||||
The primitive types are ``boolean``, ``date``, ``float``, ``int``, and ``string``.
|
||||
|
||||
@@ -289,7 +369,9 @@ With the exception of class domain types and character types (which cannot be re
|
||||
|
||||
type ::= (moduleExpr "::")? classname | dbasetype | "boolean" | "date" | "float" | "int" | "string"
|
||||
|
||||
moduleExpr ::= modulename arguments? | moduleExpr "::" modulename arguments?
|
||||
moduleExpr ::= moduleId arguments?
|
||||
|
||||
moduleId ::= modulename | moduleExpr "::" modulename
|
||||
|
||||
A type reference is resolved to a type as follows:
|
||||
|
||||
@@ -334,40 +416,6 @@ Active types
|
||||
|
||||
In a QL program, the *active* types are those defined in active modules. In the remainder of this specification, any reference to the types in the program refers only to the active types.
|
||||
|
||||
|
||||
Signatures
|
||||
----------
|
||||
|
||||
Signature definitions
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A QL signature definition has the following syntax:
|
||||
|
||||
::
|
||||
|
||||
signature ::= predicateSignature | typeSignature | moduleSignature
|
||||
|
||||
predicateSignature ::= qldoc? annotations "signature" head ";"
|
||||
|
||||
typeSignature ::= qldoc? annotations "signature" "class" classname ("extends" type ("," type)*)? (";" | "{" signaturePredicate* "}")
|
||||
|
||||
moduleSignature ::= qldoc? annotation* "signature" "module" moduleSignatureName parameters? "{" moduleSignatureBody "}"
|
||||
|
||||
moduleSignatureBody ::= (signaturePredicate | defaultPredicate | signatureType)*
|
||||
|
||||
signaturePredicate ::= qldoc? annotations head ";"
|
||||
|
||||
defaultPredicate ::= qldoc? annotations "default" head "{" formula "}"
|
||||
|
||||
signatureType ::= qldoc? annotations "class" classname ("extends" type ("," type)*)? "{" signaturePredicate* "}"
|
||||
|
||||
|
||||
A predicate signature definition extends the current module's declared predicate signature environment with a mapping from the predicate signature name and arity to the predicate signature definition.
|
||||
|
||||
A type signature definition extends the current module's declared type signature environment with a mapping from the type signature name to the type signature definition.
|
||||
|
||||
A module signature definition extends the current module's declared module signature environment with a mapping from the module signature name to the module signature definition.
|
||||
|
||||
Values
|
||||
------
|
||||
|
||||
@@ -704,12 +752,14 @@ Various kinds of syntax can have *annotations* applied to them. Annotations are
|
||||
simpleAnnotation ::= "abstract"
|
||||
| "cached"
|
||||
| "external"
|
||||
| "extensible"
|
||||
| "final"
|
||||
| "transient"
|
||||
| "library"
|
||||
| "private"
|
||||
| "deprecated"
|
||||
| "override"
|
||||
| "additional"
|
||||
| "query"
|
||||
|
||||
argsAnnotation ::= "pragma" "[" ("inline" | "inline_late" | "noinline" | "nomagic" | "noopt" | "assume_small_delta") "]"
|
||||
@@ -725,31 +775,36 @@ Simple annotations
|
||||
|
||||
The following table summarizes the syntactic constructs which can be marked with each annotation in a valid program; for example, an ``abstract`` annotation preceding a character is invalid.
|
||||
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
| Annotation | Classes | Characters | Member predicates | Non-member predicates | Imports | Fields | Modules | Aliases |
|
||||
+================+=========+============+===================+=======================+=========+========+=========+=========+
|
||||
| ``abstract`` | yes | | yes | | | | | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
| ``cached`` | yes | yes | yes | yes | | | yes | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
| ``external`` | | | | yes | | | | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
| ``final`` | yes | | yes | | | yes | | yes |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
| ``transient`` | | | | yes | | | | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
| ``library`` | yes | | | | | | | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
| ``private`` | yes | | yes | yes | yes | yes | yes | yes |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
| ``deprecated`` | yes | | yes | yes | | yes | yes | yes |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
| ``override`` | | | yes | | | yes | | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
| ``query`` | | | | yes | | | | yes |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
| Annotation | Classes | Characters | Member predicates | Non-member predicates | Imports | Fields | Modules | Aliases | Signatures |
|
||||
+================+=========+============+===================+=======================+=========+========+=========+=========+============+
|
||||
| ``abstract`` | yes | | yes | | | | | | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
| ``cached`` | yes | yes | yes | yes | | | yes | | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
| ``external`` | | | | yes | | | | | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
| ``extensible`` | | | | yes | | | | | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
| ``final`` | yes | | yes | | | yes | | (yes) | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
| ``transient`` | | | | yes | | | | | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
| ``library`` | (yes) | | | | | | | | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
| ``private`` | yes | | yes | yes | yes | yes | yes | yes | yes |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
| ``deprecated`` | yes | | yes | yes | yes | yes | yes | yes | yes |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
| ``override`` | | | yes | | | yes | | | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
| ``additional`` | yes | | | yes | | | yes | yes | yes |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
| ``query`` | | | | yes | | | | yes | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
|
||||
The ``library`` annotation is only usable within a QLL file, not a QL file.
|
||||
The ``final`` annotation is usable on type aliases, but not on module aliases and predicate aliases.
|
||||
|
||||
Annotations on aliases apply to the name introduced by the alias. An alias may, for example, have different privacy to the name it aliases.
|
||||
|
||||
@@ -765,7 +820,7 @@ The parameterized annotation ``pragma`` supplies compiler pragmas, and may be ap
|
||||
+===========================+=========+============+===================+=======================+=========+========+=========+=========+
|
||||
| ``inline`` | | yes | yes | yes | | | | |
|
||||
+---------------------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
| ``inline_late`` | | | | yes | | | | |
|
||||
| ``inline_late`` | | yes | yes | yes | | | | |
|
||||
+---------------------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
| ``noinline`` | | yes | yes | yes | | | | |
|
||||
+---------------------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
@@ -799,11 +854,13 @@ Binding sets are checked by the QL compiler in the following way:
|
||||
|
||||
A predicate may have several different binding sets, which can be stated by using multiple ``bindingset`` annotations on the same predicate.
|
||||
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
| Pragma | Classes | Characters | Member predicates | Non-member predicates | Imports | Fields | Modules | Aliases |
|
||||
+================+=========+============+===================+=======================+=========+========+=========+=========+
|
||||
| ``bindingset`` | | yes | yes | yes | | | | |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
| Annotation | Classes | Characters | Member predicates | Non-member predicates | Imports | Fields | Modules | Aliases | Signatures |
|
||||
+================+=========+============+===================+=======================+=========+========+=========+=========+============+
|
||||
| ``bindingset`` | | yes | yes | yes | | | | | (yes) |
|
||||
+----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+
|
||||
|
||||
The ``bindingset`` pragma is usable with type signatures and predicate signatures, but not with module signatures.
|
||||
|
||||
QLDoc
|
||||
-----
|
||||
@@ -850,7 +907,7 @@ If the query file starts with whitespace followed by a QLDoc comment, then the t
|
||||
Top-level entities
|
||||
------------------
|
||||
|
||||
Modules include five kinds of top-level entity: predicates, classes, modules, aliases, and select clauses.
|
||||
Modules include five kinds of top-level entity: predicates, classes, modules, aliases, signatures, and select clauses.
|
||||
|
||||
Non-member predicates
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -902,13 +959,18 @@ The types specified after the ``extends`` keyword are the *base types* of the cl
|
||||
|
||||
The types specified after the ``instanceof`` keyword are the *instanceof types* of the class.
|
||||
|
||||
A class type is said to *inherit* from the base types. In addition, inheritance is transitive: If a type ``A`` inherits from a type ``B``, and ``B`` inherits from a type ``C``, then ``A`` inherits from ``C``.
|
||||
A class type is said to *final inherit* from base types that are final or referenced through final aliases, and a class type is said to *inherit* from its other base types. In addition, inheritance is transitive:
|
||||
|
||||
- If a type ``A`` inherits from a type ``B``, and ``B`` inherits from a type ``C``, then ``A`` inherits from ``C``.
|
||||
- If a type ``A`` final inherits from a type ``B``, and ``B`` inherits from a type ``C``, then ``A`` final inherits from ``C``.
|
||||
- If a type ``A`` inherits from a type ``B``, and ``B`` final inherits from a type ``C``, then ``A`` final inherits from ``C``.
|
||||
- If a type ``A`` final inherits from a type ``B``, and ``B`` final inherits from a type ``C``, then ``A`` final inherits from ``C``.
|
||||
|
||||
A class adds a mapping from the class name to the class declaration to the current module's declared type environment.
|
||||
|
||||
A valid class can be annotated with ``abstract``, ``final``, ``library``, and ``private``. Any other annotation renders the class invalid.
|
||||
|
||||
A valid class may not inherit from a final class, from itself, or from more than one primitive type.
|
||||
A valid class may not inherit from itself, or from more than one primitive type. The set of types that a valid class inherits from must be disjoint from the set of types that it final inherits from.
|
||||
|
||||
A valid class must have at least one base type or instanceof type.
|
||||
|
||||
@@ -918,9 +980,10 @@ Class dependencies
|
||||
The program is invalid if there is a cycle of class dependencies.
|
||||
|
||||
The following are class dependencies:
|
||||
|
||||
- ``C`` depends on ``C.C``
|
||||
- ``C.C`` depends on ``C.extends``
|
||||
- If ``C`` is abstract then it depends on all classes ``D`` such that ``C`` is a base type of ``D``.
|
||||
- If ``C`` is abstract then it depends on all classes ``D`` such that ``C`` is a base type of ``D`` and ``D`` inherits from ``C``.
|
||||
- ``C.extends`` depends on ``D.D`` for each base type ``D`` of ``C``.
|
||||
- ``C.extends`` depends on ``D`` for each instanceof type ``D`` of ``C``.
|
||||
|
||||
@@ -972,7 +1035,9 @@ A valid member predicate can be annotated with ``abstract``, ``cached``, ``final
|
||||
|
||||
If a type is provided before the name of the member predicate, then that type is the *result type* of the predicate. Otherwise, the predicate has no result type. The types of the variables in the ``var_decls`` are called the predicate's *argument types*.
|
||||
|
||||
A member predicate ``p`` with enclosing class ``C`` *overrides* a member predicate ``p'`` with enclosing class ``D`` when ``C`` inherits from ``D``, ``p'`` is visible in ``C``, and both ``p`` and ``p'`` have the same name and the same arity. An overriding predicate must have the same sequence of argument types as any predicates which it overrides, otherwise the program is invalid.
|
||||
A member predicate ``p`` with enclosing class ``C`` *overrides* a member predicate ``p'`` with enclosing class ``D`` when ``p`` is annotated ``overrride``, ``C`` inherits from ``D``, ``p'`` is visible in ``C``, ``p'`` is not final, and both ``p`` and ``p'`` have the same name and the same arity. An overriding predicate must have the same sequence of argument types as any predicates which it overrides, otherwise the program is invalid.
|
||||
|
||||
A member predicate ``p`` with enclosing class ``C`` *shadows* a member predicate ``p'`` with enclosing class ``D`` when ``C`` final inherits from ``D``, ``p'`` is visible in ``C``, and both ``p`` and ``p'`` have the same name and the same arity. Additionally, a member predicate ``p`` with enclosing class ``C`` *shadows* a member predicate ``p'`` with enclosing class ``D`` when ``C`` inherits from ``D``, ``p'`` is visible in ``C``, ``p'`` is final, and both ``p`` and ``p'`` have the same name and the same arity.
|
||||
|
||||
Member predicates have one or more *root definitions*. If a member predicate overrides no other member predicate, then it is its own root definition. Otherwise, its root definitions are those of any member predicate that it overrides.
|
||||
|
||||
@@ -986,7 +1051,9 @@ A class may not inherit from a class with an abstract member predicate unless it
|
||||
|
||||
A valid class must include a non-private predicate named ``toString`` with no arguments and a result type of ``string``, or it must inherit from a class that does.
|
||||
|
||||
A valid class may not inherit from two different classes that include a predicate with the same name and number of arguments, unless either one of the predicates overrides the other, or the class defines a predicate that overrides both of them.
|
||||
A valid class may not inherit from two different classes that include a predicate with the same name and number of arguments, unless either one of the predicates overrides or shadows the other, or the class defines a predicate that overrides or shadows both of them.
|
||||
|
||||
A valid class may not final inherit from two different classes that include a predicate with the same name and number of arguments, unless either one of the predicates overrides or shadows the other, or the class defines a predicate that shadows both of them.
|
||||
|
||||
The typing environment for a member predicate or character is the same as if it were a non-member predicate, except that it additionally maps ``this`` to a type and also maps any fields on a class to a type. If the member is a character, then the typing environment maps ``this`` to the class domain type of the class. Otherwise, it maps ``this`` to the class type of the class itself.
|
||||
The typing environment also maps any field to the type of the field.
|
||||
@@ -996,14 +1063,49 @@ Fields
|
||||
|
||||
A field declaration introduces a mapping from the field name to the field declaration in the class's declared field environment.
|
||||
|
||||
A field ``f`` with enclosing class ``C`` *overrides* a field ``f'`` with enclosing class ``D`` when ``f`` is annotated ``override``, ``C`` inherits from ``D``, ``p'`` is visible in ``C``, and both ``p`` and ``p'`` have the same name.
|
||||
A field ``f`` with enclosing class ``C`` *overrides* a field ``f'`` with enclosing class ``D`` when ``f`` is annotated ``override``, ``C`` inherits from ``D``, ``p'`` is visible in ``C``, ``p'`` is not final, and both ``p`` and ``p'`` have the same name.
|
||||
|
||||
A valid class may not inherit from two different classes that include a field with the same name, unless either one of the fields overrides the other, or the class defines a field that overrides both of them.
|
||||
A field ``f`` with enclosing class ``C`` *shadows* a field ``f'`` with enclosing class ``D`` when ``C`` final inherits from ``D``, ``p'`` is visible in ``C``, and both ``p`` and ``p'`` have the same name. Additionally, a field ``f`` with enclosing class ``C`` *shadows* a field ``f'`` with enclosing class ``D`` when ``C`` inherits from ``D``, ``p'`` is visible in ``C``, ``p'`` is final, and both ``p`` and ``p'`` have the same name.
|
||||
|
||||
A valid class may not inherit from two different classes that include a field with the same name, unless either one of the fields overrides or shadows the other, or the class defines a field that overrides or shadows both of them.
|
||||
|
||||
A valid class may not final inherit from two different classes that include a field with the same name, unless either one of the fields overrides or shadows the other, or the class defines a field that shadows both of them.
|
||||
|
||||
A valid field must override another field if it is annotated ``override``.
|
||||
|
||||
When field ``f`` overrides field ``g`` the type of ``f`` must be a subtype of the type of ``g``. ``f`` may not be a final field.
|
||||
|
||||
|
||||
Signatures
|
||||
~~~~~~~~~~
|
||||
|
||||
A signature definition has the following syntax:
|
||||
|
||||
::
|
||||
|
||||
signature ::= predicateSignature | typeSignature | moduleSignature
|
||||
|
||||
predicateSignature ::= qldoc? annotations "signature" head ";"
|
||||
|
||||
typeSignature ::= qldoc? annotations "signature" "class" classname ("extends" type ("," type)*)? (";" | "{" signaturePredicate* "}")
|
||||
|
||||
moduleSignature ::= qldoc? annotation* "signature" "module" moduleSignatureName parameters? "{" moduleSignatureBody "}"
|
||||
|
||||
moduleSignatureBody ::= (signaturePredicate | defaultPredicate | signatureType)*
|
||||
|
||||
signaturePredicate ::= qldoc? annotations head ";"
|
||||
|
||||
defaultPredicate ::= qldoc? annotations "default" head "{" formula "}"
|
||||
|
||||
signatureType ::= qldoc? annotations "class" classname ("extends" type ("," type)*)? "{" signaturePredicate* "}"
|
||||
|
||||
|
||||
A predicate signature definition extends the current module's declared predicate signature environment with a mapping from the predicate signature name and arity to the predicate signature definition.
|
||||
|
||||
A type signature definition extends the current module's declared type signature environment with a mapping from the type signature name to the type signature definition.
|
||||
|
||||
A module signature definition extends the current module's declared module signature environment with a mapping from the module signature name to the module signature definition.
|
||||
|
||||
Select clauses
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
@@ -1230,15 +1332,15 @@ The type environment for the arguments is the same as for the call.
|
||||
|
||||
A valid call with results *resolves* to a set of predicates. The ways a call can resolve are as follows:
|
||||
|
||||
- If the call has no receiver and the predicate name is a simple identifier, then the predicate is resolved by looking up its name and arity in the visible member-predicate environment of the enclosing class.
|
||||
- If the call has no receiver and the predicate reference is a simple identifier, then the call is resolved by looking up the predicate reference and arity in the visible predicate environment of the enclosing class.
|
||||
|
||||
- If the call has no receiver and the predicate name is a simple identifier, then the predicate is resolved by looking up its name and arity in the visible predicate environment of the enclosing module.
|
||||
- If the call has no receiver and the predicate reference is a simple identifier, then the call is resolved by looking up the predicate reference and arity in the visible predicate environment of the enclosing module.
|
||||
|
||||
- If the call has no receiver and the predicate name is a selection identifier, then the qualifier is resolved as a module (see "`Module resolution <#module-resolution>`__"). The identifier is then resolved in the exported predicate environment of the qualifier module.
|
||||
- If the call has no receiver and the predicate reference is a selection identifier, then the qualifier is resolved as a module (see "`Module resolution <#module-resolution>`__") and the call is resolved by looking up the identifier in the exported predicate environment of the qualifier module.
|
||||
|
||||
- If the type of the receiver is the same as the enclosing class, the predicate is resolved by looking up its name and arity in the visible predicate environment of the class.
|
||||
- If the the call has a receiver and the type of the receiver is the same as the enclosing class, the call is resolved by looking up the predicate name and arity in the visible predicate environment of the enclosing class.
|
||||
|
||||
- If the type of the receiver is not the same as the enclosing class, the predicate is resolved by looking up its name and arity in the exported predicate environment of the class or domain type.
|
||||
- If the the call has a receiver and the type of the receiver is not the same as the enclosing class, the call is resolved by looking up the predicate name and arity in the exported predicate environment of the type of the receiver.
|
||||
|
||||
If all the predicates that the call resolves to are declared on a primitive type, we then restrict to the set of predicates where each argument of the call is a subtype of the corresponding predicate argument type.
|
||||
Then we find all predicates ``p`` from this new set such that there is not another predicate ``p'`` where each argument of ``p'`` is a subtype of the corresponding argument in ``p``. We then say the call resolves to this set instead.
|
||||
@@ -1261,9 +1363,10 @@ If the call includes a closure, then all declared predicate arguments, the enclo
|
||||
|
||||
A call to a member predicate may be a *direct* call:
|
||||
- If the receiver is not a super expression it is not direct.
|
||||
- If the receiver is ``A.super`` and ``A`` is an instanceof type and not a base type then it is not direct.
|
||||
- If the receiver is ``A.super`` and ``A`` is a base type type and not an instanceof type then it is direct.
|
||||
- If the receiver is ``A.super`` and ``A`` is a base type and an instanceof type then the call is not valid.
|
||||
- If the receiver is ``A.super`` and ``A`` is an instanceof type and not a base type that is inherited from then it is not direct.
|
||||
- If the receiver is ``A.super`` and ``A`` is a base type that is final inherited from then it is not direct.
|
||||
- If the receiver is ``A.super`` and ``A`` is a base type that is inherited from and not an instanceof type then it is direct.
|
||||
- If the receiver is ``A.super`` and ``A`` is a base type that is inherited from and an instanceof type then the call is not valid.
|
||||
- If the receiver is ``super`` and the member predicate is in the exported member predicate environment of an instanceof type and not in the exported member predicate environment of a base type then it isn't direct.
|
||||
- If the receiver is ``super`` and the member predicate is in the exported member predicate environment of a base type and not in the exported member predicate environment of an instanceof type then it is direct.
|
||||
- If the receiver is ``super`` and the member predicate is in the exported member predicate environment of a base type and in the exported member predicate environment of an instanceof type then the call is not valid.
|
||||
@@ -1954,10 +2057,12 @@ Stratification
|
||||
|
||||
A QL program can be *stratified* to a sequence of *layers*. A layer is a set of predicates and types.
|
||||
|
||||
A valid stratification must include each predicate and type in the QL program. It must not include any other predicates or types.
|
||||
A valid stratification must include each predicate and type in the QL program that is *fully instantiated*. It must not include any other predicates or types.
|
||||
|
||||
A valid stratification must not include the same predicate in multiple layers.
|
||||
|
||||
Each non-abstract predicate has an associated body. For predicates inside *declared modules*, this is the predicate declaration. The body of an *instantiation-nested* predicate is the body of the *underlying nested* predicate where all references and calls have been substituted with the *instantiation-relative* entity or alias.
|
||||
|
||||
Formulas, variable declarations and expressions within a predicate body have a *negation polarity* that is positive, negative, or zero. Positive and negative are opposites of each other, while zero is the opposite of itself. The negation polarity of a formula or expression is then determined as follows:
|
||||
|
||||
- The body of a predicate is positive.
|
||||
@@ -2033,7 +2138,7 @@ Predicates, and types can *depend* and *strictly depend* on each other. Such dep
|
||||
|
||||
- For each class ``C`` with a characteristic predicate, ``C.C`` depends on the characteristic predicate.
|
||||
|
||||
- For each abstract class ``A`` in the program, for each type ``C`` that has ``A`` as a base type, ``A.class`` depends on ``C.class``.
|
||||
- For each abstract class ``A`` in the program, for each type ``C`` that inherits from ``A`` and has ``A`` as a base type, ``A.class`` depends on ``C.class``.
|
||||
|
||||
- A predicate with a higher-order body may strictly depend or depend on each predicate reference within the body. The exact dependencies are left unspecified.
|
||||
|
||||
@@ -2085,7 +2190,7 @@ Each layer of the stratification is *populated* in order. To populate a layer, e
|
||||
|
||||
- To populate the type ``C.class`` for an abstract class type ``C``, identify each named tuple that has the following properties:
|
||||
- It is a member of ``C.C``.
|
||||
- For each class ``D`` that has ``C`` as a base type then there is a named tuple with variables from the public fields of ``C`` and ``this`` that the given tuple and a tuple in ``D.class`` both extend.
|
||||
- For each class ``D`` that inherits from ``C`` and has ``C`` as a base type then there is a named tuple with variables from the public fields of ``C`` and ``this`` that the given tuple and a tuple in ``D.class`` both extend.
|
||||
|
||||
|
||||
Query evaluation
|
||||
@@ -2159,12 +2264,14 @@ The complete grammar for QL is as follows:
|
||||
simpleAnnotation ::= "abstract"
|
||||
| "cached"
|
||||
| "external"
|
||||
| "extensible"
|
||||
| "final"
|
||||
| "transient"
|
||||
| "library"
|
||||
| "private"
|
||||
| "deprecated"
|
||||
| "override"
|
||||
| "additional"
|
||||
| "query"
|
||||
|
||||
argsAnnotation ::= "pragma" "[" ("inline" | "inline_late" | "noinline" | "nomagic" | "noopt" | "assume_small_delta") "]"
|
||||
|
||||
@@ -112,12 +112,13 @@ the supertypes (that is, they are in the :ref:`class domain type <domain-types>`
|
||||
A class inherits all member predicates from its base types.
|
||||
|
||||
A class can extend multiple types. For more information, see ":ref:`multiple-inheritance`."
|
||||
A class can extend final types (or final aliases of types), see ":ref:`final-extensions`."
|
||||
Classes can also specialise other types without extending the class interface via `instanceof`,
|
||||
see ":ref:`instanceof-extensions`.".
|
||||
|
||||
To be valid, a class:
|
||||
- Must not extend itself.
|
||||
- Must not extend a :ref:`final` class.
|
||||
- Must not (transitively) extend a non-final type and a final alias of that same type.
|
||||
- Must not extend types that are incompatible. For more information, see ":ref:`type-compatibility`."
|
||||
|
||||
You can also annotate a class. See the list of :ref:`annotations <annotations-overview>`
|
||||
@@ -134,8 +135,10 @@ The body of a class can contain:
|
||||
- Any number of :ref:`field <fields>` declarations.
|
||||
|
||||
When you define a class, that class also inherits all non-:ref:`private` member predicates and
|
||||
fields from its supertypes. You can :ref:`override <overriding-member-predicates>` those
|
||||
predicates and fields to give them a more specific definition.
|
||||
fields from its supertypes.
|
||||
|
||||
Depending on whether they are final, you can :ref:`override <overriding-member-predicates>` or
|
||||
:ref:`shadow <final-extensions>` those predicates and fields to give them a more specific definition.
|
||||
|
||||
.. _characteristic-predicates:
|
||||
|
||||
@@ -242,6 +245,7 @@ A class :ref:`annotated <abstract>` with ``abstract``, known as an **abstract**
|
||||
the values in a larger type. However, an abstract class is defined as the union of its
|
||||
subclasses. In particular, for a value to be in an abstract class, it must satisfy the
|
||||
characteristic predicate of the class itself **and** the characteristic predicate of a subclass.
|
||||
Note that final extensions are not considered subclasses in this context.
|
||||
|
||||
An abstract class is useful if you want to group multiple existing classes together
|
||||
under a common name. You can then define member predicates on all those classes. You can also
|
||||
@@ -281,9 +285,9 @@ there is no need to update the queries that rely on it.
|
||||
Overriding member predicates
|
||||
============================
|
||||
|
||||
If a class inherits a member predicate from a supertype, you can **override** the inherited
|
||||
definition. You do this by defining a member predicate with the same name and arity as the
|
||||
inherited predicate, and by adding the ``override`` :ref:`annotation <override>`.
|
||||
If a class inherits a member predicate from a non-final supertype, you can **override** the
|
||||
inherited definition. You do this by defining a member predicate with the same name and arity
|
||||
as the inherited predicate, and by adding the ``override`` :ref:`annotation <override>`.
|
||||
This is useful if you want to refine the predicate to give a more specific result for the
|
||||
values in the subclass.
|
||||
|
||||
@@ -382,6 +386,68 @@ from ``OneTwoThree`` and ``int``.
|
||||
must :ref:`override <overriding-member-predicates>` those definitions to avoid ambiguity.
|
||||
:ref:`Super expressions <super>` are often useful in this situation.
|
||||
|
||||
.. _final-extensions:
|
||||
|
||||
Final extensions
|
||||
================
|
||||
|
||||
A class can extend final types or final aliases of types. In that case, it inherits final
|
||||
versions of all the member predicates and fields of those supertypes.
|
||||
Member predicates that are inherited through final extensions cannot be overridden,
|
||||
but they can be shadowed.
|
||||
|
||||
For example, extending the class from the :ref:`first example <defining-a-class>`:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
final class FinalOneTwoThree = OneTwoThree;
|
||||
|
||||
class OneTwoFinalExtension extends FinalOneTwoThree {
|
||||
OneTwoFinalExtension() {
|
||||
this = 1 or this = 2
|
||||
}
|
||||
|
||||
string getAString() {
|
||||
result = "One or two: " + this.toString()
|
||||
}
|
||||
}
|
||||
|
||||
The member predicate ``getAString()`` shadows the original definition of ``getAString()``
|
||||
from ``OneTwoThree``.
|
||||
|
||||
Different to overriding (see ":ref:`overriding-member-predicates`"),
|
||||
final extensions leave the extended type unchanged:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
from OneTwoTree o
|
||||
select o, o.getAString()
|
||||
|
||||
+---+-------------------------+
|
||||
| o | ``getAString()`` result |
|
||||
+===+=========================+
|
||||
| 1 | One, two or three: 1 |
|
||||
+---+-------------------------+
|
||||
| 2 | One, two or three: 2 |
|
||||
+---+-------------------------+
|
||||
| 3 | One, two or three: 3 |
|
||||
+---+-------------------------+
|
||||
|
||||
However, when calling ``getAString()`` on ``OneTwoFinalExtension``, the original definition is shadowed:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
from OneTwoFinalExtension o
|
||||
select o, o.getAString()
|
||||
|
||||
+---+-------------------------+
|
||||
| o | ``getAString()`` result |
|
||||
+===+=========================+
|
||||
| 1 | One or two: 1 |
|
||||
+---+-------------------------+
|
||||
| 2 | One or two: 2 |
|
||||
+---+-------------------------+
|
||||
|
||||
.. _instanceof-extensions:
|
||||
|
||||
Non-extending subtypes
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
Java,"Java 7 to 20 [4]_","javac (OpenJDK and Oracle JDK),
|
||||
|
||||
Eclipse compiler for Java (ECJ) [5]_",``.java``
|
||||
Kotlin [6]_,"Kotlin 1.5.0 to 1.8.20","kotlinc",``.kt``
|
||||
Kotlin [6]_,"Kotlin 1.5.0 to 1.9.0","kotlinc",``.kt``
|
||||
JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [7]_"
|
||||
Python [8]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11",Not applicable,``.py``
|
||||
Ruby [9]_,"up to 3.2",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``"
|
||||
Swift [10]_,"Swift 5.4-5.7","Swift compiler","``.swift``"
|
||||
TypeScript [11]_,"2.6-5.0",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``"
|
||||
Swift [10]_,"Swift 5.4-5.8.1","Swift compiler","``.swift``"
|
||||
TypeScript [11]_,"2.6-5.1",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``"
|
||||
|
||||
.. container:: footnote-group
|
||||
|
||||
@@ -38,5 +38,5 @@
|
||||
.. [7] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files.
|
||||
.. [8] The extractor requires Python 3 to run. To analyze Python 2.7 you should install both versions of Python.
|
||||
.. [9] Requires glibc 2.17.
|
||||
.. [10] Swift support is currently in beta. Support for the analysis of Swift 5.4-5.7 requires macOS. Swift 5.7.3 can also be analyzed using Linux.
|
||||
.. [10] Swift support is currently in beta. Support for the analysis of Swift 5.4-5.8.1 requires macOS or Linux.
|
||||
.. [11] TypeScript analysis is performed by running the JavaScript extractor with TypeScript enabled. This is the default.
|
||||
|
||||
Reference in New Issue
Block a user