Merge remote-tracking branch 'origin/codeql-cli-2.11.5' into smowton/admin/merge-2.11.5-into-rc38
@@ -3,7 +3,9 @@
|
||||
Basic query for C and C++ code
|
||||
==============================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
@@ -14,62 +16,33 @@ The query we're going to run performs a basic search of the code for ``if`` stat
|
||||
|
||||
if (error) { }
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
#. Click the project in the search results.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **C/C++** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete ``select ""`` and paste the following query beneath the import statement ``import cpp``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import cpp
|
||||
|
||||
from IfStmt ifstmt, BlockStmt block
|
||||
where ifstmt.getThen() = block and
|
||||
block.getNumStmt() = 0
|
||||
select ifstmt, "This 'if' statement is redundant."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-cpp-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click a link in the ``ifstmt`` column to open the file and highlight the matching ``if`` statement.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-cpp-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/4242591143131494898/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``ifstmt`` column to view the ``if`` statement in the code viewer.
|
||||
|
||||
The matching ``if`` statement is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -120,7 +93,7 @@ In this case, identifying the ``if`` statement with the empty ``then`` branch as
|
||||
|
||||
To exclude ``if`` statements that have an ``else`` branch:
|
||||
|
||||
#. Extend the ``where`` clause to include the following extra condition:
|
||||
#. Edit your query and extend the ``where`` clause to include the following extra condition:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
@@ -134,14 +107,24 @@ To exclude ``if`` statements that have an ``else`` branch:
|
||||
block.getNumStmt() = 0 and
|
||||
not ifstmt.hasElse()
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results because ``if`` statements with an ``else`` branch are no longer reported.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/1899933116489579248/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/cpp-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
|
||||
.. |language-text| replace:: C/C++
|
||||
|
||||
.. |language-code| replace:: ``cpp``
|
||||
|
||||
.. |example-url| replace:: https://github.com/protocolbuffers/protobuf
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-cpp.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs.
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
Basic query for C# code
|
||||
=======================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
@@ -14,62 +16,33 @@ The query we're going to run performs a basic search of the code for ``if`` stat
|
||||
|
||||
if (error) { }
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
#. Click the project in the search results.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **C#** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete ``select ""`` and paste the following query beneath the import statement ``import csharp``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import csharp
|
||||
|
||||
from IfStmt ifstmt, BlockStmt block
|
||||
where ifstmt.getThen() = block and
|
||||
block.isEmpty()
|
||||
select ifstmt, "This 'if' statement is redundant."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-csharp-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click a link in the ``ifstmt`` column to open the file and highlight the matching ``if`` statement.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-csharp-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/1214010107827821393/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``ifstmt`` column to view the ``if`` statement in the code viewer.
|
||||
|
||||
The matching ``if`` statement is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -139,14 +112,23 @@ To exclude ``if`` statements that have an ``else`` branch:
|
||||
block.isEmpty() and
|
||||
not exists(ifstmt.getElse())
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results because ``if`` statements with an ``else`` branch are no longer included.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/6233102733683510530/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/csharp-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
.. |language-text| replace:: C#
|
||||
|
||||
.. |language-code| replace:: ``csharp``
|
||||
|
||||
.. |example-url| replace:: https://github.com/PowerShell/PowerShell
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-csharp.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs.
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
Basic query for Go code
|
||||
=======================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
@@ -22,29 +24,17 @@ This is problematic because the receiver argument is passed by value, not by ref
|
||||
|
||||
For further information on using methods on values or pointers in Go, see the `Go FAQ <https://golang.org/doc/faq#methods_on_values_or_pointers>`__.
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
#. Click the project in the search results.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **Go** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete ``select ""`` and paste the following query beneath the import statement ``import go``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import go
|
||||
|
||||
from Method m, Variable recv, Write w, Field f
|
||||
where
|
||||
recv = m.getReceiver() and
|
||||
@@ -52,34 +42,17 @@ Running the query
|
||||
not recv.getType() instanceof PointerType
|
||||
select w, "This update to " + f + " has no effect, because " + recv + " is not a pointer."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-go-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click a link in the ``w`` column to open the file and highlight the matching location.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-go-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to ``w``, which is the location in the source code where the receiver ``recv`` is modified. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/6221190009056970603/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``w`` column to view it in the code viewer.
|
||||
|
||||
The matching ``w`` is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -140,14 +113,24 @@ To exclude these values:
|
||||
not recv.getType() instanceof PointerType and
|
||||
not exists(ReturnStmt ret | ret.getExpr() = recv.getARead().asExpr())
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results because value methods that return their receiver variable are no longer reported.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/9110448975027954322/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/go-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
|
||||
.. |language-text| replace:: Go
|
||||
|
||||
.. |language-code| replace:: ``go``
|
||||
|
||||
.. |example-url| replace:: https://github.com/go-gorm/gorm
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-go.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to ``w``, which is the location in the source code where the receiver ``recv`` is modified.
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
Basic query for Java and Kotlin code
|
||||
====================================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
@@ -29,65 +31,36 @@ or Kotlin code such as:
|
||||
In either case, replacing ``s.equals("")`` with ``s.isEmpty()``
|
||||
would be more efficient.
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
#. Click the project in the search results.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **Java** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete ``select ""`` and paste the following query beneath the import statement ``import java``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import java
|
||||
|
||||
from MethodAccess ma
|
||||
where
|
||||
ma.getMethod().hasName("equals") and
|
||||
ma.getArgument(0).(StringLiteral).getValue() = ""
|
||||
select ma, "This comparison to empty string is inefficient, use isEmpty() instead."
|
||||
from MethodAccess ma
|
||||
where
|
||||
ma.getMethod().hasName("equals") and
|
||||
ma.getArgument(0).(StringLiteral).getValue() = ""
|
||||
select ma, "This comparison to empty string is inefficient, use isEmpty() instead."
|
||||
|
||||
Note that CodeQL treats Java and Kotlin as part of the same language, so even though this query starts with ``import java``, it will work for both Java and Kotlin code.
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-java-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click a link in the ``ma`` column to view the ``.equals`` expression in the code viewer.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-java-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``ma`` and is linked to the location in the source code of the project where ``ma`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/6863787472564633674/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``ma`` column to view the ``.equals`` expression in the code viewer.
|
||||
|
||||
The matching ``.equals`` expression is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -148,14 +121,24 @@ In this case, it is not possible to simply use ``o.isEmpty()`` instead, as ``o``
|
||||
ma.getMethod().hasName("equals") and
|
||||
ma.getArgument(0).(StringLiteral).getValue() = ""
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results because ``.equals`` expressions with different types are no longer included.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/3716567543394265485/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/java-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
|
||||
.. |language-text| replace:: Java
|
||||
|
||||
.. |language-code| replace:: ``java``
|
||||
|
||||
.. |example-url| replace:: https://github.com/apache/activemq
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-java.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to the expression ``ma`` and is linked to the location in the source code of the project where ``ma`` occurs.
|
||||
@@ -3,7 +3,9 @@
|
||||
Basic query for JavaScript code
|
||||
===============================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
@@ -12,62 +14,33 @@ In JavaScript, any expression can be turned into an expression statement. While
|
||||
|
||||
The query you will run finds instances of this problem. The query searches for expressions ``e`` that are pure—that is, their evaluation does not lead to any side effects—but appear as an expression statement.
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
#. Click the project in the search results.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **JavaScript** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete ``select ""`` and paste the following query beneath the import statement ``import javascript``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import javascript
|
||||
|
||||
from Expr e
|
||||
where e.isPure() and
|
||||
e.getParent() instanceof ExprStmt
|
||||
select e, "This expression has no effect."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-js-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click one of the links in the ``e`` column to open the file and highlight the matching expression.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-js-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``e`` and is linked to the location in the source code of the project where ``e`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/5137013631828816943/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click one of the links in the ``e`` column to view the expression in the code viewer.
|
||||
|
||||
The matching statement is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -119,11 +92,14 @@ To remove directives from the results:
|
||||
e.getParent() instanceof ExprStmt and
|
||||
not e.getParent() instanceof Directive
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results as ``use strict`` directives are no longer reported.
|
||||
|
||||
The improved query finds several results on the example project including `this result <https://lgtm.com/projects/g/ajaxorg/ace/rev/ad50673d7137c09d1a5a6f0ef83633a149f9e3d1/files/lib/ace/keyboard/vim.js#L320>`__:
|
||||
The improved query finds several results on the example project including the result below:
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-js-query-results-1.png
|
||||
:align: center
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
@@ -136,3 +112,15 @@ Further reading
|
||||
|
||||
.. include:: ../reusables/javascript-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
|
||||
.. |language-text| replace:: JavaScript/TypeScript
|
||||
|
||||
.. |language-code| replace:: ``javascript``
|
||||
|
||||
.. |example-url| replace:: https://github.com/ajaxorg/ace
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-js.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to the expression ``e`` and is linked to the location in the source code of the project where ``e`` occurs.
|
||||
@@ -3,7 +3,9 @@
|
||||
Basic query for Python code
|
||||
===========================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
@@ -14,62 +16,33 @@ The query we're going to run performs a basic search of the code for ``if`` stat
|
||||
|
||||
if error: pass
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
#. Click the project in the search results.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **Python** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete ``select ""`` and paste the following query beneath the import statement ``import python``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import python
|
||||
|
||||
from If ifstmt, Stmt pass
|
||||
where pass = ifstmt.getStmt(0) and
|
||||
pass instanceof Pass
|
||||
select ifstmt, "This 'if' statement is redundant."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-python-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click a link in the ``ifstmt`` column to open the file and highlight the matching ``if`` statement.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-python-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/3592297537117272922/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``ifstmt`` column to view the ``if`` statement in the code viewer.
|
||||
|
||||
The matching ``if`` statement is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -133,14 +106,24 @@ To exclude ``if`` statements that have an ``else`` branch:
|
||||
pass instanceof Pass and
|
||||
not exists(ifstmt.getOrelse())
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results because ``if`` statements with an ``else`` branch are no longer included.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/3424727946018612474/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/python-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
|
||||
.. |language-text| replace:: Python
|
||||
|
||||
.. |language-code| replace:: ``python``
|
||||
|
||||
.. |example-url| replace:: https://github.com/saltstack/salt
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-python.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs.
|
||||
@@ -3,7 +3,9 @@
|
||||
Basic query for Ruby code
|
||||
=========================
|
||||
|
||||
Learn to write and run a simple CodeQL query.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
@@ -15,24 +17,14 @@ The query we're going to run performs a basic search of the code for ``if`` expr
|
||||
if error
|
||||
# Handle the error
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
#. Click the project in the search results.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **Ruby** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete the content and paste in the following query.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
@@ -40,37 +32,20 @@ Running the query
|
||||
|
||||
from IfExpr ifexpr
|
||||
where
|
||||
not exists(ifexpr.getThen())
|
||||
not exists(ifexpr.getThen())
|
||||
select ifexpr, "This 'if' expression is redundant."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-ruby-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click a link in the ``ifexpr`` column to open the file and highlight the matching ``if`` statement.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-ruby-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``ifexpr`` and is linked to the location in the source code of the project where ``ifexpr`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/4416853782037269427/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``ifexpr`` column to view the ``if`` statement in the code viewer.
|
||||
|
||||
The matching ``if`` expression is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -131,14 +106,24 @@ To exclude ``if`` statements that have an ``else`` branch:
|
||||
not exists(ifexpr.getThen()) and
|
||||
not exists(ifexpr.getElse())
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results because ``if`` expressions with an ``else`` branch are no longer included.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/4694253275631320752/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/ruby-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
|
||||
.. |language-text| replace:: Ruby
|
||||
|
||||
.. |language-code| replace:: ``ruby``
|
||||
|
||||
.. |example-url| replace:: https://github.com/discourse/discourse
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-ruby.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to the expression ``ifexpr`` and is linked to the location in the source code of the project where ``ifexpr`` occurs.
|
||||
|
||||
@@ -123,8 +123,6 @@ Select expressions that cast a value to a type parameter:
|
||||
where assertion.getTypeAnnotation() = param.getLocalTypeName().getAnAccess()
|
||||
select assertion, "Cast to type parameter."
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1505979606441/>`__.
|
||||
|
||||
Classes and interfaces
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -179,7 +177,7 @@ Ambient nodes are mostly ignored by control flow and data flow analysis. The out
|
||||
Static type information
|
||||
-----------------------
|
||||
|
||||
Static type information and global name binding is available for projects with "full" TypeScript extraction enabled. This option is enabled by default for projects on LGTM.com and when you create databases with the :ref:`CodeQL CLI <codeql-cli>`.
|
||||
Static type information and global name binding is available for projects with "full" TypeScript extraction enabled. This option is enabled by default when you create databases with the :ref:`CodeQL CLI <codeql-cli>`.
|
||||
|
||||
Basic usage
|
||||
~~~~~~~~~~~
|
||||
@@ -403,8 +401,6 @@ It is best to use `TypeName <https://codeql.github.com/codeql-standard-libraries
|
||||
and not access.hasTypeArguments()
|
||||
select access, "Type arguments are omitted"
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1505985316500/>`__.
|
||||
|
||||
Find imported names that are used as both a type and a value:
|
||||
|
||||
.. code-block:: ql
|
||||
@@ -416,8 +412,6 @@ Find imported names that are used as both a type and a value:
|
||||
and exists (VarAccess access | access.getVariable().getADeclaration() = spec.getLocal())
|
||||
select spec, "Used as both variable and type"
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1505975787348/>`__.
|
||||
|
||||
Namespace names
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ We can use the ``Callable`` class to write a query that finds methods that are n
|
||||
where not exists(Callable caller | caller.polyCalls(callee))
|
||||
select callee
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8376915232270534450/>`__. This simple query typically returns a large number of results.
|
||||
This simple query typically returns a large number of results.
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
@@ -99,7 +99,7 @@ Running this query on a typical Java project results in lots of hits in the Java
|
||||
callee.getCompilationUnit().fromSource()
|
||||
select callee, "Not called."
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8711624074465690976/>`__. This change reduces the number of results returned for most projects.
|
||||
This change reduces the number of results returned for most codebases.
|
||||
|
||||
We might also notice several unused methods with the somewhat strange name ``<clinit>``: these are class initializers; while they are not explicitly called anywhere in the code, they are called implicitly whenever the surrounding class is loaded. Hence it makes sense to exclude them from our query. While we are at it, we can also exclude finalizers, which are similarly invoked implicitly:
|
||||
|
||||
@@ -113,7 +113,7 @@ We might also notice several unused methods with the somewhat strange name ``<cl
|
||||
not callee.hasName("<clinit>") and not callee.hasName("finalize")
|
||||
select callee, "Not called."
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/925473733866047471/>`__. This also reduces the number of results returned by most projects.
|
||||
This also reduces the number of results returned by most codebases.
|
||||
|
||||
We may also want to exclude public methods from our query, since they may be external API entry points:
|
||||
|
||||
@@ -128,7 +128,7 @@ We may also want to exclude public methods from our query, since they may be ext
|
||||
not callee.isPublic()
|
||||
select callee, "Not called."
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/6284320987237954610/>`__. This should have a more noticeable effect on the number of results returned.
|
||||
This should have a more noticeable effect on the number of results returned.
|
||||
|
||||
A further special case is non-public default constructors: in the singleton pattern, for example, a class is provided with private empty default constructor to prevent it from being instantiated. Since the very purpose of such constructors is their not being called, they should not be flagged up:
|
||||
|
||||
@@ -144,7 +144,7 @@ A further special case is non-public default constructors: in the singleton patt
|
||||
not callee.(Constructor).getNumberOfParameters() = 0
|
||||
select callee, "Not called."
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/2625028545869146918/>`__. This change has a large effect on the results for some projects but little effect on the results for others. Use of this pattern varies widely between different projects.
|
||||
This change has a large effect on the results for some projects but little effect on the results for others. Use of this pattern varies widely between different projects.
|
||||
|
||||
Finally, on many Java projects there are methods that are invoked indirectly by reflection. So, while there are no calls invoking these methods, they are, in fact, used. It is in general very hard to identify such methods. A very common special case, however, is JUnit test methods, which are reflectively invoked by a test runner. The CodeQL library for Java has support for recognizing test classes of JUnit and other testing frameworks, which we can employ to filter out methods defined in such classes:
|
||||
|
||||
@@ -161,7 +161,7 @@ Finally, on many Java projects there are methods that are invoked indirectly by
|
||||
not callee.getDeclaringType() instanceof TestClass
|
||||
select callee, "Not called."
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/2055862421970264112/>`__. This should give a further reduction in the number of results returned.
|
||||
This should give a further reduction in the number of results returned.
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
@@ -338,10 +338,9 @@ step by step in the UI:
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
select sink, source, sink, "Property access on JSON value originating $@.", source, "here"
|
||||
|
||||
`Here <https://lgtm.com/query/5347702611074820306>`_ is a run of this query on the `plexus-interop
|
||||
<https://lgtm.com/projects/g/finos-plexus/plexus-interop/>`_ project on LGTM.com. Many of the 19
|
||||
results are false positives since we currently do not model many ways in which a value can be
|
||||
checked for nullness. In particular, after a property reference ``x.p`` we implicitly know that
|
||||
We ran this query on the https://github.com/finos/plexus-interop repository. Many of the
|
||||
results were false positives since the query does not currently model many ways in which we can check
|
||||
a value for nullness. In particular, after a property reference ``x.p`` we implicitly know that
|
||||
``x`` cannot be null anymore, since otherwise the reference would have thrown an exception.
|
||||
Modeling this would allow us to get rid of most of the false positives, but is beyond the scope of
|
||||
this tutorial.
|
||||
@@ -391,10 +390,10 @@ Some of our standard security queries use flow labels. You can look at their imp
|
||||
to get a feeling for how to use flow labels in practice.
|
||||
|
||||
In particular, both of the examples mentioned in the section on limitations of basic data flow above
|
||||
are from standard security queries that use flow labels. The `Prototype pollution
|
||||
<https://lgtm.com/rules/1508857356317>`_ query uses two flow labels to distinguish completely
|
||||
are from standard security queries that use flow labels. The `Prototype-polluting merge call
|
||||
<https://codeql.github.com/codeql-query-help/javascript/js-prototype-pollution/>`_ query uses two flow labels to distinguish completely
|
||||
tainted objects from partially tainted objects. The `Uncontrolled data used in path expression
|
||||
<https://lgtm.com/rules/1971530250>`_ query uses four flow labels to track whether a user-controlled
|
||||
<https://codeql.github.com/codeql-query-help/javascript/js-path-injection/>`_ query uses four flow labels to track whether a user-controlled
|
||||
string may be an absolute path and whether it may contain ``..`` components.
|
||||
|
||||
Further reading
|
||||
|
||||
@@ -228,15 +228,23 @@ Here's see an example of what this can handle now:
|
||||
|
||||
Tracking in the whole model
|
||||
---------------------------
|
||||
We applied this pattern to ``firebaseDatabase()`` in the previous section, and it
|
||||
can just as easily apply to the other predicates.
|
||||
For reference, here's our simple Firebase model with type tracking on every predicate:
|
||||
We applied this pattern to ``firebaseDatabase()`` in the previous section, and we can
|
||||
apply the model just as easily to other predicates.
|
||||
This example query uses the model to find `set` calls.
|
||||
It's been modified slightly to handle a bit more of the API, which is beyond the scope of this tutorial.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import javascript
|
||||
import DataFlow
|
||||
|
||||
SourceNode firebase(TypeTracker t) {
|
||||
t.start() and
|
||||
result = globalVarRef("firebase")
|
||||
(
|
||||
result = globalVarRef("firebase")
|
||||
or
|
||||
result = moduleImport("firebase/app")
|
||||
)
|
||||
or
|
||||
exists(TypeTracker t2 |
|
||||
result = firebase(t2).track(t2, t)
|
||||
@@ -277,8 +285,7 @@ For reference, here's our simple Firebase model with type tracking on every pred
|
||||
result = firebaseRef().getAMethodCall("set")
|
||||
}
|
||||
|
||||
`Here <https://lgtm.com/query/1053770500827789481>`__ is a run of an example query using the model to find `set` calls on one of the Firebase sample projects.
|
||||
It's been modified slightly to handle a bit more of the API, which is beyond the scope of this tutorial.
|
||||
select firebaseSetterCall()
|
||||
|
||||
Tracking associated data
|
||||
------------------------
|
||||
@@ -392,7 +399,98 @@ Based on that we can track the ``snapshot`` value and find the ``val()`` call it
|
||||
|
||||
With this addition, ``firebaseDatabaseRead("forecast")`` finds the call to ``snapshot.val()`` that contains the value of the forecast.
|
||||
|
||||
`Here <https://lgtm.com/query/8761360814276109092>`__ is a run of an example query using the model to find `val` calls.
|
||||
.. code-block:: ql
|
||||
|
||||
import javascript
|
||||
import DataFlow
|
||||
|
||||
SourceNode firebase(TypeTracker t) {
|
||||
t.start() and
|
||||
(
|
||||
result = globalVarRef("firebase")
|
||||
or
|
||||
result = moduleImport("firebase/app")
|
||||
)
|
||||
or
|
||||
exists(TypeTracker t2 |
|
||||
result = firebase(t2).track(t2, t)
|
||||
)
|
||||
}
|
||||
|
||||
SourceNode firebase() {
|
||||
result = firebase(TypeTracker::end())
|
||||
}
|
||||
|
||||
SourceNode firebaseDatabase(TypeTracker t) {
|
||||
t.start() and
|
||||
result = firebase().getAMethodCall("database")
|
||||
or
|
||||
exists(TypeTracker t2 |
|
||||
result = firebaseDatabase(t2).track(t2, t)
|
||||
)
|
||||
}
|
||||
|
||||
SourceNode firebaseDatabase() {
|
||||
result = firebaseDatabase(TypeTracker::end())
|
||||
}
|
||||
|
||||
SourceNode firebaseRef(Node name, TypeTracker t) {
|
||||
t.start() and
|
||||
exists(CallNode call |
|
||||
call = firebaseDatabase().getAMethodCall("ref") and
|
||||
name = call.getArgument(0) and
|
||||
result = call
|
||||
)
|
||||
or
|
||||
exists(TypeTracker t2 |
|
||||
result = firebaseRef(name, t2).track(t2, t)
|
||||
)
|
||||
}
|
||||
|
||||
SourceNode firebaseRef(Node name) {
|
||||
result = firebaseRef(name, TypeTracker::end())
|
||||
}
|
||||
|
||||
MethodCallNode firebaseSetterCall(Node name) {
|
||||
result = firebaseRef(name).getAMethodCall("set")
|
||||
}
|
||||
|
||||
SourceNode firebaseSnapshotCallback(Node refName, TypeBackTracker t) {
|
||||
t.start() and
|
||||
(
|
||||
result = firebaseRef(refName).getAMethodCall("once").getArgument(1).getALocalSource()
|
||||
or
|
||||
result = firebaseRef(refName).getAMethodCall("once").getAMethodCall("then").getArgument(0).getALocalSource()
|
||||
)
|
||||
or
|
||||
exists(TypeBackTracker t2 |
|
||||
result = firebaseSnapshotCallback(refName, t2).backtrack(t2, t)
|
||||
)
|
||||
}
|
||||
|
||||
FunctionNode firebaseSnapshotCallback(Node refName) {
|
||||
result = firebaseSnapshotCallback(refName, TypeBackTracker::end())
|
||||
}
|
||||
|
||||
SourceNode firebaseSnapshot(Node refName, TypeTracker t) {
|
||||
t.start() and
|
||||
result = firebaseSnapshotCallback(refName).getParameter(0)
|
||||
or
|
||||
exists(TypeTracker t2 |
|
||||
result = firebaseSnapshot(refName, t2).track(t2, t)
|
||||
)
|
||||
}
|
||||
|
||||
SourceNode firebaseSnapshot(Node refName) {
|
||||
result = firebaseSnapshot(refName, TypeTracker::end())
|
||||
}
|
||||
|
||||
MethodCallNode firebaseDatabaseRead(Node refName) {
|
||||
result = firebaseSnapshot(refName).getAMethodCall("val")
|
||||
}
|
||||
|
||||
from Node name
|
||||
select name, firebaseDatabaseRead(name)
|
||||
|
||||
Summary
|
||||
-------
|
||||
|
||||
@@ -112,7 +112,7 @@ Here's a first version of our query:
|
||||
wsinner > wsouter
|
||||
select outer, "Whitespace around nested operators contradicts precedence."
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8141155897270480914/>`__. This query is likely to find results on most projects.
|
||||
This query is likely to find results on most codebases.
|
||||
|
||||
The first conjunct of the ``where`` clause restricts ``inner`` to be an operand of ``outer``, the second conjunct binds ``wsinner`` and ``wsouter``, while the last conjunct selects the suspicious cases.
|
||||
|
||||
@@ -143,7 +143,7 @@ Note that our predicate ``operatorWS`` computes the **total** amount of white sp
|
||||
wsinner > wsouter
|
||||
select outer, "Whitespace around nested operators contradicts precedence."
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/3151720037708691205/>`__. Any results will be refined by our changes to the query.
|
||||
Any results will be refined by our changes to the query.
|
||||
|
||||
Another source of false positives are associative operators: in an expression of the form ``x + y+z``, the first plus is syntactically nested inside the second, since + in Java associates to the left; hence the expression is flagged as suspicious. But since + is associative to begin with, it does not matter which way around the operators are nested, so this is a false positive. To exclude these cases, let us define a new class identifying binary expressions with an associative operator:
|
||||
|
||||
@@ -175,8 +175,6 @@ Now we can extend our query to discard results where the outer and the inner exp
|
||||
wsinner > wsouter
|
||||
select outer, "Whitespace around nested operators contradicts precedence."
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/5714614966569401039/>`__.
|
||||
|
||||
Notice that we again use ``getOp``, this time to determine whether two binary expressions have the same operator. Running our improved query now finds the Java standard library bug described in the Overview. It also flags up the following suspicious code in `Hadoop HBase <https://hbase.apache.org/>`__:
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
@@ -55,7 +55,7 @@ def setup(sphinx):
|
||||
sphinx.add_lexer("ql", QLLexer())
|
||||
|
||||
# The version of CodeQL for the current release you're documenting, acts as replacement for
|
||||
# |version| and |release|. Not currently used except in LGTM Enterprise support info.
|
||||
# |version| and |release|. Not currently used.
|
||||
|
||||
# The short X.Y version.
|
||||
# version = u'3.0'
|
||||
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 315 KiB |
|
After Width: | Height: | Size: 386 KiB |
|
After Width: | Height: | Size: 189 KiB |
|
After Width: | Height: | Size: 250 KiB |
|
After Width: | Height: | Size: 241 KiB |
|
After Width: | Height: | Size: 271 KiB |
|
After Width: | Height: | Size: 203 KiB |
|
After Width: | Height: | Size: 314 KiB |
|
After Width: | Height: | Size: 202 KiB |
|
After Width: | Height: | Size: 214 KiB |
|
After Width: | Height: | Size: 375 KiB |
|
After Width: | Height: | Size: 204 KiB |
|
After Width: | Height: | Size: 242 KiB |
|
After Width: | Height: | Size: 226 KiB |
|
After Width: | Height: | Size: 262 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 146 KiB |
BIN
docs/codeql/images/ql-select-statement-class-name.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 13 KiB |
BIN
docs/codeql/images/ql-select-statement-link.png
Normal file
|
After Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 17 KiB |
1
docs/codeql/reusables/setup-to-run-tutorials.rst
Normal file
@@ -0,0 +1 @@
|
||||
For information about installing the CodeQL extension for Visual Studio code, see ":ref:`Setting up CodeQL in Visual Studio Code <setting-up-codeql-in-visual-studio-code>`."
|
||||
@@ -0,0 +1,23 @@
|
||||
Finding a CodeQL database to experiment with
|
||||
--------------------------------------------
|
||||
|
||||
Before you start writing queries for |language-text| code, you need a CodeQL database to run them against. The simplest way to do this is to download a database for a repository that uses |language-text| directly from GitHub.com.
|
||||
|
||||
#. In Visual Studio Code, click the **QL** icon |codeql-ext-icon| in the left sidebar to display the CodeQL extension.
|
||||
|
||||
#. Click **From GitHub** or the GitHub logo |github-db| at the top of the CodeQL extension to open an entry field.
|
||||
|
||||
#. Copy the URL for the repository into the field and press the keyboard **Enter** key. For example, |example-url|.
|
||||
|
||||
#. Optionally, if the repository has more than one CodeQL database available, select |language-code| to download the database created from the |language-text| code.
|
||||
|
||||
Information about the download progress for the database is shown in the bottom right corner of Visual Studio Code. When the download is complete, the database is shown with a check mark in the **Databases** section of the CodeQL extension (see screenshot below).
|
||||
|
||||
.. |codeql-ext-icon| image:: ../images/codeql-for-visual-studio-code/codeql-extension-icon.png
|
||||
:width: 20
|
||||
:alt: Icon for the CodeQL extension.
|
||||
|
||||
.. |github-db| image:: ../images/codeql-for-visual-studio-code/add-codeql-db-github.png
|
||||
:width: 20
|
||||
:alt: Icon for the CodeQL extension option to download a CodeQL database from GitHub.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
If you want to move your experimental query somewhere more permanent, you need to move the whole ``Quick Queries`` directory. The directory is a CodeQL pack with a ``qlpack.yml`` file that defines the content as queries for |language-text| CodeQL databases. For more information about CodeQL packs, see ":ref:`Working with CodeQL packs in Visual Studio Code <working-with-codeql-packs-in-visual-studio-code>`."
|
||||
@@ -0,0 +1,7 @@
|
||||
The CodeQL extension for Visual Studio Code adds several **CodeQL:** commands to the command palette including **Quick Query**, which you can use to run a query without any set up.
|
||||
|
||||
#. From the command palette in Visual Studio Code, select **CodeQL: Quick Query**.
|
||||
|
||||
#. After a moment, a new tab *quick-query.ql* is opened, ready for you to write a query for your currently selected CodeQL database (here a |language-code| database). If you are prompted to reload your workspace as a multi-folder workspace to allow Quick queries, accept or create a new workspace using the starter workflow.
|
||||
|
||||
|image-quick-query|
|
||||
@@ -0,0 +1,7 @@
|
||||
4. Save the query in its default location (a temporary "Quick Queries" directory under the workspace for ``GitHub.vscode-codeql/quick-queries``).
|
||||
|
||||
#. Right-click in the query tab and select **CodeQL: Run Query**. (Alternatively, run the command from the Command Palette.)
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed in a CodeQL Query Results view, next to the main editor view.
|
||||
|
||||
The query results are listed in two columns, corresponding to the expressions in the ``select`` clause of the query. |result-col-1| The second column is the alert message.
|
||||
@@ -0,0 +1 @@
|
||||
For information about installing the CodeQL extension for Visual Studio code, see ":ref:`Setting up CodeQL in Visual Studio Code <setting-up-codeql-in-visual-studio-code>`."
|
||||
@@ -105,7 +105,7 @@ Now try applying ``isAllowedIn(string region)`` to a person ``p``. If ``p`` is n
|
||||
|
||||
You know that the fire starters live in the south *and* that they must have been able to travel to the north. Write a query to find the possible suspects. You could also extend the ``select`` clause to list the age of the suspects. That way you can clearly see that all the children have been excluded from the list.
|
||||
|
||||
➤ `See the answer in the query console on LGTM.com <https://lgtm.com/query/2551838470440192723/>`__
|
||||
➤ `Check your answer <#exercise-1>`__
|
||||
|
||||
You can now continue to gather more clues and find out which of your suspects started the fire...
|
||||
|
||||
@@ -142,7 +142,7 @@ The predicate ``isBald`` is defined to take a ``Person``, so it can also take a
|
||||
|
||||
You can now write a query to select the bald southerners who are allowed into the north.
|
||||
|
||||
➤ `See the answer in the query console on LGTM.com <https://lgtm.com/query/2572701606358725253/>`__
|
||||
➤ `Check your answer <#exercise-2>`__
|
||||
|
||||
You have found the two fire starters! They are arrested and the villagers are once again impressed with your work.
|
||||
|
||||
@@ -150,3 +150,65 @@ Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
--------------
|
||||
|
||||
Answers
|
||||
-------
|
||||
|
||||
In these answers, we use ``/*`` and ``*/`` to label the different parts of the query. Any text surrounded by ``/*`` and ``*/`` is not evaluated as part of the QL code, but is treated as a *comment*.
|
||||
|
||||
Exercise 1
|
||||
~~~~~~~~~~
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import tutorial
|
||||
|
||||
predicate isSouthern(Person p) { p.getLocation() = "south" }
|
||||
|
||||
class Southerner extends Person {
|
||||
/* the characteristic predicate */
|
||||
Southerner() { isSouthern(this) }
|
||||
}
|
||||
|
||||
class Child extends Person {
|
||||
/* the characteristic predicate */
|
||||
Child() { this.getAge() < 10 }
|
||||
|
||||
/* a member predicate */
|
||||
override predicate isAllowedIn(string region) { region = this.getLocation() }
|
||||
}
|
||||
|
||||
from Southerner s
|
||||
where s.isAllowedIn("north")
|
||||
select s, s.getAge()
|
||||
|
||||
Exercise 2
|
||||
~~~~~~~~~~
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import tutorial
|
||||
|
||||
predicate isSouthern(Person p) { p.getLocation() = "south" }
|
||||
|
||||
class Southerner extends Person {
|
||||
/* the characteristic predicate */
|
||||
Southerner() { isSouthern(this) }
|
||||
}
|
||||
|
||||
class Child extends Person {
|
||||
/* the characteristic predicate */
|
||||
Child() { this.getAge() < 10 }
|
||||
|
||||
/* a member predicate */
|
||||
override predicate isAllowedIn(string region) { region = this.getLocation() }
|
||||
}
|
||||
|
||||
predicate isBald(Person p) { not exists(string c | p.getHairColor() = c) }
|
||||
|
||||
from Southerner s
|
||||
where s.isAllowedIn("north") and isBald(s)
|
||||
select s
|
||||
|
||||
|
||||
@@ -260,21 +260,34 @@ Alternative solutions
|
||||
|
||||
Here are some more example queries that solve the river crossing puzzle:
|
||||
|
||||
#. This query uses a modified ``path`` variable to describe the resulting path in
|
||||
more detail.
|
||||
.. container:: toggle
|
||||
|
||||
➤ `See solution in the query console on LGTM.com <https://lgtm.com/query/659603593702729237/>`__
|
||||
.. container:: name
|
||||
|
||||
#. This query models the man and the cargo items in a different way, using an
|
||||
:ref:`abstract <abstract>`
|
||||
class and predicate. It also displays the resulting path in a more visual way.
|
||||
*Show/hide example query - modified path*
|
||||
|
||||
➤ `See solution in the query console on LGTM.com <https://lgtm.com/query/1025323464423811143/>`__
|
||||
.. literalinclude:: river-answer-1-path.ql
|
||||
:language: ql
|
||||
|
||||
#. This query introduces :ref:`algebraic datatypes <algebraic-datatypes>`
|
||||
to model the situation, instead of defining everything as a subclass of ``string``.
|
||||
|
||||
➤ `See solution in the query console on LGTM.com <https://lgtm.com/query/7260748307619718263/>`__
|
||||
.. container:: toggle
|
||||
|
||||
.. container:: name
|
||||
|
||||
*Show/hide example query - abstract class*
|
||||
|
||||
.. literalinclude:: river-answer-2-abstract-class.ql
|
||||
:language: ql
|
||||
|
||||
|
||||
.. container:: toggle
|
||||
|
||||
.. container:: name
|
||||
|
||||
*Show/hide example query - datatypes*
|
||||
|
||||
.. literalinclude:: river-answer-3-datatypes.ql
|
||||
:language: ql
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
@@ -129,7 +129,7 @@ Here is one way to define ``relativeOf()``:
|
||||
|
||||
Don't forget to use the predicate ``isDeceased()`` to find relatives that are still alive.
|
||||
|
||||
➤ `See the answer in the query console on LGTM.com <https://lgtm.com/query/6710025057257064639/>`__
|
||||
➤ `Check your answer <#exercise-1>`__
|
||||
|
||||
Select the true heir
|
||||
--------------------
|
||||
@@ -142,7 +142,7 @@ To decide who should inherit the king's fortune, the villagers carefully read th
|
||||
|
||||
As your final challenge, define a predicate ``hasCriminalRecord`` so that ``hasCriminalRecord(p)`` holds if ``p`` is any of the criminals you unmasked earlier (in the ":doc:`Find the thief <find-the-thief>`" and ":doc:`Catch the fire starter <catch-the-fire-starter>`" tutorials).
|
||||
|
||||
➤ `See the answer in the query console on LGTM.com <https://lgtm.com/query/1820692755164273290/>`__
|
||||
➤ `Check your answer <#exercise-2>`__
|
||||
|
||||
Experimental explorations
|
||||
-------------------------
|
||||
@@ -164,3 +164,47 @@ Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
--------------
|
||||
|
||||
Answers
|
||||
-------
|
||||
|
||||
In these answers, we use ``/*`` and ``*/`` to label the different parts of the query. Any text surrounded by ``/*`` and ``*/`` is not evaluated as part of the QL code, but is treated as a *comment*.
|
||||
|
||||
Exercise 1
|
||||
~~~~~~~~~~
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import tutorial
|
||||
|
||||
Person relativeOf(Person p) { parentOf*(result) = parentOf*(p) }
|
||||
|
||||
from Person p
|
||||
where
|
||||
not p.isDeceased() and
|
||||
p = relativeOf("King Basil")
|
||||
select p
|
||||
|
||||
Exercise 2
|
||||
~~~~~~~~~~
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import tutorial
|
||||
|
||||
Person relativeOf(Person p) { parentOf*(result) = parentOf*(p) }
|
||||
|
||||
predicate hasCriminalRecord(Person p) {
|
||||
p = "Hester" or
|
||||
p = "Hugh" or
|
||||
p = "Charlie"
|
||||
}
|
||||
|
||||
from Person p
|
||||
where
|
||||
not p.isDeceased() and
|
||||
p = relativeOf("King Basil") and
|
||||
not hasCriminalRecord(p)
|
||||
select p
|
||||
|
||||
@@ -9,8 +9,8 @@ About query results
|
||||
-------------------
|
||||
|
||||
The information contained in the results of a query is controlled by the ``select`` statement. Part of the process of developing a useful query is to make the results clear and easy for other users to understand.
|
||||
When you write your own queries in the query console or in the CodeQL :ref:`extension for VS Code <codeql-for-visual-studio-code>` there are no constraints on what can be selected.
|
||||
However, if you want to use a query to create alerts in LGTM or generate valid analysis results using the :ref:`CodeQL CLI <codeql-cli>`, you'll need to make the ``select`` statement report results in the required format.
|
||||
When you write your own queries in the CodeQL :ref:`extension for VS Code <codeql-for-visual-studio-code>` there are no constraints on what can be selected.
|
||||
However, if you want to use a query to create alerts for code scanning or generate valid analysis results using the :ref:`CodeQL CLI <codeql-cli>`, you'll need to make the ``select`` statement report results in the required format.
|
||||
You must also ensure that the query has the appropriate metadata properties defined.
|
||||
This topic explains how to write your select statement to generate helpful analysis results.
|
||||
|
||||
@@ -23,7 +23,7 @@ In their most basic form, the ``select`` statement must select two 'columns':
|
||||
- **Element**—a code element that's identified by the query. This defines the location of the alert.
|
||||
- **String**—a message to display for this code element, describing why the alert was generated.
|
||||
|
||||
If you look at some of the LGTM queries, you'll see that they can select extra element/string pairs, which are combined with ``$@`` placeholder markers in the message to form links. For example, `Dereferenced variable may be null <https://lgtm.com/query/rule:1954750296/lang:java/>`__ (Java), or `Duplicate switch case <https://lgtm.com/query/rule:7890077/lang:javascript/>`__ (JavaScript).
|
||||
If you look at some of the existing queries, you'll see that they can select extra element/string pairs, which are combined with ``$@`` placeholder markers in the message to form links. For example, `Dereferenced variable may be null <https://github.com/github/codeql/blob/95e65347cafe502bbd0d9f48d1175fd3d66e0459/java/ql/src/Likely%20Bugs/Nullness/NullMaybe.ql>`__ (Java), or `Duplicate switch case <https://github.com/github/codeql/blob/95e65347cafe502bbd0d9f48d1175fd3d66e0459/javascript/ql/src/Expressions/DuplicateSwitchCase.ql>`__ (JavaScript).
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
@@ -34,78 +34,70 @@ If you look at some of the LGTM queries, you'll see that they can select extra e
|
||||
Developing a select statement
|
||||
-----------------------------
|
||||
|
||||
Here's a simple query that uses the standard CodeQL ``CodeDuplication.qll`` library to identify similar files.
|
||||
Here's a simple query to find Java classes that extend other classes.
|
||||
|
||||
Basic select statement
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import java
|
||||
import external.CodeDuplication
|
||||
|
||||
from File f, File other, int percent
|
||||
where similarFiles(f, other, percent)
|
||||
select f, "This file is similar to another file."
|
||||
/**
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
from Class c, Class superclass
|
||||
where superclass = c.getASupertype()
|
||||
select c, "This class extends another class."
|
||||
|
||||
This basic select statement has two columns:
|
||||
|
||||
#. Element to display the alert on: ``f`` corresponds to ``File``.
|
||||
#. String message to display: ``"This file is similar to another file."``
|
||||
#. An element with a location to display the alert on: ``c`` corresponds to ``Class``.
|
||||
#. String message to display: ``"This class extends another class."``
|
||||
|
||||
.. image:: ../images/ql-select-statement-basic.png
|
||||
:alt: Results of basic select statement
|
||||
:class: border
|
||||
|
||||
Including the name of the similar file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Including the name of the superclass
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The alert message defined by the basic select statement is constant and doesn't give users much information. Since the query identifies the similar file (``other``), it's easy to extend the ``select`` statement to report the name of the similar file. For example:
|
||||
The alert message defined by the basic select statement is constant and doesn't give users much information. Since the query identifies the superclass, it's easy to include its name in the string message. For example:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
select f, "This file is similar to " + other.getBaseName()
|
||||
select c, "This class extends the class " + superclass.getName()
|
||||
|
||||
#. Element: ``f`` as before.
|
||||
#. String message: ``"This file is similar to "``—the string text is combined with the file name for the ``other``, similar file, returned by ``getBaseName()``.
|
||||
#. Element: ``c`` as before.
|
||||
#. String message: ``"This class extends the class "``—the string text is combined with the class name for the ``superclass``, returned by ``getName()``.
|
||||
|
||||
.. image:: ../images/ql-select-statement-filename.png
|
||||
.. image:: ../images/ql-select-statement-class-name.png
|
||||
:alt: Results of extended select statement
|
||||
:class: border
|
||||
|
||||
While this is more informative than the original select statement, the user still needs to find the other file manually.
|
||||
While this is more informative than the original select statement, the user still needs to find the superclass manually.
|
||||
|
||||
Adding a link to the similar file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Adding a link to the superclass
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can use placeholders in the text of alert messages to insert additional information, such as links to the similar file. Placeholders are defined using ``$@``, and filled using the information in the next two columns of the select statement. For example, this select statement returns four columns:
|
||||
You can use placeholders in the text of alert messages to insert additional information, such as links to the superclass. Placeholders are defined using ``$@``, and filled using the information in the next two columns of the select statement. For example, this select statement returns four columns:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
select f, "This file is similar to $@.", other, other.getBaseName()
|
||||
select c, "This class extends the class $@.", superclass, superclass.getName()
|
||||
|
||||
#. Element: ``f`` as before.
|
||||
#. String message: ``"This file is similar to $@."``—the string text now includes a placeholder, which will display the combined content of the next two columns.
|
||||
#. Element for placeholder: ``other`` corresponds to the similar file.
|
||||
#. String text for placeholder: the short file name returned by ``other.getBaseName()``.
|
||||
#. Element: ``c`` as before.
|
||||
#. String message: ``"This class extends the class $@."``—the string text now includes a placeholder, which will display the combined content of the next two columns.
|
||||
#. Element for placeholder: the ``superclass``.
|
||||
#. String text for placeholder: the class name returned by ``superclass.getBaseName()``.
|
||||
|
||||
When the alert message is displayed, the ``$@`` placeholder is replaced by a link created from the contents of the third and fourth columns defined by the ``select`` statement.
|
||||
When the alert message is displayed, the ``$@`` placeholder is replaced by a link created from the contents of the third and fourth columns defined by the ``select`` statement. In this example, the link target will be the location of the superclass's definition, and the link text will be its name. Note that some superclasses, such as ``Object``, will not be in the database, since they are built in to the Java language. Clicking those links will have no effect.
|
||||
|
||||
If you use the ``$@`` placeholder marker multiple times in the description text, then the ``N``\ th use is replaced by a link formed from columns ``2N+2`` and ``2N+3``. If there are more pairs of additional columns than there are placeholder markers, then the trailing columns are ignored. Conversely, if there are fewer pairs of additional columns than there are placeholder markers, then the trailing markers are treated as normal text rather than placeholder markers.
|
||||
|
||||
Adding details of the extent of similarity
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You could go further and change the ``select`` statement to report on the similarity of content in the two files, since this information is already available in the query. For example:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
select f, percent + "% of the lines in " + f.getBaseName() + " are similar to lines in $@.", other, other.getBaseName()
|
||||
|
||||
The new elements added here don't need to be clickable, so we added them directly to the description string.
|
||||
|
||||
.. image:: ../images/ql-select-statement-similarity.png
|
||||
:alt: Results showing the extent of similarity
|
||||
.. image:: ../images/ql-select-statement-link.png
|
||||
:alt: Results including links
|
||||
:class: border
|
||||
|
||||
Further reading
|
||||
|
||||
@@ -50,9 +50,7 @@ You start asking some creative questions and making notes of the answers so you
|
||||
|
||||
There is too much information to search through by hand, so you decide to use your newly acquired QL skills to help you with your investigation...
|
||||
|
||||
#. Open the `query console on LGTM.com <https://lgtm.com/query>`__ to get started.
|
||||
#. Select a language and a demo project. For this tutorial, any language and project will do.
|
||||
#. Delete the default code ``import <language> select "hello world"``.
|
||||
.. include:: ../reusables/setup-to-run-tutorials.rst
|
||||
|
||||
QL libraries
|
||||
------------
|
||||
@@ -209,13 +207,7 @@ Hints
|
||||
|
||||
Once you have finished, you will have a list of possible suspects. One of those people must be the thief!
|
||||
|
||||
➤ `See the answer in the query console on LGTM.com <https://lgtm.com/query/1505743955992/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
In the answer, we used ``/*`` and ``*/`` to label the different parts of the query. Any text surrounded by ``/*`` and ``*/`` is not evaluated as part of the QL code, but is just a *comment*.
|
||||
➤ `Check your answer <#exercise-1>`__
|
||||
|
||||
You are getting closer to solving the mystery! Unfortunately, you still have quite a long list of suspects... To find out which of your suspects is the thief, you must gather more information and refine your query in the next step.
|
||||
|
||||
@@ -291,9 +283,59 @@ You can now translate the remaining questions into QL:
|
||||
|
||||
Have you found the thief?
|
||||
|
||||
➤ `See the answer in the query console on LGTM.com <https://lgtm.com/query/1505744186085/>`__
|
||||
➤ `Check your answer <#exercise-2>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
|
||||
--------------
|
||||
|
||||
Answers
|
||||
-------
|
||||
|
||||
In these answers, we use ``/*`` and ``*/`` to label the different parts of the query. Any text surrounded by ``/*`` and ``*/`` is not evaluated as part of the QL code, but is treated as a *comment*.
|
||||
|
||||
Exercise 1
|
||||
^^^^^^^^^^
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import tutorial
|
||||
|
||||
from Person t
|
||||
where
|
||||
/* 1 */ t.getHeight() > 150 and
|
||||
/* 2 */ not t.getHairColor() = "blond" and
|
||||
/* 3 */ exists (string c | t.getHairColor() = c) and
|
||||
/* 4 */ not t.getAge() < 30 and
|
||||
/* 5 */ t.getLocation() = "east" and
|
||||
/* 6 */ (t.getHairColor() = "black" or t.getHairColor() = "brown") and
|
||||
/* 7 */ not (t.getHeight() > 180 and t.getHeight() < 190) and
|
||||
/* 8 */ exists(Person p | p.getAge() > t.getAge())
|
||||
select t
|
||||
|
||||
Exercise 2
|
||||
^^^^^^^^^^
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import tutorial
|
||||
|
||||
from Person t
|
||||
where
|
||||
/* 1 */ t.getHeight() > 150 and
|
||||
/* 2 */ not t.getHairColor() = "blond" and
|
||||
/* 3 */ exists (string c | t.getHairColor() = c) and
|
||||
/* 4 */ not t.getAge() < 30 and
|
||||
/* 5 */ t.getLocation() = "east" and
|
||||
/* 6 */ (t.getHairColor() = "black" or t.getHairColor() = "brown") and
|
||||
/* 7 */ not (t.getHeight() > 180 and t.getHeight() < 190) and
|
||||
/* 8 */ exists(Person p | p.getAge() > t.getAge()) and
|
||||
/* 9 */ not t = max(Person p | | p order by p.getHeight()) and
|
||||
/* 10 */ t.getHeight() < avg(float i | exists(Person p | p.getHeight() = i) | i) and
|
||||
/* 11 */ t = max(Person p | p.getLocation() = "east" | p order by p.getAge())
|
||||
select "The thief is " + t + "!"
|
||||
|
||||
115
docs/codeql/writing-codeql-queries/river-answer-1-path.ql
Normal file
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* A solution to the river crossing puzzle using a modified `path` variable
|
||||
* to describe the resulting path in detail.
|
||||
*/
|
||||
|
||||
/** A possible cargo item. */
|
||||
class Cargo extends string {
|
||||
Cargo() {
|
||||
this = "Nothing" or
|
||||
this = "Goat" or
|
||||
this = "Cabbage" or
|
||||
this = "Wolf"
|
||||
}
|
||||
}
|
||||
|
||||
/** One of two shores. */
|
||||
class Shore extends string {
|
||||
Shore() {
|
||||
this = "Left" or
|
||||
this = "Right"
|
||||
}
|
||||
|
||||
/** Returns the other shore. */
|
||||
Shore other() {
|
||||
this = "Left" and result = "Right"
|
||||
or
|
||||
this = "Right" and result = "Left"
|
||||
}
|
||||
}
|
||||
|
||||
/** Renders the state as a string. */
|
||||
string renderState(Shore manShore, Shore goatShore, Shore cabbageShore, Shore wolfShore) {
|
||||
result = manShore + "," + goatShore + "," + cabbageShore + "," + wolfShore
|
||||
}
|
||||
|
||||
/** A record of where everything is. */
|
||||
class State extends string {
|
||||
Shore manShore;
|
||||
Shore goatShore;
|
||||
Shore cabbageShore;
|
||||
Shore wolfShore;
|
||||
|
||||
State() { this = renderState(manShore, goatShore, cabbageShore, wolfShore) }
|
||||
|
||||
/** Returns the state that is reached after ferrying a particular cargo item. */
|
||||
State ferry(Cargo cargo) {
|
||||
cargo = "Nothing" and
|
||||
result = renderState(manShore.other(), goatShore, cabbageShore, wolfShore)
|
||||
or
|
||||
cargo = "Goat" and
|
||||
result = renderState(manShore.other(), goatShore.other(), cabbageShore, wolfShore)
|
||||
or
|
||||
cargo = "Cabbage" and
|
||||
result = renderState(manShore.other(), goatShore, cabbageShore.other(), wolfShore)
|
||||
or
|
||||
cargo = "Wolf" and
|
||||
result = renderState(manShore.other(), goatShore, cabbageShore, wolfShore.other())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the state is safe. This occurs when neither the goat nor the cabbage
|
||||
* can get eaten.
|
||||
*/
|
||||
predicate isSafe() {
|
||||
// The goat can't eat the cabbage.
|
||||
(goatShore != cabbageShore or goatShore = manShore) and
|
||||
// The wolf can't eat the goat.
|
||||
(wolfShore != goatShore or wolfShore = manShore)
|
||||
}
|
||||
|
||||
/** Returns the state that is reached after safely ferrying a cargo item. */
|
||||
State safeFerry(Cargo cargo) { result = this.ferry(cargo) and result.isSafe() }
|
||||
|
||||
string towards() {
|
||||
manShore = "Left" and result = "to the left"
|
||||
or
|
||||
manShore = "Right" and result = "to the right"
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all states that are reachable via safe ferrying.
|
||||
* `path` keeps track of how it is achieved.
|
||||
* `visitedStates` keeps track of previously visited states and is used to avoid loops.
|
||||
*/
|
||||
State reachesVia(string path, string visitedStates) {
|
||||
// Reachable in 1 step by ferrying a specific cargo
|
||||
exists(Cargo cargo |
|
||||
result = this.safeFerry(cargo) and
|
||||
visitedStates = result and
|
||||
path = "First " + cargo + " is ferried " + result.towards()
|
||||
)
|
||||
or
|
||||
// Reachable by first following pathSoFar and then ferrying cargo
|
||||
exists(string pathSoFar, string visitedStatesSoFar, Cargo cargo |
|
||||
result = this.reachesVia(pathSoFar, visitedStatesSoFar).safeFerry(cargo) and
|
||||
not exists(int i | i = visitedStatesSoFar.indexOf(result)) and // resulting state is not visited yet
|
||||
visitedStates = visitedStatesSoFar + "_" + result and
|
||||
path = pathSoFar + ",\nthen " + cargo + " is ferried " + result.towards()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The initial state, where everything is on the left shore. */
|
||||
class InitialState extends State {
|
||||
InitialState() { this = renderState("Left", "Left", "Left", "Left") }
|
||||
}
|
||||
|
||||
/** The goal state, where everything is on the right shore. */
|
||||
class GoalState extends State {
|
||||
GoalState() { this = renderState("Right", "Right", "Right", "Right") }
|
||||
}
|
||||
|
||||
from string path
|
||||
where any(InitialState i).reachesVia(path, _) = any(GoalState g)
|
||||
select path + "."
|
||||
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* A solution to the river crossing puzzle using abstract
|
||||
* classes/predicates to model the situation and unicode
|
||||
* symbols to display the answer.
|
||||
*/
|
||||
|
||||
/** One of two shores. */
|
||||
class Shore extends string {
|
||||
Shore() { this = "left" or this = "right" }
|
||||
}
|
||||
|
||||
/** Models the behavior of the man. */
|
||||
class Man extends string {
|
||||
Shore s;
|
||||
|
||||
Man() { this = "man " + s }
|
||||
|
||||
/** Holds if the man is on a particular shore. */
|
||||
predicate isOn(Shore shore) { s = shore }
|
||||
|
||||
/** Returns the other shore, after the man crosses the river. */
|
||||
Man cross() { result != this }
|
||||
|
||||
/** Returns a cargo and its position after being ferried. */
|
||||
Cargo ferry(Cargo c) {
|
||||
result = c.cross() and
|
||||
c.isOn(s)
|
||||
}
|
||||
}
|
||||
|
||||
/** One of three possible cargo items, with their position. */
|
||||
abstract class Cargo extends string {
|
||||
Shore s;
|
||||
|
||||
bindingset[this]
|
||||
Cargo() { any() }
|
||||
|
||||
/** Holds if the cargo is on a particular shore. */
|
||||
predicate isOn(Shore shore) { s = shore }
|
||||
|
||||
/** Returns the other shore, after the cargo crosses the river. */
|
||||
abstract Cargo cross();
|
||||
}
|
||||
|
||||
/** Models the position of the goat. */
|
||||
class Goat extends Cargo {
|
||||
Goat() { this = "goat " + s }
|
||||
|
||||
override Goat cross() { result != this }
|
||||
}
|
||||
|
||||
/** Models the position of the wolf. */
|
||||
class Wolf extends Cargo {
|
||||
Wolf() { this = "wolf " + s }
|
||||
|
||||
override Wolf cross() { result != this }
|
||||
}
|
||||
|
||||
/** Models the position of the cabbage. */
|
||||
class Cabbage extends Cargo {
|
||||
Cabbage() { this = "cabbage " + s }
|
||||
|
||||
override Cabbage cross() { result != this }
|
||||
}
|
||||
|
||||
/** Returns a unicode representation of everything on the left shore. */
|
||||
string onLeft(Man man, Goat goat, Cabbage cabbage, Wolf wolf) {
|
||||
exists(string manOnLeft, string goatOnLeft, string cabbageOnLeft, string wolfOnLeft |
|
||||
(
|
||||
man.isOn("left") and manOnLeft = "🕴"
|
||||
or
|
||||
man.isOn("right") and manOnLeft = "____"
|
||||
) and
|
||||
(
|
||||
goat.isOn("left") and goatOnLeft = "🐐"
|
||||
or
|
||||
goat.isOn("right") and goatOnLeft = "___"
|
||||
) and
|
||||
(
|
||||
cabbage.isOn("left") and cabbageOnLeft = "🥬"
|
||||
or
|
||||
cabbage.isOn("right") and cabbageOnLeft = "___"
|
||||
) and
|
||||
(
|
||||
wolf.isOn("left") and wolfOnLeft = "🐺"
|
||||
or
|
||||
wolf.isOn("right") and wolfOnLeft = "___"
|
||||
) and
|
||||
result = manOnLeft + "__" + goatOnLeft + "__" + cabbageOnLeft + "__" + wolfOnLeft
|
||||
)
|
||||
}
|
||||
|
||||
/** Returns a unicode representation of everything on the right shore. */
|
||||
string onRight(Man man, Goat goat, Cabbage cabbage, Wolf wolf) {
|
||||
exists(string manOnLeft, string goatOnLeft, string cabbageOnLeft, string wolfOnLeft |
|
||||
(
|
||||
man.isOn("right") and manOnLeft = "🕴"
|
||||
or
|
||||
man.isOn("left") and manOnLeft = "_"
|
||||
) and
|
||||
(
|
||||
goat.isOn("right") and goatOnLeft = "🐐"
|
||||
or
|
||||
goat.isOn("left") and goatOnLeft = "__"
|
||||
) and
|
||||
(
|
||||
cabbage.isOn("right") and cabbageOnLeft = "🥬"
|
||||
or
|
||||
cabbage.isOn("left") and cabbageOnLeft = "__"
|
||||
) and
|
||||
(
|
||||
wolf.isOn("right") and wolfOnLeft = "🐺"
|
||||
or
|
||||
wolf.isOn("left") and wolfOnLeft = "__"
|
||||
) and
|
||||
result = manOnLeft + "__" + goatOnLeft + "__" + cabbageOnLeft + "__" + wolfOnLeft
|
||||
)
|
||||
}
|
||||
|
||||
/** Renders the state as a string, using unicode symbols. */
|
||||
string render(Man man, Goat goat, Cabbage cabbage, Wolf wolf) {
|
||||
result = onLeft(man, goat, cabbage, wolf) + "___🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊___" +
|
||||
onRight(man, goat, cabbage, wolf)
|
||||
}
|
||||
|
||||
/** A record of where everything is. */
|
||||
class State extends string {
|
||||
Man man;
|
||||
|
||||
Goat goat;
|
||||
|
||||
Cabbage cabbage;
|
||||
|
||||
Wolf wolf;
|
||||
|
||||
State() { this = render(man, goat, cabbage, wolf) }
|
||||
|
||||
/**
|
||||
* Returns the possible states that you can transition to
|
||||
* by ferrying one or zero cargo items.
|
||||
*/
|
||||
State transition() {
|
||||
result = render(man.cross(), man.ferry(goat), cabbage, wolf) or
|
||||
result = render(man.cross(), goat, man.ferry(cabbage), wolf) or
|
||||
result = render(man.cross(), goat, cabbage, man.ferry(wolf)) or
|
||||
result = render(man.cross(), goat, cabbage, wolf)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all states that are reachable via a transition
|
||||
* and have not yet been visited.
|
||||
* `path` keeps track of how it is achieved.
|
||||
*/
|
||||
State reachesVia(string path) {
|
||||
exists(string pathSoFar |
|
||||
result = this.reachesVia(pathSoFar).transition() and
|
||||
not exists(int i | i = pathSoFar.indexOf(result.toString())) and
|
||||
path = pathSoFar + "\n↓\n" + result
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The initial state, where everything is on the left shore. */
|
||||
class InitialState extends State {
|
||||
InitialState() {
|
||||
exists(Shore left | left = "left" |
|
||||
man.isOn(left) and goat.isOn(left) and cabbage.isOn(left) and wolf.isOn(left)
|
||||
)
|
||||
}
|
||||
|
||||
override State reachesVia(string path) {
|
||||
path = this + "\n↓\n" + result and result = transition()
|
||||
or
|
||||
result = super.reachesVia(path)
|
||||
}
|
||||
}
|
||||
|
||||
/** The goal state, where everything is on the right shore. */
|
||||
class GoalState extends State {
|
||||
GoalState() {
|
||||
exists(Shore right | right = "right" |
|
||||
man.isOn(right) and goat.isOn(right) and cabbage.isOn(right) and wolf.isOn(right)
|
||||
)
|
||||
}
|
||||
|
||||
override State transition() { none() }
|
||||
}
|
||||
|
||||
/** An unsafe state, where something gets eaten. */
|
||||
class IllegalState extends State {
|
||||
IllegalState() {
|
||||
exists(Shore s |
|
||||
goat.isOn(s) and cabbage.isOn(s) and not man.isOn(s)
|
||||
or
|
||||
wolf.isOn(s) and goat.isOn(s) and not man.isOn(s)
|
||||
)
|
||||
}
|
||||
|
||||
override State transition() { none() }
|
||||
}
|
||||
|
||||
from string path
|
||||
where any(InitialState i).reachesVia(path) = any(GoalState g)
|
||||
select path
|
||||
|
||||
172
docs/codeql/writing-codeql-queries/river-answer-3-datatypes.ql
Normal file
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* "Typesafe" solution to the river crossing puzzle.
|
||||
*/
|
||||
|
||||
/** Either the left shore or the right shore. */
|
||||
newtype TShore =
|
||||
Left() or
|
||||
Right()
|
||||
|
||||
class Shore extends TShore {
|
||||
Shore other() { result != this }
|
||||
|
||||
string toString() {
|
||||
this = Left() and result = "left"
|
||||
or
|
||||
this = Right() and result = "right"
|
||||
}
|
||||
}
|
||||
|
||||
newtype TMan = TManOn(Shore s)
|
||||
|
||||
/** Models the behavior of the man. */
|
||||
class Man extends TMan {
|
||||
Shore s;
|
||||
|
||||
Man() { this = TManOn(s) }
|
||||
|
||||
/** Holds if the man is on a particular shore. */
|
||||
predicate isOn(Shore shore) { s = shore }
|
||||
|
||||
/** Returns the other shore, after the man crosses the river. */
|
||||
Man cross() { result.isOn(s.other()) }
|
||||
|
||||
/** Returns a cargo and its position after being ferried. */
|
||||
Cargo ferry(Cargo c) {
|
||||
result = c.cross() and
|
||||
c.isOn(s)
|
||||
}
|
||||
|
||||
string toString() { result = "man " + s }
|
||||
}
|
||||
|
||||
newtype TCargo =
|
||||
TGoat(Shore s) or
|
||||
TCabbage(Shore s) or
|
||||
TWolf(Shore s)
|
||||
|
||||
/** One of three possible cargo items, with their position. */
|
||||
abstract class Cargo extends TCargo {
|
||||
Shore s;
|
||||
|
||||
/** Holds if the cargo is on a particular shore. */
|
||||
predicate isOn(Shore shore) { s = shore }
|
||||
|
||||
/** Returns the other shore, after the cargo crosses the river. */
|
||||
abstract Cargo cross();
|
||||
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/** Models the position of the goat. */
|
||||
class Goat extends Cargo, TGoat {
|
||||
Goat() { this = TGoat(s) }
|
||||
|
||||
override Cargo cross() { result = TGoat(s.other()) }
|
||||
|
||||
override string toString() { result = "goat " + s }
|
||||
}
|
||||
|
||||
/** Models the position of the wolf. */
|
||||
class Wolf extends Cargo, TWolf {
|
||||
Wolf() { this = TWolf(s) }
|
||||
|
||||
override Cargo cross() { result = TWolf(s.other()) }
|
||||
|
||||
override string toString() { result = "wolf " + s }
|
||||
}
|
||||
|
||||
/** Models the position of the cabbage. */
|
||||
class Cabbage extends Cargo, TCabbage {
|
||||
Cabbage() { this = TCabbage(s) }
|
||||
|
||||
override Cargo cross() { result = TCabbage(s.other()) }
|
||||
|
||||
override string toString() { result = "cabbage " + s }
|
||||
}
|
||||
|
||||
newtype TState = Currently(Man man, Goat goat, Cabbage cabbage, Wolf wolf)
|
||||
|
||||
/** A record of where everything is. */
|
||||
class State extends TState {
|
||||
Man man;
|
||||
|
||||
Goat goat;
|
||||
|
||||
Cabbage cabbage;
|
||||
|
||||
Wolf wolf;
|
||||
|
||||
State() { this = Currently(man, goat, cabbage, wolf) }
|
||||
|
||||
/**
|
||||
* Returns the possible states that you can transition to
|
||||
* by ferrying one or zero cargo items.
|
||||
*/
|
||||
State transition() {
|
||||
result = Currently(man.cross(), man.ferry(goat), cabbage, wolf) or
|
||||
result = Currently(man.cross(), goat, man.ferry(cabbage), wolf) or
|
||||
result = Currently(man.cross(), goat, cabbage, man.ferry(wolf)) or
|
||||
result = Currently(man.cross(), goat, cabbage, wolf)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all states that are reachable via a transition
|
||||
* and have not yet been visited.
|
||||
* `path` keeps track of how it is achieved.
|
||||
*/
|
||||
State reachesVia(string path) {
|
||||
exists(string pathSoFar |
|
||||
result = this.reachesVia(pathSoFar).transition() and
|
||||
not exists(int i | i = pathSoFar.indexOf(result.toString())) and
|
||||
path = pathSoFar + "\n" + result
|
||||
)
|
||||
}
|
||||
|
||||
string toString() { result = man + "/" + goat + "/" + cabbage + "/" + wolf }
|
||||
}
|
||||
|
||||
/** The initial state, where everything is on the left shore. */
|
||||
class InitialState extends State {
|
||||
InitialState() {
|
||||
man.isOn(Left()) and goat.isOn(Left()) and cabbage.isOn(Left()) and wolf.isOn(Left())
|
||||
}
|
||||
|
||||
override State reachesVia(string path) {
|
||||
path = this + "\n" + result and result = transition()
|
||||
or
|
||||
result = super.reachesVia(path)
|
||||
}
|
||||
|
||||
override string toString() { result = "Initial: " + super.toString() }
|
||||
}
|
||||
|
||||
/** The goal state, where everything is on the right shore. */
|
||||
class GoalState extends State {
|
||||
GoalState() {
|
||||
man.isOn(Right()) and goat.isOn(Right()) and cabbage.isOn(Right()) and wolf.isOn(Right())
|
||||
}
|
||||
|
||||
override State transition() { none() }
|
||||
|
||||
override string toString() { result = "Goal: " + super.toString() }
|
||||
}
|
||||
|
||||
/** An unsafe state, where something gets eaten. */
|
||||
class IllegalState extends State {
|
||||
IllegalState() {
|
||||
exists(Shore s |
|
||||
goat.isOn(s) and cabbage.isOn(s) and not man.isOn(s)
|
||||
or
|
||||
wolf.isOn(s) and goat.isOn(s) and not man.isOn(s)
|
||||
)
|
||||
}
|
||||
|
||||
override State transition() { none() }
|
||||
|
||||
override string toString() { result = "ILLEGAL: " + super.toString() }
|
||||
}
|
||||
|
||||
from string path
|
||||
where any(InitialState i).reachesVia(path) = any(GoalState g)
|
||||
select path
|
||||