Skip to content

Commit 65acf16

Browse files
authored
Merge pull request github#12320 from yoff/python/document-api-call-node
Python: Document `API::CallNode`
2 parents bf6f6ee + 335be21 commit 65acf16

File tree

1 file changed

+34
-10
lines changed

1 file changed

+34
-10
lines changed

docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,16 @@ following snippet demonstrates.
3131
3232
This query selects the API graph node corresponding to the ``re`` module. This node represents the fact that the ``re`` module has been imported rather than a specific location in the program where the import happens. Therefore, there will be at most one result per project, and it will not have a useful location, so you'll have to click `Show 1 non-source result` in order to see it.
3333

34-
To find where the ``re`` module is referenced in the program, you can use the ``getAUse`` method. The following query selects all references to the ``re`` module in the current database.
34+
To find where the ``re`` module is referenced in the program, you can use the ``getAValueReachableFromSource`` method. The following query selects all references to the ``re`` module in the current database.
3535

3636
.. code-block:: ql
3737
3838
import python
3939
import semmle.python.ApiGraphs
4040
41-
select API::moduleImport("re").getAUse()
41+
select API::moduleImport("re").getAValueReachableFromSource()
4242
43-
Note that the ``getAUse`` method accounts for local flow, so that ``my_re_compile``
43+
Note that the ``getAValueReachableFromSource`` method accounts for local flow, so that ``my_re_compile``
4444
in the following snippet is
4545
correctly recognized as a reference to the ``re.compile`` function.
4646

@@ -53,7 +53,7 @@ correctly recognized as a reference to the ``re.compile`` function.
5353
r = my_re_compile(".*")
5454
5555
If you only require immediate uses, without taking local flow into account, then you can use
56-
the ``getAnImmediateUse`` method instead.
56+
the ``asSource`` method instead.
5757

5858
Note that the given module name *must not* contain any dots. Thus, something like
5959
``API::moduleImport("flask.views")`` will not do what you expect. Instead, this should be decomposed
@@ -71,7 +71,7 @@ the above ``re.compile`` example, you can now find references to ``re.compile``.
7171
import python
7272
import semmle.python.ApiGraphs
7373
74-
select API::moduleImport("re").getMember("compile").getAUse()
74+
select API::moduleImport("re").getMember("compile").getAValueReachableFromSource()
7575
7676
In addition to ``getMember``, you can use the ``getUnknownMember`` method to find references to API
7777
components where the name is not known statically. You can use the ``getAMember`` method to
@@ -89,12 +89,36 @@ where the return value of ``re.compile`` is used:
8989
import python
9090
import semmle.python.ApiGraphs
9191
92-
select API::moduleImport("re").getMember("compile").getReturn().getAUse()
92+
select API::moduleImport("re").getMember("compile").getReturn().getAValueReachableFromSource()
9393
9494
Note that this includes all uses of the result of ``re.compile``, including those reachable via
95-
local flow. To get just the *calls* to ``re.compile``, you can use ``getAnImmediateUse`` instead of
96-
``getAUse``. As this is a common occurrence, you can use ``getACall`` instead of
97-
``getReturn`` followed by ``getAnImmediateUse``.
95+
local flow. To get just the *calls* to ``re.compile``, you can use ``asSource`` instead of
96+
``getAValueReachableFromSource``. As this is a common occurrence, you can, instead of
97+
``getReturn`` followed by ``asSource``, simply use ``getACall``. This will result in an
98+
``API::CallNode``, which deserves a small description of its own.
99+
100+
``API::CallNode``s are not ``API::Node``s. Instead they are ``DataFlow::Node``s with some convenience
101+
predicates that allows you to recover ``API::Node``s for the return value as well as for arguments
102+
to the call. This enables you to constrain the call in various ways using the API graph. The following
103+
snippet finds all calls to ``re.compile`` where the ``pattern`` argument comes from parsing a command
104+
line argument using the ``argparse`` library.
105+
106+
.. code-block:: ql
107+
108+
import python
109+
import semmle.python.ApiGraphs
110+
111+
from API::CallNode call
112+
where
113+
call = API::moduleImport("re").getMember("compile").getACall() and
114+
call.getParameter(0, "pattern") =
115+
API::moduleImport("argparse")
116+
.getMember("ArgumentParser")
117+
.getReturn()
118+
.getMember("parse_args")
119+
.getMember(_)
120+
select call
121+
98122
99123
Note that the API graph does not distinguish between class instantiations and function calls. As far
100124
as it's concerned, both are simply places where an API graph node is called.
@@ -122,7 +146,7 @@ all subclasses of ``View``, you must explicitly include the subclasses of ``Meth
122146
API::moduleImport("flask").getMember("views").getMember(["View", "MethodView"]).getASubclass*()
123147
}
124148
125-
select viewClass().getAUse()
149+
select viewClass().getAValueReachableFromSource()
126150
127151
Note the use of the set literal ``["View", "MethodView"]`` to match both classes simultaneously.
128152

0 commit comments

Comments
 (0)