mirror of
https://github.com/github/codeql.git
synced 2025-12-20 10:46:30 +01:00
651 lines
29 KiB
ReStructuredText
651 lines
29 KiB
ReStructuredText
.. _expressions:
|
||
|
||
Expressions
|
||
###########
|
||
|
||
An expression evaluates to a set of values and has a type.
|
||
|
||
For example, the expression ``1 + 2``
|
||
evaluates to the integer ``3`` and the expression ``"QL"`` evaluates to the string ``"QL"``. ``1 + 2`` has :ref:`type <types>` ``int`` and ``"QL"`` has type ``string``.
|
||
|
||
The following sections describe the expressions that are available in QL.
|
||
|
||
Variable references
|
||
*******************
|
||
|
||
A variable reference is the name of a declared :ref:`variable <variables>`. This kind of
|
||
expression has the same type as the variable it refers to.
|
||
|
||
For example, if you have :ref:`declared <variable-declarations>` the variables ``int i`` and ``LocalScopeVariable lsv``, then
|
||
the expressions ``i`` and ``lsv`` have types ``int`` and ``LocalScopeVariable`` respectively.
|
||
|
||
You can also refer to the variables ``this`` and ``result``. These are used in :ref:`predicate
|
||
<predicates>` definitions and act in the same way as other variable references.
|
||
|
||
.. index:: literal
|
||
|
||
Literals
|
||
********
|
||
|
||
You can express certain values directly in QL, such as numbers, booleans, and strings.
|
||
|
||
- :ref:`Boolean <boolean>` literals: These are the values ``true`` and ``false``.
|
||
|
||
- :ref:`Integer <int>` literals: These are sequences of decimal digits (``0`` through ``9``),
|
||
possibly starting with a minus sign (``-``).
|
||
For example::
|
||
|
||
0
|
||
42
|
||
-2048
|
||
|
||
- :ref:`Float <float>` literals: These are sequences of decimal digits separated by a dot
|
||
(``.``), possibly starting with a minus sign (``-``).
|
||
For example::
|
||
|
||
2.0
|
||
123.456
|
||
-100.5
|
||
|
||
- :ref:`String <string>` literals: These are finite strings of 16-bit characters. You can
|
||
define a string literal by enclosing characters in quotation marks (``"..."``). Most
|
||
characters represent themselves, but there are a few characters that you need to "escape"
|
||
with a backslash. The following are examples of string literals::
|
||
|
||
"hello"
|
||
"They said, \"Please escape quotation marks!\""
|
||
|
||
See `String literals <https://help.semmle.com/QL/ql-spec/language.html#string-literals-string>`_
|
||
in the QL language specification for more details.
|
||
|
||
Note: there is no "date literal" in QL. Instead, to specify a :ref:`date <date>`, you should
|
||
convert a string to the date that it represents using the ``toDate()`` predicate. For example,
|
||
``"2016-04-03".toDate()`` is the date April 3, 2016, and ``"2000-01-01 00:00:01".toDate()`` is the
|
||
point in time one second after New Year 2000.
|
||
|
||
The following string formats are recognized as dates:
|
||
- **ISO dates**, such as ``"2016-04-03 17:00:24"``. The seconds part is optional (assumed
|
||
to be ``"00"`` if it's missing), and the entire time part can also be missing (in which
|
||
case it's assumed to be ``"00:00:00"``).
|
||
- **Short-hand ISO dates**, such as ``"20160403"``.
|
||
- **UK-style dates**, such as ``"03/04/2016"``.
|
||
- **Verbose dates**, such as ``"03 April 2016"``.
|
||
|
||
Parenthesized expressions
|
||
*************************
|
||
|
||
A parenthesized expression is an expression surrounded by parentheses, ``(`` and ``)``. This
|
||
expression has exactly the same type and values as the original expression.
|
||
Parentheses are useful for grouping expressions together to remove ambiguity and improve
|
||
readability.
|
||
|
||
.. index:: range
|
||
.. _ranges:
|
||
|
||
Ranges
|
||
******
|
||
|
||
A range expression denotes a range of values ordered between two expressions. It consists of
|
||
two expressions separated by ``..`` and enclosed in brackets (``[`` and ``]``).
|
||
For example, ``[3 .. 7]`` is a valid range expression. Its values are any integers between
|
||
``3`` and ``7`` (including ``3`` and ``7`` themselves).
|
||
|
||
In a valid range, the start and end expression are integers, floats, or dates. If one of them
|
||
is a date, then both must be dates. If one of them is an integer and the other a float, then
|
||
both are treated as floats.
|
||
|
||
.. index:: setliteral
|
||
.. _setliteral:
|
||
|
||
Set literal expressions
|
||
***********************
|
||
|
||
A set literal expression allows the explicit listing of a choice between several values.
|
||
It consists of a comma-separated collection of expressions that are enclosed in brackets (``[`` and ``]``).
|
||
For example, ``[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]`` is a valid set literal expression.
|
||
Its values are the first ten prime numbers.
|
||
|
||
The values of the contained expressions need to be of :ref:`compatible types <type-compatibility>` for a valid set literal expression.
|
||
Furthermore, at least one of the set elements has to be of a type that is a supertype of the types of all
|
||
the other contained expressions.
|
||
|
||
Set literals are supported from release 2.1.0 of the CodeQL CLI, and release 1.24 of LGTM Enterprise.
|
||
|
||
.. index:: super
|
||
.. _super:
|
||
|
||
Super expressions
|
||
*****************
|
||
|
||
Super expressions in QL are similar to super expressions in other programming languages, such
|
||
as Java. You can use them in predicate calls, when you want to use the predicate definition
|
||
from a supertype. In practice, this is useful when a predicate inherits two definitions from
|
||
its supertypes. In that case, the predicate must :ref:`override <overriding-member-predicates>`
|
||
those definitions to avoid ambiguity.
|
||
However, if you want to use the definition from a particular supertype instead of writing a
|
||
new definition, you can use a super expression.
|
||
|
||
In the following example, the class ``C`` inherits two definitions of the predicate
|
||
``getANumber()``—one from ``A`` and one from ``B``.
|
||
Instead of overriding both definitions, it uses the definition from ``B``.
|
||
|
||
::
|
||
|
||
class A extends int {
|
||
A() { this = 1 }
|
||
int getANumber() { result = 2 }
|
||
}
|
||
|
||
class B extends int {
|
||
B() { this = 1 }
|
||
int getANumber() { result = 3 }
|
||
}
|
||
|
||
class C extends A, B {
|
||
// Need to define `int getANumber()`; otherwise it would be ambiguous
|
||
int getANumber() {
|
||
result = B.super.getANumber()
|
||
}
|
||
}
|
||
|
||
from C c
|
||
select c, c.getANumber()
|
||
|
||
The result of this query is ``1, 3``.
|
||
|
||
.. _calls-with-result:
|
||
|
||
Calls to predicates (with result)
|
||
*********************************
|
||
|
||
Calls to :ref:`predicates with results <predicates-with-result>` are themselves expressions,
|
||
unlike calls to :ref:`predicates without results <predicates-without-result>` which are
|
||
formulas. See :ref:`calls` in the :ref:`formulas` topic for more general information about
|
||
calls.
|
||
|
||
A call to a predicate with result evaluates to the values of the ``result`` variable of the
|
||
called predicate.
|
||
|
||
For example ``a.getAChild()`` is a call to a predicate ``getAChild()`` on a variable ``a``.
|
||
This call evaluates to the set of children of ``a``.
|
||
|
||
.. index:: aggregate
|
||
.. _aggregations:
|
||
|
||
Aggregations
|
||
************
|
||
|
||
An aggregation is a mapping that computes a result value from a set of input values that are
|
||
specified by a formula.
|
||
|
||
The general syntax is::
|
||
|
||
<aggregate>(<variable declarations> | <formula> | <expression>)
|
||
|
||
The variables :ref:`declared <variable-declarations>` in ``<variable declarations>`` are called
|
||
the **aggregation variables**.
|
||
|
||
Ordered aggregates (namely ``min``, ``max``, ``rank``, ``concat``, and ``strictconcat``) are
|
||
ordered by their ``<expression>`` values by default. The ordering is either numeric (for
|
||
integers and floating point numbers) or lexicographic (for strings). Lexicographic ordering is
|
||
based on the `Unicode value <https://en.wikipedia.org/wiki/List_of_Unicode_characters#Basic_Latin>`_
|
||
of each character.
|
||
|
||
To specify a different order, follow ``<expression>`` with the keywords ``order by``, then
|
||
the expression that specifies the order, and optionally the keyword ``asc`` or ``desc``
|
||
(to determine whether to order the expression in ascending or descending order). If you don't
|
||
specify an ordering, it defaults to ``asc``.
|
||
|
||
The following aggregates are available in QL:
|
||
|
||
.. index:: count
|
||
|
||
- ``count``: This aggregate determines the number of distinct values of ``<expression>`` for
|
||
each possible assignment of the aggregation variables.
|
||
|
||
For example, the following aggregation returns the number of files that have more than
|
||
``500`` lines::
|
||
|
||
count(File f | f.getTotalNumberOfLines() > 500 | f)
|
||
|
||
If there are no possible assignments to the aggregation variables that satisfy the formula, as in
|
||
``count(int i | i = 1 and i = 2 | i)``, then ``count`` defaults to the value ``0``.
|
||
|
||
.. index:: min, max, minimum, maximum
|
||
|
||
- ``min`` and ``max``: These aggregates determine the smallest (``min``) or largest (``max``)
|
||
value of ``<expression>`` among the possible assignments to the aggregation variables.
|
||
In this case, ``<expression>`` must be of numeric type or of type ``string``.
|
||
|
||
For example, the following aggregation returns the name of the ``.js`` file (or files) with the
|
||
largest number of lines::
|
||
|
||
max(File f | f.getExtension() = "js" | f.getBaseName() order by f.getTotalNumberOfLines())
|
||
|
||
The following aggregation returns the minimum string ``s`` out of the three strings mentioned
|
||
below, that is, the string that comes first in the lexicographic ordering of all the possible
|
||
values of ``s``. (In this case, it returns ``"De Morgan"``.)
|
||
|
||
::
|
||
|
||
min(string s | s = "Tarski" or s = "Dedekind" or s = "De Morgan" | s)
|
||
|
||
.. index:: avg, average
|
||
|
||
- ``avg``: This aggregate determines the average value of ``<expression>`` for all possible
|
||
assignments to the aggregation variables. The type of ``<expression>`` must be numeric.
|
||
If there are no possible assignments to the aggregation variables that satisfy the formula, the aggregation fails and
|
||
returns no values. In other words, it evaluates to the empty set.
|
||
|
||
For example, the following aggregation returns the average of the integers ``0``, ``1``,
|
||
``2``, and ``3``::
|
||
|
||
avg(int i | i = [0 .. 3] | i)
|
||
|
||
.. index:: sum
|
||
|
||
- ``sum``: This aggregate determines the sum of the values of ``<expression>`` over all possible
|
||
assignments to the aggregation variables. The type of ``<expression>`` must be numeric.
|
||
If there are no possible assignments to the aggregation variables that satisfy the formula, then the sum is ``0``.
|
||
|
||
For example, the following aggregation returns the sum of ``i * j`` for all possible values
|
||
of ``i`` and ``j``::
|
||
|
||
sum(int i, int j | i = [0 .. 2] and j = [3 .. 5] | i * j)
|
||
|
||
.. index:: concat
|
||
|
||
- ``concat``: This aggregate concatenates the values of ``<expression>`` over all possible
|
||
assignments to the aggregation variables. Note that ``<expression>`` must be of type
|
||
``string``. If there are no possible assignments to the aggregation variables that satisfy
|
||
the formula, then ``concat`` defaults to the empty string.
|
||
|
||
For example, the following aggregation returns the string ``"3210"``, that is, the
|
||
concatenation of the strings ``"0"``, ``"1"``, ``"2"``, and ``"3"`` in descending order::
|
||
|
||
concat(int i | i = [0 .. 3] | i.toString() order by i desc)
|
||
|
||
The ``concat`` aggregate can also take a second expression, separated from the first one by
|
||
a comma. This second expression is inserted as a separator between each concatenated value.
|
||
|
||
For example, the following aggregation returns ``"0|1|2|3"``::
|
||
|
||
concat(int i | i = [0 .. 3] | i.toString(), "|")
|
||
|
||
.. index:: rank
|
||
|
||
- ``rank``: This aggregate takes the possible values of ``<expression>`` and ranks them.
|
||
In this case, ``<expression>`` must be of numeric type or of type ``string``. The aggregation
|
||
returns the value that is ranked in the position specified by the **rank expression**.
|
||
You must include this rank expression in brackets after the keyword ``rank``.
|
||
|
||
For example, the following aggregation returns the value that is ranked 4th out of all the
|
||
possible values. In this case, ``8`` is the 4th integer in the range from ``5`` through
|
||
``15``::
|
||
|
||
rank[4](int i | i = [5 .. 15] | i)
|
||
|
||
Note that the rank indices start at ``1``, so ``rank[0](...)`` returns no results.
|
||
|
||
.. index:: strictconcat, strictcount, strictsum
|
||
|
||
- ``strictconcat``, ``strictcount``, and ``strictsum``: These aggregates work like ``concat``,
|
||
``count``, and ``sum`` respectively, except that they are *strict*. That is, if there are no
|
||
possible assignments to the aggregation variables that satisfy the formula, then the entire aggregation fails and
|
||
evaluates to the empty set (instead of defaulting to ``0`` or the empty string).
|
||
This is useful if you're only interested in results where the aggregation body is non-trivial.
|
||
|
||
.. index:: unique
|
||
|
||
- ``unique``: This aggregate depends on the values of ``<expression>`` over all possible assignments to
|
||
the aggregation variables. If there is a unique value of ``<expression>`` over the aggregation variables,
|
||
then the aggregate evaluates to that value.
|
||
Otherwise, the aggregate has no value.
|
||
|
||
For example, the following query returns the positive integers ``1``, ``2``, ``3``, ``4``, ``5``.
|
||
For negative integers ``x``, the expressions ``x`` and ``x.abs()`` have different values, so the
|
||
value for ``y`` in the aggregate expression is not uniquely determined. ::
|
||
|
||
from int x
|
||
where x in [-5 .. 5] and x != 0
|
||
select unique(int y | y = x or y = x.abs() | y)
|
||
|
||
The ``unique`` aggregate is supported from release 2.1.0 of the CodeQL CLI, and release 1.24 of LGTM Enterprise.
|
||
|
||
Evaluation of aggregates
|
||
========================
|
||
|
||
In general, aggregate evaluation involves the following steps:
|
||
|
||
#. Determine the input variables: these are the aggregation variables declared in ``<variable declarations>`` and
|
||
also the variables declared outside of the aggregate that are used in some component of the aggregate.
|
||
|
||
#. Generate all possible distinct tuples (combinations) of the values of input variables such that the
|
||
``<formula>`` holds true. Note that the same value of an aggregate variable may appear in
|
||
multiple distinct tuples. All such occurrences of the same value are treated as distinct occurrences
|
||
when processing tuples.
|
||
|
||
#. Apply ``<expression>`` on each tuple and collect the generated (distinct) values. The application
|
||
of ``<expression>`` on a tuple may result in generating more than one value.
|
||
|
||
#. Apply the aggregation function on the values generated in step 3 to compute the final result.
|
||
|
||
Let us apply these steps to the ``sum`` aggregate in the following query:
|
||
|
||
.. code-block:: ql
|
||
|
||
select sum(int i, int j |
|
||
exists(string s | s = "hello".charAt(i)) and exists(string s | s = "world!".charAt(j)) | i)
|
||
|
||
#. Input variables: ``i``, ``j``.
|
||
|
||
#. All possible tuples ``(<value of i>, <value of j>)`` satisfying the given condition:
|
||
``(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 0), (1, 1), ..., (4, 5)``.
|
||
|
||
30 tuples are generated in this step.
|
||
|
||
#. Apply the ``<expression> i`` on all tuples. This means selecting all values of ``i`` from
|
||
all tuples: ``0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4.``
|
||
|
||
#. Apply the aggregation function ``sum`` on the above values to get the final result ``60``.
|
||
|
||
If we change ``<expression>`` to ``i + j`` in the above query, the query result is ``135`` since
|
||
applying ``i + j`` on all tuples results in following values:
|
||
\ ``0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6, 7, 3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 9``.
|
||
|
||
Next, consider the following query:
|
||
|
||
.. code-block:: ql
|
||
|
||
select count(string s | s = "hello" | s.charAt(_))
|
||
|
||
#. ``s`` is the input variable of the aggregate.
|
||
|
||
#. A single tuple ``"hello"`` is generated in this step.
|
||
|
||
#. The ``<expression> charAt(_)`` is applied on this tuple. The underscore ``_`` in ``charAt(_)``
|
||
is a :ref:`don't-care expression <dont-care>`, which represents any value.
|
||
``s.charAt(_)`` generates four distinct values ``h, e, l, o``.
|
||
|
||
#. Finally, ``count`` is applied on these values, and the query returns ``4``.
|
||
|
||
|
||
|
||
Omitting parts of an aggregation
|
||
================================
|
||
|
||
The three parts of an aggregation are not always required, so you can often write the
|
||
aggregation in a simpler form:
|
||
|
||
#. If you want to write an aggregation of the form ``<aggregate>(<type> v | <expression> = v | v)``,
|
||
then you can omit the ``<variable declarations>`` and ``<formula>`` parts and write it
|
||
as follows::
|
||
|
||
<aggregate>(<expression>)
|
||
|
||
For example, the following aggregations determine how many times the letter ``l`` occurs in
|
||
string ``"hello"``. These forms are equivalent::
|
||
|
||
count(int i | i = "hello".indexOf("l") | i)
|
||
count("hello".indexOf("l"))
|
||
|
||
#. If there only one aggregation variable, you can omit the ``<expression>`` part instead.
|
||
In this case, the expression is considered to be the aggregation variable itself.
|
||
For example, the following aggregations are equivalent::
|
||
|
||
avg(int i | i = [0 .. 3] | i)
|
||
avg(int i | i = [0 .. 3])
|
||
|
||
#. As a special case, you can omit the ``<expression>`` part from ``count`` even if there is more
|
||
than one aggregation variable. In such a case, it counts the number of distinct tuples of
|
||
aggregation variables that satisfy the formula. In other words, the expression part is
|
||
considered to be the constant ``1``. For example, the following aggregations are equivalent::
|
||
|
||
count(int i, int j | i in [1 .. 3] and j in [1 .. 3] | 1)
|
||
count(int i, int j | i in [1 .. 3] and j in [1 .. 3])
|
||
|
||
#. You can omit the ``<formula>`` part, but in that case you should include two vertical bars::
|
||
|
||
<aggregate>(<variable declarations> | | <expression>)
|
||
|
||
This is useful if you don't want to restrict the aggregation variables any further.
|
||
For example, the following aggregation returns the maximum number of lines across all files::
|
||
|
||
max(File f | | f.getTotalNumberOfLines())
|
||
|
||
#. Finally, you can also omit both the ``<formula>`` and ``<expression>`` parts. For example,
|
||
the following aggregations are equivalent ways to count the number of files in a database::
|
||
|
||
count(File f | any() | 1)
|
||
count(File f | | 1)
|
||
count(File f)
|
||
|
||
.. _monotonic-aggregates:
|
||
|
||
Monotonic aggregates
|
||
====================
|
||
|
||
In addition to standard aggregates, QL also supports monotonic aggregates.
|
||
Monotonic aggregates differ from standard aggregates in the way that they deal with the
|
||
values generated by the ``<expression>`` part of the formula:
|
||
|
||
- Standard aggregates take the ``<expression>`` values for each ``<formula>`` value and
|
||
flatten them into a list. A single aggregation function is applied to all the values.
|
||
- Monotonic aggregates take an ``<expression>`` for each value given by the ``<formula>``,
|
||
and create combinations of all the possible values. The aggregation
|
||
function is applied to each of the resulting combinations.
|
||
|
||
In general, if the ``<expression>`` is total and functional, then monotonic aggregates are
|
||
equivalent to standard aggregates. Results differ when there is not precisely one ``<expression>``
|
||
value for each value generated by the ``<formula>``:
|
||
|
||
- If there are missing ``<expression>`` values (that is, there is no
|
||
``<expression>`` value for a value generated by the ``<formula>``), monotonic aggregates
|
||
won't compute a result, as you cannot create combinations of values
|
||
including exactly one ``<expression>`` value for each value generated by the ``<formula>``.
|
||
|
||
- If there is more than one ``<expression>`` per ``<formula>`` result, you can create multiple
|
||
combinations of values including exactly one ``<expression>`` value for each
|
||
value generated by the ``<formula>``. Here, the aggregation function is applied to each of the
|
||
resulting combinations.
|
||
|
||
Recursive monotonic aggregates
|
||
------------------------------
|
||
|
||
Monotonic aggregates may be used :ref:`recursively <recursion>`, but the recursive call may only appear in the
|
||
expression, and not in the range. The recursive semantics for aggregates are the same as the
|
||
recursive semantics for the rest of QL. For example, we might define a predicate to calculate
|
||
the distance of a node in a graph from the leaves as follows:
|
||
|
||
.. code-block:: ql
|
||
|
||
int depth(Node n) {
|
||
if not exists(n.getAChild())
|
||
then result = 0
|
||
else result = 1 + max(Node child | child = n.getAChild() | depth(child))
|
||
}
|
||
|
||
Here the recursive call is in the expression, which is legal. The recursive semantics for aggregates
|
||
are the same as the recursive semantics for the rest of QL. If you understand how aggregates work in
|
||
the non-recursive case then you should not find it difficult to use them recursively. However, it is
|
||
worth seeing how the evaluation of a recursive aggregation proceeds.
|
||
|
||
Consider the depth example we just saw with the following graph as input (arrows point from children to parents):
|
||
|
||
.. |image0| image:: ../images/monotonic-aggregates-graph.png
|
||
|
||
|image0|
|
||
|
||
Then the evaluation of the ``depth`` predicate proceeds as follows:
|
||
|
||
+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||
| **Stage** | **depth** | **Comments** |
|
||
+===========+============================================+==========================================================================================================================================================================+
|
||
| 0 | | We always begin with the empty set. |
|
||
+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||
| 1 | ``(0, b), (0, d), (0, e)`` | The nodes with no children have depth 0. The recursive step for **a** and **c** fails to produce a value, since some of their children do not have values for ``depth``. |
|
||
+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||
| 2 | ``(0, b), (0, d), (0, e), (1, c)`` | The recursive step for **c** succeeds, since ``depth`` now has a value for all its children (**d** and **e**). The recursive step for **a** still fails. |
|
||
+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||
| 3 | ``(0, b), (0, d), (0, e), (1, c), (2, a)`` | The recursive step for **a** succeeds, since ``depth`` now has a value for all its children (**b** and **c**). |
|
||
+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||
|
||
Here, we can see that at the intermediate stages it is very important for the aggregate to
|
||
fail if some of the children lack a value - this prevents erroneous values being added.
|
||
|
||
.. index:: any
|
||
|
||
Any
|
||
***
|
||
|
||
The general syntax of an ``any`` expression is similar to the syntax of an
|
||
:ref:`aggregation <aggregations>`, namely::
|
||
|
||
any(<variable declarations> | <formula> | <expression>)
|
||
|
||
You should always include the :ref:`variable declarations <variable-declarations>`, but the
|
||
:ref:`formula <formulas>` and :ref:`expression <expressions>` parts are optional.
|
||
|
||
The ``any`` expression denotes any values that are of a particular form and that satisfy a
|
||
particular condition.
|
||
More precisely, the ``any`` expression:
|
||
|
||
#. Introduces temporary variables.
|
||
#. Restricts their values to those that satisfy the ``<formula>`` part (if it's present).
|
||
#. Returns ``<expression>`` for each of those variables. If there is no ``<expression>`` part,
|
||
then it returns the variables themselves.
|
||
|
||
The following table lists some examples of different forms of ``any`` expressions:
|
||
|
||
+------------------------------------------+-------------------------------------------------+
|
||
| Expression | Values |
|
||
+==========================================+=================================================+
|
||
| ``any(File f)`` | all ``File``\ s in the database |
|
||
+------------------------------------------+-------------------------------------------------+
|
||
| ``any(Element e | e.getName())`` | the names of all ``Element``\ s in the database |
|
||
+------------------------------------------+-------------------------------------------------+
|
||
| ``any(int i | i = [0 .. 3])`` | the integers ``0``, ``1``, ``2``, and ``3`` |
|
||
+------------------------------------------+-------------------------------------------------+
|
||
| ``any(int i | i = [0 .. 3] | i * i)`` | the integers ``0``, ``1``, ``4``, and ``9`` |
|
||
+------------------------------------------+-------------------------------------------------+
|
||
|
||
.. note::
|
||
There is also a `built-in predicate <https://help.semmle.com/QL/ql-spec/language.html#non-member-built-ins>`_
|
||
``any()``. This is a predicate that always holds.
|
||
|
||
Unary operations
|
||
****************
|
||
|
||
A unary operation is a minus sign (``-``) or a plus sign (``+``) followed by an expression of type
|
||
``int`` or ``float``. For example::
|
||
|
||
-6.28
|
||
+(10 - 4)
|
||
+avg(float f | f = 3.4 or f = -9.8)
|
||
-sum(int i | i in [0 .. 9] | i * i)
|
||
|
||
A plus sign leaves the values of the expression unchanged, while a minus sign takes the
|
||
arithmetic negations of the values.
|
||
|
||
.. _binary-operations:
|
||
|
||
Binary operations
|
||
*****************
|
||
|
||
A binary operation consists of an expression, followed by a binary operator, followed by
|
||
another expression. For example::
|
||
|
||
5 % 2
|
||
(9 + 1) / (-2)
|
||
"Q" + "L"
|
||
2 * min(float f | f in [-3 .. 3])
|
||
|
||
.. index:: addition, concatenation, multiplication, division, subtraction, modulo
|
||
seealso: concatenation; concat
|
||
|
||
You can use the following binary operators in QL:
|
||
|
||
+------------------------+--------+
|
||
| Name | Symbol |
|
||
+========================+========+
|
||
| Addition/concatenation | ``+`` |
|
||
+------------------------+--------+
|
||
| Multiplication | ``*`` |
|
||
+------------------------+--------+
|
||
| Division | ``/`` |
|
||
+------------------------+--------+
|
||
| Subtraction | ``-`` |
|
||
+------------------------+--------+
|
||
| Modulo | ``%`` |
|
||
+------------------------+--------+
|
||
|
||
If both expressions are numbers, these operators act as standard arithmetic operators. For
|
||
example, ``10.6 - 3.2`` has value ``7.4``, ``123.456 * 0`` has value ``0``, and ``9 % 4`` has
|
||
value ``1`` (the remainder after dividing ``9`` by ``4``).
|
||
If both operands are integers, then the result is an integer. Otherwise the result is a
|
||
floating-point number.
|
||
|
||
You can also use ``+`` as a string concatenation operator. In this case, at least one of the
|
||
expressions must be a string—the other expression is implicitly converted to a string using the
|
||
``toString()`` predicate. The two expressions are concatenated, and the result is a string. For
|
||
example, the expression ``221 + "B"`` has value ``"221B"``.
|
||
|
||
.. _casts:
|
||
|
||
Casts
|
||
*****
|
||
|
||
A cast allows you to constrain the :ref:`type <types>` of an expression. This is similar to casting in other
|
||
languages, for example in Java.
|
||
|
||
You can write a cast in two ways:
|
||
- As a "postfix" cast: A dot followed by the name of a type in parentheses.
|
||
For example, ``x.(Foo)`` restricts the type of ``x`` to ``Foo``.
|
||
- As a "prefix" cast: A type in parentheses followed by another expression.
|
||
For example, ``(Foo)x`` also restricts the type of ``x`` to ``Foo``.
|
||
|
||
Note that a postfix cast is equivalent to a prefix cast surrounded by parentheses—``x.(Foo)``
|
||
is exactly equivalent to ``((Foo)x)``.
|
||
|
||
Casts are useful if you want to call a :ref:`member predicate <member-predicates>` that is only defined for a more
|
||
specific type. For example, the following query selects Java
|
||
`classes <https://help.semmle.com/qldoc/java/semmle/code/java/Type.qll/type.Type$Class.html>`_
|
||
that have a direct supertype called "List"::
|
||
|
||
import java
|
||
|
||
from Type t
|
||
where t.(Class).getASupertype().hasName("List")
|
||
select t
|
||
|
||
Since the predicate ``getASupertype()`` is defined for ``Class``, but not for ``Type``, you
|
||
can't call ``t.getASupertype()`` directly. The cast ``t.(Class)`` ensures that ``t`` is
|
||
of type ``Class``, so it has access to the desired predicate.
|
||
|
||
If you prefer to use a prefix cast, you can rewrite the ``where`` part as::
|
||
|
||
where ((Class)t).getASupertype().hasName("List")
|
||
|
||
.. index:: underscore
|
||
.. _dont-care:
|
||
|
||
Don't-care expressions
|
||
**********************
|
||
|
||
This is an expression written as a single underscore ``_``. It represents any value. (You
|
||
"don't care" what the value is.)
|
||
|
||
Unlike other expressions, a don't-care expression does not have a type. In practice, this
|
||
means that ``_`` doesn't have any :ref:`member predicates <member-predicates>`, so you can't
|
||
call ``_.somePredicate()``.
|
||
|
||
For example, the following query selects all the characters in the string ``"hello"``::
|
||
|
||
from string s
|
||
where s = "hello".charAt(_)
|
||
select s
|
||
|
||
The ``charAt(int i)`` predicate is defined on strings and usually takes an ``int`` argument.
|
||
Here the don't care expression ``_`` is used to tell the query to select characters at
|
||
every possible index. The query returns the values ``h``, ``e``, ``l``, and ``o``.
|