mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge pull request #4874 from shati-patel/docs-highlighting
Docs: Tweak syntax highlighting
This commit is contained in:
@@ -108,8 +108,8 @@ Count the number of lines of code, excluding the directory ``external``:
|
||||
.. code-block:: ql
|
||||
|
||||
select sum(SourceFile f |
|
||||
not exists(Folder external | external.getShortName() = "external" |
|
||||
external.getAFolder*().getAFile() = f) |
|
||||
not exists(Folder ext | ext.getShortName() = "external" |
|
||||
ext.getAFolder*().getAFile() = f) |
|
||||
f.getNumberOfLines())
|
||||
|
||||
Exercises
|
||||
@@ -961,7 +961,7 @@ Find all obsolete elements:
|
||||
|
||||
Model NUnit test fixtures:
|
||||
|
||||
.. code-block:: csharp
|
||||
.. code-block:: ql
|
||||
|
||||
class TestFixture extends Class
|
||||
{
|
||||
|
||||
@@ -39,6 +39,12 @@ source_encoding = 'utf-8-sig'
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# The default language for syntax highlighting. We need to explicitly set this to "none",
|
||||
# otherwise Sphinx tries to highlight any unlabeled code samples as "python3".
|
||||
# See https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-highlight_language.
|
||||
|
||||
highlight_language = "none"
|
||||
|
||||
# Import the QL Lexer to use for syntax highlighting
|
||||
import os
|
||||
import sys
|
||||
|
||||
@@ -33,7 +33,9 @@ to the name that it aliases.
|
||||
Module aliases
|
||||
==============
|
||||
|
||||
Use the following syntax to define an alias for a :ref:`module <modules>`::
|
||||
Use the following syntax to define an alias for a :ref:`module <modules>`:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
module ModAlias = ModuleName;
|
||||
|
||||
@@ -52,14 +54,18 @@ a deprecation warning is displayed.
|
||||
Type aliases
|
||||
============
|
||||
|
||||
Use the following syntax to define an alias for a :ref:`type <types>`::
|
||||
Use the following syntax to define an alias for a :ref:`type <types>`:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class TypeAlias = TypeName;
|
||||
|
||||
Note that ``class`` is just a keyword. You can define an alias for any type—namely, :ref:`primitive types <primitive-types>`,
|
||||
:ref:`database types <database-types>` and user-defined :ref:`classes <classes>`.
|
||||
|
||||
For example, you can use an alias to abbreviate the name of the primitive type ``boolean`` to ``bool``::
|
||||
For example, you can use an alias to abbreviate the name of the primitive type ``boolean`` to ``bool``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class bool = boolean;
|
||||
|
||||
@@ -80,21 +86,27 @@ Or, to use a class ``OneTwo`` defined in a :ref:`module <explicit-modules>` ``M`
|
||||
Predicate aliases
|
||||
=================
|
||||
|
||||
Use the following syntax to define an alias for a :ref:`non-member predicate <non-member-predicates>`::
|
||||
Use the following syntax to define an alias for a :ref:`non-member predicate <non-member-predicates>`:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
predicate PredAlias = PredicateName/Arity;
|
||||
|
||||
This works for predicates :ref:`with <predicates-with-result>` or :ref:`without <predicates-without-result>` result.
|
||||
|
||||
For example, suppose you frequently use the following predicate, which calculates the successor of a positive integer
|
||||
less than ten::
|
||||
less than ten:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
int getSuccessor(int i) {
|
||||
result = i + 1 and
|
||||
i in [1 .. 9]
|
||||
}
|
||||
|
||||
You can use an alias to abbreviate the name to ``succ``::
|
||||
You can use an alias to abbreviate the name to ``succ``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
predicate succ = getSuccessor/1;
|
||||
|
||||
|
||||
@@ -83,7 +83,9 @@ to describe specific configurations. Any non-abstract subtypes must override it
|
||||
indirectly) to describe what sources of data they each track.
|
||||
|
||||
In other words, all non-abstract classes that extend ``Configuration`` must override ``isSource`` in their
|
||||
own body, or they must inherit from another class that overrides ``isSource``::
|
||||
own body, or they must inherit from another class that overrides ``isSource``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class ConfigA extends Configuration {
|
||||
...
|
||||
@@ -329,8 +331,10 @@ When you use this annotation, be aware of the following issues:
|
||||
In particular, you can't chain predicate :ref:`calls <calls>` or call predicates on a
|
||||
:ref:`cast <casts>`. You must write them as multiple conjuncts and explicitly order them.
|
||||
|
||||
For example, suppose you have the following definitions::
|
||||
|
||||
For example, suppose you have the following definitions:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class Small extends int {
|
||||
Small() { this in [1 .. 10] }
|
||||
Small getSucc() { result = this + 1}
|
||||
@@ -344,8 +348,10 @@ When you use this annotation, be aware of the following issues:
|
||||
s.getSucc().getSucc() = 3
|
||||
}
|
||||
|
||||
If you add ``noopt`` pragmas, you must rewrite the predicates. For example::
|
||||
|
||||
If you add ``noopt`` pragmas, you must rewrite the predicates. For example:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
pragma[noopt]
|
||||
predicate p(int i) {
|
||||
exists(Small s | s = i and s.getSucc() = 2)
|
||||
|
||||
@@ -48,21 +48,27 @@ Here are some common ways that you might define infinite predicates. These all g
|
||||
compilation errors:
|
||||
|
||||
- The following query conceptually selects all values of type ``int``, without restricting them.
|
||||
The QL compiler returns the error ``'i' is not bound to a value``::
|
||||
The QL compiler returns the error ``'i' is not bound to a value``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
from int i
|
||||
select i
|
||||
|
||||
- The following predicate generates two errors: ``'n' is not bound to a value`` and ``'result' is
|
||||
not bound to a value``::
|
||||
not bound to a value``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
int timesTwo(int n) {
|
||||
result = n * 2
|
||||
}
|
||||
|
||||
- The following class ``Person`` contains all strings that start with ``"Peter"``. There are
|
||||
infinitely many such strings, so this is another invalid definition. The QL compiler gives the
|
||||
error message ``'this' is not bound to a value``::
|
||||
error message ``'this' is not bound to a value``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class Person extends string {
|
||||
Person() {
|
||||
|
||||
@@ -37,7 +37,7 @@ You can express certain values directly in QL, such as numbers, booleans, and st
|
||||
possibly starting with a minus sign (``-``).
|
||||
For example:
|
||||
|
||||
.. code-block:: ql
|
||||
.. code-block:: ql
|
||||
|
||||
0
|
||||
42
|
||||
@@ -45,7 +45,9 @@ You can express certain values directly in QL, such as numbers, booleans, and st
|
||||
|
||||
- :ref:`Float <float>` literals: These are sequences of decimal digits separated by a dot
|
||||
(``.``), possibly starting with a minus sign (``-``).
|
||||
For example::
|
||||
For example:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
2.0
|
||||
123.456
|
||||
@@ -56,7 +58,7 @@ You can express certain values directly in QL, such as numbers, booleans, and st
|
||||
characters represent themselves, but there are a few characters that you need to "escape"
|
||||
with a backslash. The following are examples of string literals:
|
||||
|
||||
.. code-block:: ql
|
||||
.. code-block:: ql
|
||||
|
||||
"hello"
|
||||
"They said, \"Please escape quotation marks!\""
|
||||
@@ -135,7 +137,7 @@ In the following example, the class ``C`` inherits two definitions of the predic
|
||||
``getANumber()``—one from ``A`` and one from ``B``.
|
||||
Instead of overriding both definitions, it uses the definition from ``B``.
|
||||
|
||||
::
|
||||
.. code-block:: ql
|
||||
|
||||
class A extends int {
|
||||
A() { this = 1 }
|
||||
@@ -213,7 +215,7 @@ The following aggregates are available in QL:
|
||||
For example, the following aggregation returns the number of files that have more than
|
||||
``500`` lines:
|
||||
|
||||
.. code-block:: ql
|
||||
.. code-block:: ql
|
||||
|
||||
count(File f | f.getTotalNumberOfLines() > 500 | f)
|
||||
|
||||
@@ -229,7 +231,7 @@ The following aggregates are available in QL:
|
||||
For example, the following aggregation returns the name of the ``.js`` file (or files) with the
|
||||
largest number of lines:
|
||||
|
||||
.. code-block:: ql
|
||||
.. code-block:: ql
|
||||
|
||||
max(File f | f.getExtension() = "js" | f.getBaseName() order by f.getTotalNumberOfLines())
|
||||
|
||||
@@ -237,7 +239,7 @@ The following aggregates are available in QL:
|
||||
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"``.)
|
||||
|
||||
::
|
||||
.. code-block:: ql
|
||||
|
||||
min(string s | s = "Tarski" or s = "Dedekind" or s = "De Morgan" | s)
|
||||
|
||||
@@ -249,7 +251,9 @@ The following aggregates are available in QL:
|
||||
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``::
|
||||
``2``, and ``3``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
avg(int i | i = [0 .. 3] | i)
|
||||
|
||||
@@ -260,7 +264,9 @@ The following aggregates are available in QL:
|
||||
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``::
|
||||
of ``i`` and ``j``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
sum(int i, int j | i = [0 .. 2] and j = [3 .. 5] | i * j)
|
||||
|
||||
@@ -274,14 +280,16 @@ The following aggregates are available in QL:
|
||||
For example, the following aggregation returns the string ``"3210"``, that is, the
|
||||
concatenation of the strings ``"0"``, ``"1"``, ``"2"``, and ``"3"`` in descending order:
|
||||
|
||||
.. code-block:: ql
|
||||
.. code-block:: ql
|
||||
|
||||
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"``::
|
||||
For example, the following aggregation returns ``"0|1|2|3"``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
concat(int i | i = [0 .. 3] | i.toString(), "|")
|
||||
|
||||
@@ -294,7 +302,9 @@ The following aggregates are available in QL:
|
||||
|
||||
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``::
|
||||
``15``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
rank[4](int i | i = [5 .. 15] | i)
|
||||
|
||||
@@ -317,7 +327,9 @@ The following aggregates are available in QL:
|
||||
|
||||
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. ::
|
||||
value for ``y`` in the aggregate expression is not uniquely determined.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
from int x
|
||||
where x in [-5 .. 5] and x != 0
|
||||
@@ -394,48 +406,54 @@ aggregation in a simpler form:
|
||||
then you can omit the ``<variable declarations>`` and ``<formula>`` parts and write it
|
||||
as follows:
|
||||
|
||||
.. code-block:: ql
|
||||
.. code-block:: ql
|
||||
|
||||
<aggregate>(<expression>)
|
||||
|
||||
For example, the following aggregations determine how many times the letter ``l`` occurs in
|
||||
string ``"hello"``. These forms are equivalent::
|
||||
string ``"hello"``. These forms are equivalent:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
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.
|
||||
#. If there is 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::
|
||||
|
||||
For example, the following aggregations are equivalent:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
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::
|
||||
|
||||
considered to be the constant ``1``. For example, the following aggregations are equivalent:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
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:
|
||||
|
||||
.. code-block:: ql
|
||||
.. code-block:: ql
|
||||
|
||||
<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:
|
||||
|
||||
.. code-block:: ql
|
||||
.. code-block:: ql
|
||||
|
||||
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:
|
||||
|
||||
.. code-block:: ql
|
||||
.. code-block:: ql
|
||||
|
||||
count(File f | any() | 1)
|
||||
count(File f | | 1)
|
||||
@@ -638,7 +656,9 @@ 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://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Type.qll/type.Type$Class.html>`_
|
||||
that have a direct supertype called "List"::
|
||||
that have a direct supertype called "List":
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import java
|
||||
|
||||
@@ -669,7 +689,9 @@ Unlike other expressions, a don't-care expression does not have a type. In pract
|
||||
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"``::
|
||||
For example, the following query selects all the characters in the string ``"hello"``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
from string s
|
||||
where s = "hello".charAt(_)
|
||||
|
||||
@@ -382,13 +382,14 @@ disjunction.
|
||||
**Example**
|
||||
|
||||
With the following definition, an integer is in the class ``OneTwoThree`` if it is equal to
|
||||
``1``, ``2``, or ``3``::
|
||||
``1``, ``2``, or ``3``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class OneTwoThree extends int {
|
||||
OneTwoThree() {
|
||||
this = 1 or this = 2 or this = 3
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
.. index:: implies
|
||||
@@ -419,15 +420,15 @@ The following query selects any ``SmallInt`` that is odd, or a multiple of ``4``
|
||||
.. [#] The difference between ``A != B`` and ``not A = B`` is due to the underlying quantifiers.
|
||||
If you think of ``A`` and ``B`` as sets of values, then ``A != B`` means:
|
||||
|
||||
.. code-block:: ql
|
||||
.. code-block:: ql
|
||||
|
||||
exists( a, b | a in A and b in B | a != b )
|
||||
exists( a, b | a in A and b in B | a != b )
|
||||
|
||||
On the other hand, ``not A = B`` means:
|
||||
|
||||
.. code-block:: ql
|
||||
.. code-block:: ql
|
||||
|
||||
not exists( a, b | a in A and b in B | a = b )
|
||||
|
||||
This is equivalent to ``forall( a, b | a in A and b in B | a != b )``, which is very
|
||||
different from the first formula.
|
||||
different from the first formula.
|
||||
|
||||
@@ -17,7 +17,9 @@ Defining a module
|
||||
|
||||
There are various ways to define modules—here is an example of the simplest way, declaring an
|
||||
:ref:`explicit module <explicit-modules>` named ``Example`` containing
|
||||
a class ``OneTwoThree``::
|
||||
a class ``OneTwoThree``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
module Example {
|
||||
class OneTwoThree extends int {
|
||||
@@ -115,7 +117,9 @@ the module name, and then the module body enclosed in braces. It can contain any
|
||||
of the elements listed in ":ref:`module-bodies`" below, apart from select clauses.
|
||||
|
||||
For example, you could add the following QL snippet to the library file **OneTwoThreeLib.qll**
|
||||
defined :ref:`above <library-modules>`::
|
||||
defined :ref:`above <library-modules>`:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
...
|
||||
module M {
|
||||
|
||||
@@ -106,7 +106,7 @@ Consider the following :ref:`library module <library-modules>`:
|
||||
|
||||
**CountriesLib.qll**
|
||||
|
||||
::
|
||||
.. code-block:: ql
|
||||
|
||||
class Countries extends string {
|
||||
Countries() {
|
||||
@@ -129,7 +129,9 @@ Consider the following :ref:`library module <library-modules>`:
|
||||
}
|
||||
|
||||
You could write a query that imports ``CountriesLib`` and then uses ``M::EuropeanCountries``
|
||||
to refer to the class ``EuropeanCountries``::
|
||||
to refer to the class ``EuropeanCountries``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import CountriesLib
|
||||
|
||||
@@ -137,7 +139,9 @@ to refer to the class ``EuropeanCountries``::
|
||||
select ec
|
||||
|
||||
Alternatively, you could import the contents of ``M`` directly by using the selection
|
||||
``CountriesLib::M`` in the import statement::
|
||||
``CountriesLib::M`` in the import statement:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import CountriesLib::M
|
||||
|
||||
@@ -246,7 +250,7 @@ were defined in the :ref:`QL tutorials <ql-tutorials>`:
|
||||
|
||||
**Villagers.qll**
|
||||
|
||||
::
|
||||
.. code-block:: ql
|
||||
|
||||
import tutorial
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@ Predicates
|
||||
Predicates are used to describe the logical relations that make up a QL program.
|
||||
|
||||
Strictly speaking, a predicate evaluates to a set of tuples. For example, consider the
|
||||
following two predicate definitions::
|
||||
following two predicate definitions:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
predicate isCountry(string country) {
|
||||
country = "Germany"
|
||||
@@ -143,7 +145,9 @@ on itself.
|
||||
For example, you could use recursion to refine the above example. As it stands, the relation
|
||||
defined in ``getANeighbor`` is not symmetric—it does not capture the fact that if x is a
|
||||
neighbor of y, then y is a neighbor of x. A simple way to capture this is to call this
|
||||
predicate recursively, as shown below::
|
||||
predicate recursively, as shown below:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
string getANeighbor(string country) {
|
||||
country = "France" and result = "Belgium"
|
||||
|
||||
@@ -7,10 +7,6 @@ QL language specification
|
||||
|
||||
This is a formal specification for the QL language. It provides a comprehensive reference for terminology, syntax, and other technical details about QL.
|
||||
|
||||
.. This ``highlight`` directive prevents code blocks in this file being highlighted as QL (the default language for this Sphinx project).
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@ Select clauses
|
||||
**************
|
||||
|
||||
When writing a query module, you can include a **select clause** (usually at the end of the
|
||||
file) of the following form::
|
||||
file) of the following form:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
from /* ... variable declarations ... */
|
||||
where /* ... logical formula ... */
|
||||
@@ -105,7 +107,9 @@ This predicate returns the following results:
|
||||
|
||||
A benefit of writing a query predicate instead of a select clause is that you can call the
|
||||
predicate in other parts of the code too. For example, you can call ``getProduct`` inside
|
||||
the body of a :ref:`class <classes>`::
|
||||
the body of a :ref:`class <classes>`:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class MultipleOfThree extends int {
|
||||
MultipleOfThree() { this = getProduct(_, _) }
|
||||
|
||||
@@ -29,7 +29,9 @@ Counting from 0 to 100
|
||||
======================
|
||||
|
||||
The following query uses the predicate ``getANumber()`` to list all integers from 0 to 100
|
||||
(inclusive)::
|
||||
(inclusive):
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
int getANumber() {
|
||||
result = 0
|
||||
@@ -46,7 +48,9 @@ Mutual recursion
|
||||
================
|
||||
|
||||
Predicates can be mutually recursive, that is, you can have a cycle of predicates that
|
||||
depend on each other. For example, here is a QL query that counts to 100 using even numbers::
|
||||
depend on each other. For example, here is a QL query that counts to 100 using even numbers:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
int getAnEven() {
|
||||
result = 0
|
||||
@@ -89,7 +93,9 @@ helpful abbreviations:
|
||||
``p``, and so on.
|
||||
|
||||
Using this ``+`` notation is often simpler than defining the recursive predicate explicitly.
|
||||
In this case, an explicit definition could look like this::
|
||||
In this case, an explicit definition could look like this:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
Person getAnAncestor() {
|
||||
result = this.getAParent()
|
||||
@@ -107,7 +113,9 @@ helpful abbreviations:
|
||||
For example, the result of ``p.getAParent*()`` is an ancestor of ``p`` (as above), or ``p``
|
||||
itself.
|
||||
|
||||
In this case, the explicit definition looks like this::
|
||||
In this case, the explicit definition looks like this:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
Person getAnAncestor2() {
|
||||
result = this
|
||||
@@ -176,7 +184,9 @@ According to this definition, the predicate ``isParadox()`` holds precisely when
|
||||
This is impossible, so there is no fixed point solution to the recursion.
|
||||
|
||||
If the recursion appears under an even number of negations, then this isn't a problem.
|
||||
For example, consider the following (slightly macabre) member predicate of class ``Person``::
|
||||
For example, consider the following (slightly macabre) member predicate of class ``Person``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
predicate isExtinct() {
|
||||
this.isDead() and
|
||||
|
||||
@@ -163,7 +163,9 @@ The expression ``(OneTwoThree)`` is a :ref:`cast <casts>`. It ensures that ``1``
|
||||
``getAString()``.
|
||||
|
||||
Member predicates are especially useful because you can chain them together. For example, you
|
||||
can use ``toUpperCase()``, a built-in function defined for ``string``::
|
||||
can use ``toUpperCase()``, a built-in function defined for ``string``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
1.(OneTwoThree).getAString().toUpperCase()
|
||||
|
||||
@@ -172,9 +174,7 @@ This call returns ``"ONE, TWO OR THREE: 1"``.
|
||||
.. index:: this
|
||||
.. _this:
|
||||
|
||||
.. note:
|
||||
|
||||
.. code-block:: ql
|
||||
.. pull-quote:: Note
|
||||
|
||||
Characteristic predicates and member predicates often use the variable ``this``.
|
||||
This variable always refers to a member of the class—in this case a value belonging to the
|
||||
@@ -195,7 +195,9 @@ declarations (that is, variable declarations) within its body. You can use these
|
||||
predicate declarations inside the class. Much like the :ref:`variable <this>` ``this``, fields
|
||||
must be constrained in the :ref:`characteristic predicate <characteristic-predicates>`.
|
||||
|
||||
For example::
|
||||
For example:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class SmallInt extends int {
|
||||
SmallInt() { this = [1 .. 10] }
|
||||
@@ -283,7 +285,9 @@ 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.
|
||||
|
||||
For example, extending the class from the :ref:`first example <defining-a-class>`::
|
||||
For example, extending the class from the :ref:`first example <defining-a-class>`:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class OneTwo extends OneTwoThree {
|
||||
OneTwo() {
|
||||
@@ -298,7 +302,9 @@ For example, extending the class from the :ref:`first example <defining-a-class>
|
||||
The member predicate ``getAString()`` overrides the original definition of ``getAString()``
|
||||
from ``OneTwoThree``.
|
||||
|
||||
Now, consider the following query::
|
||||
Now, consider the following query:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
from OneTwoThree o
|
||||
select o, o.getAString()
|
||||
@@ -318,7 +324,9 @@ look like this:
|
||||
|
||||
In QL, unlike other object-oriented languages, different subtypes of the same types don't need to be
|
||||
disjoint. For example, you could define another subclass of ``OneTwoThree``, which overlaps
|
||||
with ``OneTwo``::
|
||||
with ``OneTwo``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class TwoThree extends OneTwoThree {
|
||||
TwoThree() {
|
||||
@@ -429,7 +437,9 @@ It also means that a unique ``NoCall`` value is produced.
|
||||
Defining an algebraic datatype
|
||||
==============================
|
||||
|
||||
To define an algebraic datatype, use the following general syntax::
|
||||
To define an algebraic datatype, use the following general syntax:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
newtype <TypeName> = <branches>
|
||||
|
||||
@@ -478,7 +488,9 @@ In the standard QL language libraries, this is usually done as follows:
|
||||
For example, the following code snippet from the CodeQL data-flow library for C# defines classes
|
||||
for dealing with tainted or untainted values. In this case, it doesn't make sense for
|
||||
``TaintType`` to extend a database type. It is part of the taint analysis, not the underlying
|
||||
program, so it's helpful to extend a new type (namely ``TTaintType``)::
|
||||
program, so it's helpful to extend a new type (namely ``TTaintType``):
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
private newtype TTaintType =
|
||||
TExactValue()
|
||||
@@ -535,7 +547,9 @@ For example, the following construction is legal:
|
||||
}
|
||||
|
||||
However, a similar implementation that restricts ``InitialValueSource`` in a class extension is not valid.
|
||||
If we had implemented ``DefiniteInitialization`` as a class extension instead, it would trigger a type test for ``InitialValueSource``. This results in an illegal recursion ``DefiniteInitialization -> InitialValueSource -> UnknownInitialGarbage -> ¬DefiniteInitialization`` since ``UnknownInitialGarbage`` relies on ``DefiniteInitialization``::
|
||||
If we had implemented ``DefiniteInitialization`` as a class extension instead, it would trigger a type test for ``InitialValueSource``. This results in an illegal recursion ``DefiniteInitialization -> InitialValueSource -> UnknownInitialGarbage -> ¬DefiniteInitialization`` since ``UnknownInitialGarbage`` relies on ``DefiniteInitialization``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
// THIS WON'T WORK: The implicit type check for InitialValueSource involves an illegal recursion
|
||||
// DefiniteInitialization -> InitialValueSource -> UnknownInitialGarbage -> ¬DefiniteInitialization!
|
||||
|
||||
@@ -21,7 +21,9 @@ For more information on how to format your code when contributing queries to the
|
||||
Basic query structure
|
||||
*********************
|
||||
|
||||
:ref:`Queries <queries>` written with CodeQL have the file extension ``.ql``, and contain a ``select`` clause. Many of the existing queries include additional optional information, and have the following structure::
|
||||
:ref:`Queries <queries>` written with CodeQL have the file extension ``.ql``, and contain a ``select`` clause. Many of the existing queries include additional optional information, and have the following structure:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -44,7 +44,9 @@ Constructing a path query
|
||||
Path queries require certain metadata, query predicates, and ``select`` statement structures.
|
||||
Many of the built-in path queries included in CodeQL follow a simple structure, which depends on how the language you are analyzing is modeled with CodeQL.
|
||||
|
||||
For C/C++, C#, Java, and JavaScript you should use the following template::
|
||||
For C/C++, C#, Java, and JavaScript you should use the following template:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
/**
|
||||
* ...
|
||||
@@ -66,7 +68,9 @@ Where:
|
||||
- ``source`` and ``sink`` are nodes on the `path graph <https://en.wikipedia.org/wiki/Path_graph>`__, and ``DataFlow::PathNode`` is their type.
|
||||
- ``Configuration`` is a class containing the predicates which define how data may flow between the ``source`` and the ``sink``.
|
||||
|
||||
For Python you should use a slightly different template::
|
||||
For Python you should use a slightly different template:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
/**
|
||||
* ...
|
||||
@@ -104,13 +108,17 @@ To do this you need to define a :ref:`query predicate <query-predicates>` called
|
||||
This predicate defines the edge relations of the graph you are computing, and it is used to compute the paths related to each result that your query generates.
|
||||
You can import a predefined ``edges`` predicate from a path graph module in one of the standard data flow libraries. In addition to the path graph module, the data flow libraries contain the other ``classes``, ``predicates``, and ``modules`` that are commonly used in data flow analysis. The import statement to use depends on the language that you are analyzing.
|
||||
|
||||
For C/C++, C#, Java, and JavaScript you would use::
|
||||
For C/C++, C#, Java, and JavaScript you would use:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import DataFlow::PathGraph
|
||||
|
||||
This statement imports the ``PathGraph`` module from the data flow library (``DataFlow.qll``), in which ``edges`` is defined.
|
||||
|
||||
For Python, the ``Paths`` module contains the ``edges`` predicate::
|
||||
For Python, the ``Paths`` module contains the ``edges`` predicate:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import semmle.python.security.Paths
|
||||
|
||||
@@ -121,7 +129,9 @@ For all languages, you can also optionally define a ``nodes`` query predicate, w
|
||||
Defining your own ``edges`` predicate
|
||||
-------------------------------------
|
||||
|
||||
You can also define your own ``edges`` predicate in the body of your query. It should take the following form::
|
||||
You can also define your own ``edges`` predicate in the body of your query. It should take the following form:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
query predicate edges(PathNode a, PathNode b) {
|
||||
/** Logical conditions which hold if `(a,b)` is an edge in the data flow graph */
|
||||
@@ -136,7 +146,9 @@ You must provide information about the ``source`` and ``sink`` in your path quer
|
||||
The name and the type of the ``source`` and the ``sink`` must be declared in the ``from`` statement of the query, and the types must be compatible with the nodes of the graph computed by the ``edges`` predicate.
|
||||
|
||||
If you are querying C/C++, C#, Java, or JavaScript code (and you have used ``import DataFlow::PathGraph`` in your query), the definitions of the ``source`` and ``sink`` are accessed via the ``Configuration`` class in the data flow library. You should declare all three of these objects in the ``from`` statement.
|
||||
For example::
|
||||
For example:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
|
||||
@@ -149,7 +161,9 @@ For more information on using the configuration class in your analysis see the s
|
||||
|
||||
You can also create a configuration for different frameworks and environments by extending the ``Configuration`` class. For more information, see ":ref:`Types <defining-a-class>`" in the QL language reference.
|
||||
|
||||
If you are querying Python code (and you have used ``import semmle.python.security.Paths`` in your query) you should declare ``TaintedPathSource source, TaintedPathSink sink`` in your ``from`` statement. You do not need to declare a ``Configuration`` class as the definitions of the ``TaintedPathSource`` and ``TaintedPathSink`` contain all of the type information that is required::
|
||||
If you are querying Python code (and you have used ``import semmle.python.security.Paths`` in your query) you should declare ``TaintedPathSource source, TaintedPathSink sink`` in your ``from`` statement. You do not need to declare a ``Configuration`` class as the definitions of the ``TaintedPathSource`` and ``TaintedPathSink`` contain all of the type information that is required:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
from TaintedPathSource source, TaintedPathSink sink
|
||||
|
||||
@@ -163,11 +177,15 @@ This clause can use :ref:`aggregations <aggregations>`, :ref:`predicates <predic
|
||||
|
||||
When writing a path queries, you would typically include a predicate that holds only if data flows from the ``source`` to the ``sink``.
|
||||
|
||||
For C/C++, C#, Java or JavaScript, you would use the ``hasFlowPath`` predicate to define flow from the ``source`` to the ``sink`` for a given ``Configuration``::
|
||||
For C/C++, C#, Java or JavaScript, you would use the ``hasFlowPath`` predicate to define flow from the ``source`` to the ``sink`` for a given ``Configuration``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
where config.hasFlowPath(source, sink)
|
||||
|
||||
For Python, you would simply use the ``flowsTo`` predicate to define flow from the ``source`` to the ``sink``::
|
||||
For Python, you would simply use the ``flowsTo`` predicate to define flow from the ``source`` to the ``sink``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
where source.flowsTo(sink)
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ a piece of cargo.
|
||||
*Show/hide code*
|
||||
|
||||
.. literalinclude:: river-crossing.ql
|
||||
:language: ql
|
||||
:lines: 15-23
|
||||
|
||||
Second, any item can be on one of two shores. Let's call these the "left shore" and the "right shore".
|
||||
@@ -63,6 +64,7 @@ You can do this by defining a member predicate
|
||||
*Show/hide code*
|
||||
|
||||
.. literalinclude:: river-crossing.ql
|
||||
:language: ql
|
||||
:lines: 25-38
|
||||
|
||||
We also want a way to keep track of where the man, the goat, the cabbage, and the wolf are at any point. We can call this combined
|
||||
@@ -80,6 +82,7 @@ temporary variables in the body of a class are called :ref:`fields <fields>`.
|
||||
*Show/hide code*
|
||||
|
||||
.. literalinclude:: river-crossing-1.ql
|
||||
:language: ql
|
||||
:lines: 33-40,87
|
||||
|
||||
We are interested in two particular states, namely the initial state and the goal state,
|
||||
@@ -94,6 +97,7 @@ Assuming that all items start on the left shore and end up on the right shore, d
|
||||
*Show/hide code*
|
||||
|
||||
.. literalinclude:: river-crossing-1.ql
|
||||
:language: ql
|
||||
:lines: 89-97
|
||||
|
||||
.. pull-quote::
|
||||
@@ -112,6 +116,7 @@ Using the above note, the QL code so far looks like this:
|
||||
*Show/hide code*
|
||||
|
||||
.. literalinclude:: river-crossing.ql
|
||||
:language: ql
|
||||
:lines: 15-52,103-113
|
||||
|
||||
Model the action of "ferrying"
|
||||
@@ -130,6 +135,7 @@ after ferrying a particular cargo. (Hint: Use the predicate ``other``.)
|
||||
*Show/hide code*
|
||||
|
||||
.. literalinclude:: river-crossing.ql
|
||||
:language: ql
|
||||
:lines: 54-67
|
||||
|
||||
Of course, not all ferrying actions are possible. Add some extra conditions to describe when a ferrying
|
||||
@@ -147,6 +153,7 @@ For example, follow these steps:
|
||||
*Show/hide code*
|
||||
|
||||
.. literalinclude:: river-crossing.ql
|
||||
:language: ql
|
||||
:lines: 69-81
|
||||
|
||||
Find paths from one state to another
|
||||
@@ -185,6 +192,7 @@ for example ``steps <= 7``.
|
||||
*Show/hide code*
|
||||
|
||||
.. literalinclude:: river-crossing-1.ql
|
||||
:language: ql
|
||||
:lines: 70-86
|
||||
|
||||
However, although this ensures that the solution is finite, it can still contain loops if the upper bound
|
||||
@@ -215,6 +223,7 @@ the given path without revisiting any previously visited states.
|
||||
*Show/hide code*
|
||||
|
||||
.. literalinclude:: river-crossing.ql
|
||||
:language: ql
|
||||
:lines: 83-102
|
||||
|
||||
Display the results
|
||||
@@ -230,6 +239,7 @@ that returns the resulting path.
|
||||
*Show/hide code*
|
||||
|
||||
.. literalinclude:: river-crossing.ql
|
||||
:language: ql
|
||||
:lines: 115-117
|
||||
|
||||
The :ref:`don't-care expression <don-t-care-expressions>` (``_``),
|
||||
|
||||
@@ -27,7 +27,9 @@ The performance of a predicate can often be judged by considering roughly how ma
|
||||
One way of creating badly performing predicates is by using two variables without relating them in any way, or only relating them using a negation.
|
||||
This leads to computing the `Cartesian product <https://en.wikipedia.org/wiki/Cartesian_product>`__ between the sets of possible values for each variable, potentially generating a huge table of results.
|
||||
This can occur if you don't specify restrictions on your variables.
|
||||
For instance, consider the following predicate that checks whether a Java method ``m`` may access a field ``f``::
|
||||
For instance, consider the following predicate that checks whether a Java method ``m`` may access a field ``f``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
predicate mayAccess(Method m, Field f) {
|
||||
f.getAnAccess().getEnclosingCallable() = m
|
||||
@@ -39,7 +41,9 @@ The predicate holds if ``m`` contains an access to ``f``, but also conservativel
|
||||
|
||||
However, if ``m`` is a native method, the table computed by ``mayAccess`` will contain a row ``m, f`` for *all* fields ``f`` in the codebase, making it potentially very large.
|
||||
|
||||
This example shows a similar mistake in a member predicate::
|
||||
This example shows a similar mistake in a member predicate:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class Foo extends Class {
|
||||
...
|
||||
@@ -57,11 +61,15 @@ Use specific types
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
":ref:`Types <types>`" provide an upper bound on the size of a relation.
|
||||
This helps the query optimizer be more effective, so it's generally good to use the most specific types possible. For example::
|
||||
This helps the query optimizer be more effective, so it's generally good to use the most specific types possible. For example:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
predicate foo(LoggingCall e)
|
||||
|
||||
is preferred over::
|
||||
is preferred over:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
predicate foo(Expr e)
|
||||
|
||||
@@ -95,7 +103,9 @@ Avoid complex recursion
|
||||
":ref:`Recursion <recursion>`" is about self-referencing definitions.
|
||||
It can be extremely powerful as long as it is used appropriately.
|
||||
On the whole, you should try to make recursive predicates as simple as possible.
|
||||
That is, you should define a *base case* that allows the predicate to *bottom out*, along with a single *recursive call*::
|
||||
That is, you should define a *base case* that allows the predicate to *bottom out*, along with a single *recursive call*:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
int depth(Stmt s) {
|
||||
exists(Callable c | c.getBody() = s | result = 0) // base case
|
||||
|
||||
Reference in New Issue
Block a user