Merge pull request #4874 from shati-patel/docs-highlighting

Docs: Tweak syntax highlighting
This commit is contained in:
Shati Patel
2021-01-06 10:51:01 +00:00
committed by GitHub
18 changed files with 222 additions and 93 deletions

View File

@@ -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
{

View File

@@ -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

View File

@@ -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;

View File

@@ -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)

View File

@@ -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() {

View File

@@ -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(_)

View File

@@ -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.

View File

@@ -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 {

View File

@@ -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

View File

@@ -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"

View File

@@ -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
------------

View File

@@ -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(_, _) }

View File

@@ -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

View File

@@ -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!

View File

@@ -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
/**
*

View File

@@ -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)

View File

@@ -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>` (``_``),

View File

@@ -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