Merge branch 'main' into sourcestest

This commit is contained in:
Geoffrey White
2025-10-22 17:31:25 +01:00
75 changed files with 8110 additions and 5597 deletions

View File

@@ -1,4 +0,0 @@
When reviewing code:
* do not review changes in files with `.expected` extension (they are automatically ensured to be correct).
* in `.ql` and `.qll` files, do not try to review the code itself as you don't understand the programming language
well enough to make comments in these languages. You can still check for typos or comment improvements.

View File

@@ -0,0 +1,4 @@
---
applyTo: "**/*.expected"
---
Ignore these files. These are generated to be correct by running the tests, and should not be edited manually.

View File

@@ -0,0 +1,6 @@
---
applyTo: "**/*.ql,**/*.qll"
---
When reviewing these QL files, do not make any comment on the code itself. You don't understand the QL programming language well enough yet. You can only make comments about the following aspects:
* comments (lines starting with `//` or block comments enclosed in `/* ... */`): you can suggest improvements to the clarity of comments, or point out spelling mistakes
* typos in identifiers

View File

@@ -40,8 +40,29 @@ namespace Semmle.Extraction.CSharp.Entities
get;
}
private static void WriteStarId(EscapingTextWriter writer)
{
writer.Write('*');
}
public sealed override void WriteQuotedId(EscapingTextWriter writer)
{
if (Context.ExtractionContext.IsStandalone)
{
WriteStarId(writer);
return;
}
base.WriteQuotedId(writer);
}
public override void WriteId(EscapingTextWriter trapFile)
{
if (Context.ExtractionContext.IsStandalone)
{
WriteStarId(trapFile);
return;
}
trapFile.Write("loc,");
trapFile.WriteSubId(FileEntity);
trapFile.Write(',');

View File

@@ -74,7 +74,9 @@ namespace Semmle.Extraction.CSharp
specifiedFramework = compilerDir;
}
var versionInfo = FileVersionInfo.GetVersionInfo(SpecifiedCompiler);
// If csc is specified as compiler name, then attempt to read the version information from csc.dll
var compilerBinaryName = Path.GetFileName(SpecifiedCompiler) == "csc" ? $"{SpecifiedCompiler}.dll" : SpecifiedCompiler;
var versionInfo = FileVersionInfo.GetVersionInfo(File.Exists(compilerBinaryName) ? compilerBinaryName : SpecifiedCompiler);
if (!knownCompilerNames.TryGetValue(versionInfo.OriginalFilename ?? string.Empty, out var vendor))
{
SkipExtractionBecause("the compiler name is not recognised");

View File

@@ -0,0 +1 @@
Console.WriteLine($"<arguments>{string.Join(",", args)}</arguments>");

View File

@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,5 @@
{
"sdk": {
"version": "10.0.100-rc.2.25502.107"
}
}

View File

@@ -0,0 +1,6 @@
import os
import runs_on
@runs_on.linux
def test(codeql, csharp):
codeql.database.create()

View File

@@ -0,0 +1 @@
Console.WriteLine($"<arguments>{string.Join(",", args)}</arguments>");

View File

@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,5 @@
{
"sdk": {
"version": "10.0.100-rc.2.25502.107"
}
}

View File

@@ -0,0 +1,6 @@
import os
import runs_on
@runs_on.windows
def test(codeql, csharp):
codeql.database.create()

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The extraction of location information for source code entities has been updated to use star IDs (`*` IDs). This change should be transparent to end-users but may improve extraction performance in some cases by reducing TRAP file size and eliminating overhead from location de-duplication.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added tracer support for macOS and Linux when the .NET CLI (`dotnet`) directly invokes the C# compiler (`csc`). This enhancement provides basic tracing and extraction capabilities for .NET 10 RC2 on these platforms.

View File

@@ -221,9 +221,9 @@ function RegisterExtractorPack(id)
}
local posixMatchers = {
DotnetMatcherBuild,
CreatePatternMatcher({ '^mcs%.exe$', '^csc%.exe$' }, MatchCompilerName,
CreatePatternMatcher({ '^mcs%.exe$', '^csc%.exe$', '^csc$' }, MatchCompilerName,
extractor, {
prepend = { '--compiler', '"${compiler}"' },
prepend = { '--compiler', '${compiler}' },
order = ORDER_BEFORE
}),
MsBuildMatcher,

View File

@@ -314,7 +314,7 @@ Exercise 2: Write a query that finds all hard-coded strings used to create a ``h
Exercise 3: Write a class that represents flow sources from ``getenv``. (`Answer <#exercise-3>`__)
Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flow paths from ``getenv`` to ``gethostbyname``. (`Answer <#exercise-4>`__)
Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flow paths from ``getenv`` to ``gethostbyname``. (`Answer <#exercise-4>`__ `Answer as a path query <#path-query-example>`__)
Answers
-------
@@ -411,6 +411,48 @@ Exercise 4
GetenvToGethostbynameFlow::flow(source, sink)
select getenv, fc
Path query example
~~~~~~~~~~~~~~~~~~
Here is the answer to exercise 4 above, converted into a path query:
.. code-block:: ql
/**
* @kind path-problem
* @problem.severity warning
* @id getenv-to-gethostbyname
*/
import cpp
import semmle.code.cpp.dataflow.new.DataFlow
class GetenvSource extends DataFlow::Node {
GetenvSource() { this.asIndirectExpr(1).(FunctionCall).getTarget().hasGlobalName("getenv") }
}
module GetenvToGethostbynameConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof GetenvSource }
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall fc |
sink.asIndirectExpr(1) = fc.getArgument(0) and
fc.getTarget().hasName("gethostbyname")
)
}
}
module GetenvToGethostbynameFlow = DataFlow::Global<GetenvToGethostbynameConfiguration>;
import GetenvToGethostbynameFlow::PathGraph
from GetenvToGethostbynameFlow::PathNode source, GetenvToGethostbynameFlow::PathNode sink
where GetenvToGethostbynameFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "This file access uses data from $@.",
source, "user-controllable input."
For more information, see "`Creating path queries <https://codeql.github.com/docs/writing-codeql-queries/creating-path-queries/>`__".
Further reading
---------------

View File

@@ -287,7 +287,7 @@ Exercise 2: Find all hard-coded strings passed to ``System.Uri``, using global d
Exercise 3: Define a class that represents flow sources from ``System.Environment.GetEnvironmentVariable``. (`Answer <#exercise-3>`__)
Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flow paths from ``System.Environment.GetEnvironmentVariable`` to ``System.Uri``. (`Answer <#exercise-4>`__)
Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flow paths from ``System.Environment.GetEnvironmentVariable`` to ``System.Uri``. (`Answer <#exercise-4>`__ `Answer as a path query <#path-query-example>`__)
Extending library data flow
---------------------------
@@ -537,6 +537,48 @@ This can be adapted from the ``SystemUriFlow`` class:
}
}
Path query example
~~~~~~~~~~~~~~~~~~
Here is the answer to exercise 4 above, converted into a path query:
.. code-block:: ql
/**
* @kind path-problem
* @problem.severity warning
* @id getenv-to-gethostbyname
*/
import csharp
class EnvironmentVariableFlowSource extends DataFlow::ExprNode {
EnvironmentVariableFlowSource() {
this.getExpr().(MethodCall).getTarget().hasQualifiedName("System.Environment.GetEnvironmentVariable")
}
}
module EnvironmentToUriConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) {
src instanceof EnvironmentVariableFlowSource
}
predicate isSink(DataFlow::Node sink) {
exists(Call c | c.getTarget().(Constructor).getDeclaringType().hasQualifiedName("System.Uri")
and sink.asExpr()=c.getArgument(0))
}
}
module EnvironmentToUriFlow = DataFlow::Global<EnvironmentToUriConfig>;
import EnvironmentToUriFlow::PathGraph
from EnvironmentToUriFlow::PathNode src, EnvironmentToUriFlow::PathNode sink
where EnvironmentToUriFlow::flowPath(src, sink)
select src.getNode(), src, sink, "This environment variable constructs a 'System.Uri' $@.", sink, "here"
For more information, see "`Creating path queries <https://codeql.github.com/docs/writing-codeql-queries/creating-path-queries/>`__".
Further reading
---------------

View File

@@ -224,7 +224,7 @@ The resulting module has an identical signature to the one obtained from ``DataF
Flow sources
~~~~~~~~~~~~
The data flow library contains some predefined flow sources. The class ``RemoteFlowSource`` (defined in ``semmle.code.java.dataflow.FlowSources``) represents data flow sources that may be controlled by a remote user, which is useful for finding security problems.
The data flow library contains some predefined flow sources. The class ``RemoteFlowSource`` represents data flow sources that may be controlled by a remote user, which is useful for finding security problems.
Examples
~~~~~~~~
@@ -252,7 +252,7 @@ Exercise 2: Write a query that finds all hard-coded strings used to create a ``u
Exercise 3: Write a class that represents flow sources from ``os.Getenv(..)``. (`Answer <#exercise-3>`__)
Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flow paths from ``os.Getenv`` to ``url.URL``. (`Answer <#exercise-4>`__)
Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flow paths from ``os.Getenv`` to ``url.URL``. (`Answer <#exercise-4>`__ `Answer as a path query <#path-query-example>`__)
Answers
-------
@@ -312,7 +312,7 @@ Exercise 3
import go
class GetenvSource extends CallExpr {
class GetenvSource extends DataFlow::CallNode {
GetenvSource() {
exists(Function m | m = this.getTarget() |
m.hasQualifiedName("os", "Getenv")
@@ -327,7 +327,7 @@ Exercise 4
import go
class GetenvSource extends CallExpr {
class GetenvSource extends DataFlow::CallNode {
GetenvSource() {
exists(Function m | m = this.getTarget() |
m.hasQualifiedName("os", "Getenv")
@@ -350,7 +350,6 @@ Exercise 4
sink.asExpr() = call.getArgument(0)
)
}
}
}
module GetenvToURLFlow = DataFlow::Global<GetenvToURLConfig>;
@@ -359,6 +358,56 @@ Exercise 4
where GetenvToURLFlow::flow(src, sink)
select src, "This environment variable constructs a URL $@.", sink, "here"
Path query example
~~~~~~~~~~~~~~~~~~
Here is the answer to exercise 4 above, converted into a path query:
.. code-block:: ql
/**
* @kind path-problem
* @problem.severity warning
* @id getenv-to-url
*/
import go
class GetenvSource extends DataFlow::CallNode {
GetenvSource() {
exists(Function m | m = this.getTarget() |
m.hasQualifiedName("os", "Getenv")
)
}
}
module GetenvToURLConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof GetenvSource
}
predicate isSink(DataFlow::Node sink) {
exists(Function urlParse, CallExpr call |
(
urlParse.hasQualifiedName("url", "Parse") or
urlParse.hasQualifiedName("url", "ParseRequestURI")
) and
call.getTarget() = urlParse and
sink.asExpr() = call.getArgument(0)
)
}
}
module GetenvToURLFlow = DataFlow::Global<GetenvToURLConfig>;
import GetenvToURLFlow::PathGraph
from GetenvToURLFlow::PathNode src, GetenvToURLFlow::PathNode sink
where GetenvToURLFlow::flowPath(src, sink)
select src.getNode(), src, sink, "This environment variable constructs a URL $@.", sink, "here"
For more information, see "`Creating path queries <https://codeql.github.com/docs/writing-codeql-queries/creating-path-queries/>`__".
Further reading
---------------

View File

@@ -262,7 +262,7 @@ Exercise 2: Write a query that finds all hard-coded strings used to create a ``j
Exercise 3: Write a class that represents flow sources from ``java.lang.System.getenv(..)``. (`Answer <#exercise-3>`__)
Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flow paths from ``getenv`` to ``java.net.URL``. (`Answer <#exercise-4>`__)
Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flow paths from ``getenv`` to ``java.net.URL``. (`Answer <#exercise-4>`__ `Answer as a path query <#path-query-example>`__)
Answers
-------
@@ -361,6 +361,54 @@ Exercise 4
where GetenvToURLFlow::flow(src, sink)
select src, "This environment variable constructs a URL $@.", sink, "here"
Path query example
~~~~~~~~~~~~~~~~~~
Here is the answer to exercise 4 above, converted into a path query:
.. code-block:: ql
/**
* @kind path-problem
* @problem.severity warning
* @id getenv-to-url
*/
import java
import semmle.code.java.dataflow.DataFlow
class GetenvSource extends DataFlow::ExprNode {
GetenvSource() {
exists(Method m | m = this.asExpr().(MethodCall).getMethod() |
m.hasName("getenv") and
m.getDeclaringType() instanceof TypeSystem
)
}
}
module GetenvToURLConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof GetenvSource
}
predicate isSink(DataFlow::Node sink) {
exists(Call call |
sink.asExpr() = call.getArgument(0) and
call.getCallee().(Constructor).getDeclaringType().hasQualifiedName("java.net", "URL")
)
}
}
module GetenvToURLFlow = DataFlow::Global<GetenvToURLConfig>;
import GetenvToURLFlow::PathGraph
from GetenvToURLFlow::PathNode src, GetenvToURLFlow::PathNode sink
where GetenvToURLFlow::flowPath(src, sink)
select src.getNode(), src, sink, "This environment variable constructs a URL $@.", sink, "here"
For more information, see "`Creating path queries <https://codeql.github.com/docs/writing-codeql-queries/creating-path-queries/>`__".
Further reading
---------------

View File

@@ -456,7 +456,7 @@ Exercise 3: Write a class which represents flow sources from the array elements
Hint: array indices are properties with numeric names; you can use regular expression matching to check this. (`Answer <#exercise-3>`__)
Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flow paths from array elements of the result of a call to the ``tagName`` argument to the
``createElement`` function. (`Answer <#exercise-4>`__)
``createElement`` function. (`Answer <#exercise-4>`__ `Answer as a path query <#path-query-example>`__)
Answers
-------
@@ -541,6 +541,48 @@ Exercise 4
where HardCodedTagNameFlow::flow(source, sink)
select source, sink
Path query example
~~~~~~~~~~~~~~~~~~
Here is the answer to exercise 4 above, converted into a path query:
.. code-block:: ql
/**
* @kind path-problem
* @problem.severity warning
* @id hard-coded-tag-name
*/
import javascript
class ArrayEntryCallResult extends DataFlow::Node {
ArrayEntryCallResult() {
exists(DataFlow::CallNode call, string index |
this = call.getAPropertyRead(index) and
index.regexpMatch("\\d+")
)
}
}
module HardCodedTagNameConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof ArrayEntryCallResult }
predicate isSink(DataFlow::Node sink) {
sink = DataFlow::globalVarRef("document").getAMethodCall("createElement").getArgument(0)
}
}
module HardCodedTagNameFlow = DataFlow::Global<HardCodedTagNameConfig>;
import HardCodedTagNameFlow::PathGraph
from HardCodedTagNameFlow::PathNode source, HardCodedTagNameFlow::PathNode sink
where HardCodedTagNameFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Hard-coded tag name $@.", source, "here"
For more information, see "`Creating path queries <https://codeql.github.com/docs/writing-codeql-queries/creating-path-queries/>`__".
Further reading
---------------

View File

@@ -354,11 +354,50 @@ This data flow configuration tracks data flow from environment variables to open
select fileOpen, "This call to 'os.open' uses data from $@.",
environment, "call to 'os.getenv'"
Path query example
~~~~~~~~~~~~~~~~~~
Here is the network input example above, converted into a path query:
.. code-block:: ql
/**
* @kind path-problem
* @problem.severity warning
* @id file-system-access-from-remote-input
*/
import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
import semmle.python.dataflow.new.RemoteFlowSources
import semmle.python.Concepts
module RemoteToFileConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource
}
predicate isSink(DataFlow::Node sink) {
sink = any(FileSystemAccess fa).getAPathArgument()
}
}
module RemoteToFileFlow = TaintTracking::Global<RemoteToFileConfiguration>;
import RemoteToFileFlow::PathGraph
from RemoteToFileFlow::PathNode input, RemoteToFileFlow::PathNode fileAccess
where RemoteToFileFlow::flowPath(input, fileAccess)
select fileAccess.getNode(), input, fileAccess, "This file access uses data from $@.",
input, "user-controllable input."
For more information, see "`Creating path queries <https://codeql.github.com/docs/writing-codeql-queries/creating-path-queries/>`__".
Further reading
---------------
- `Exploring data flow with path queries <https://docs.github.com/en/code-security/codeql-for-vs-code/getting-started-with-codeql-for-vs-code/exploring-data-flow-with-path-queries>`__ in the GitHub documentation.
- `Creating path queries <https://codeql.github.com/docs/writing-codeql-queries/creating-path-queries/>`__.
.. include:: ../reusables/python-further-reading.rst

View File

@@ -372,6 +372,43 @@ The following global data-flow query finds calls to ``File.open`` where the file
select fileOpen, "This call to 'File.open' uses data from $@.", environment,
"an environment variable"
Path query example
~~~~~~~~~~~~~~~~~~
Here is the taint-tracking example above, converted into a path query:
.. code-block:: ql
/**
* @kind path-problem
* @problem.severity warning
* @id file-system-access-from-remote-input
*/
import codeql.ruby.DataFlow
import codeql.ruby.TaintTracking
import codeql.ruby.Concepts
import codeql.ruby.dataflow.RemoteFlowSources
module RemoteToFileConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) {
sink = any(FileSystemAccess fa).getAPathArgument()
}
}
module RemoteToFileFlow = TaintTracking::Global<RemoteToFileConfiguration>;
import RemoteToFileFlow::PathGraph
from RemoteToFileFlow::PathNode input, RemoteToFileFlow::PathNode fileAccess
where RemoteToFileFlow::flowPath(input, fileAccess)
select fileAccess.getNode(), input, fileAccess, "This file access uses data from $@.",
input, "user-controllable input."
For more information, see "`Creating path queries <https://codeql.github.com/docs/writing-codeql-queries/creating-path-queries/>`__".
Further reading
---------------

View File

@@ -231,6 +231,46 @@ The following global taint-tracking query finds places where a string literal is
where ConstantPasswordFlow::flow(sourceNode, sinkNode)
select sinkNode, "The value $@ is used as a constant password.", sourceNode, sourceNode.toString()
Path query example
~~~~~~~~~~~~~~~~~~
Here is the taint-tracking example above, converted into a path query:
.. code-block:: ql
/**
* @kind path-problem
* @problem.severity warning
* @id constant-password
*/
import rust
import codeql.rust.dataflow.DataFlow
import codeql.rust.dataflow.TaintTracking
module ConstantPasswordConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node.asExpr().getExpr() instanceof StringLiteralExpr }
predicate isSink(DataFlow::Node node) {
// any argument going to a parameter called `password`
exists(Function f, CallExpr call, int index |
call.getArg(index) = node.asExpr().getExpr() and
call.getStaticTarget() = f and
f.getParam(index).getPat().(IdentPat).getName().getText() = "password"
)
}
}
module ConstantPasswordFlow = TaintTracking::Global<ConstantPasswordConfig>;
import ConstantPasswordFlow::PathGraph
from ConstantPasswordFlow::PathNode sourceNode, ConstantPasswordFlow::PathNode sinkNode
where ConstantPasswordFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode, "The value $@ is used as a constant password.", sourceNode, sourceNode.toString()
For more information, see "`Creating path queries <https://codeql.github.com/docs/writing-codeql-queries/creating-path-queries/>`__".
Further reading
---------------

View File

@@ -278,6 +278,45 @@ The following global taint-tracking query finds places where a value from a remo
where SqlInjectionFlow::flow(sourceNode, sinkNode)
select sinkNode, "This query depends on a $@.", sourceNode, "user-provided value"
Path query example
~~~~~~~~~~~~~~~~~~
Here is the string literal example above, converted into a path query:
.. code-block:: ql
/**
* @kind path-problem
* @problem.severity warning
* @id sql-injection
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.dataflow.FlowSources
module SqlInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node instanceof FlowSource }
predicate isSink(DataFlow::Node node) {
exists(CallExpr call |
call.getStaticTarget().(Method).hasQualifiedName("Connection", "execute(_:)") and
call.getArgument(0).getExpr() = node.asExpr()
)
}
}
module SqlInjectionFlow = TaintTracking::Global<SqlInjectionConfig>;
import SqlInjectionFlow::PathGraph
from SqlInjectionFlow::PathNode sourceNode, SqlInjectionFlow::PathNode sinkNode
where SqlInjectionFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode, "This query depends on a $@.", sourceNode, "user-provided value"
For more information, see "`Creating path queries <https://codeql.github.com/docs/writing-codeql-queries/creating-path-queries/>`__".
Further reading
---------------

View File

@@ -0,0 +1,136 @@
.. _codeql-cli-2.23.3:
==========================
CodeQL 2.23.3 (2025-10-17)
==========================
.. contents:: Contents
:depth: 2
:local:
:backlinks: none
This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog <https://github.blog/tag/code-scanning/>`__, `relevant GitHub Changelog updates <https://github.blog/changelog/label/application-security/>`__, `changes in the CodeQL extension for Visual Studio Code <https://marketplace.visualstudio.com/items/GitHub.vscode-codeql/changelog>`__, and the `CodeQL Action changelog <https://github.com/github/codeql-action/blob/main/CHANGELOG.md>`__.
Security Coverage
-----------------
CodeQL 2.23.3 runs a total of 480 security queries when configured with the Default suite (covering 166 CWE). The Extended suite enables an additional 135 queries (covering 35 more CWE). 1 security query has been added with this release.
CodeQL CLI
----------
Breaking Changes
~~~~~~~~~~~~~~~~
* The :code:`--permissive` command line option has been removed from the C/C++ extractor,
and passing the option will make the extractor fail. The option was introduced to make the extractor accept the following invalid code, which is accepted by gcc with the :code:`-fpermissive` flag:
.. code-block:: cpp
void f(char*);
void g() {
const char* str = "string";
f(str);
}
The :code:`--permissive` option was removed, as under some circumstances it would break the extractor's ability to parse valid C++ code. When calling the extractor directly,
:code:`--permissive` should no longer be passed. The above code will fail to parse, and we recommend the code being made :code:`const`\ -correct.
Bug Fixes
~~~~~~~~~
* Fixed a bug that made many :code:`codeql` subcommands fail with the message :code:`not in while, until, select, or repeat loop` on Linux or macOS systems where :code:`/bin/sh` is :code:`zsh`.
Query Packs
-----------
New Queries
~~~~~~~~~~~
Rust
""""
* Added a new query, :code:`rust/insecure-cookie`, to detect cookies created without the 'Secure' attribute.
Language Libraries
------------------
Bug Fixes
~~~~~~~~~
Python
""""""
* The Python extractor no longer crashes with an :code:`ImportError` when run using Python 3.14.
Breaking Changes
~~~~~~~~~~~~~~~~
C/C++
"""""
* The "Guards" libraries (:code:`semmle.code.cpp.controlflow.Guards` and :code:`semmle.code.cpp.controlflow.IRGuards`) have been totally rewritten to recognize many more guards. The API remains unchanged, but the :code:`GuardCondition` class now extends :code:`Element` instead of :code:`Expr`.
Golang
""""""
* The member predicate :code:`writesField` on :code:`DataFlow::Write` now uses the post-update node for :code:`base` when that is the node being updated, which is in all cases except initializing a struct literal. A new member predicate :code:`writesFieldPreUpdate` has been added for cases where this behaviour is not desired.
* The member predicate :code:`writesElement` on :code:`DataFlow::Write` now uses the post-update node for :code:`base` when that is the node being updated, which is in all cases except initializing an array/slice/map literal. A new member predicate :code:`writesElementPreUpdate` has been added for cases where this behaviour is not desired.
Major Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Golang
""""""
* The shape of the Go data-flow graph has changed. Previously for code like :code:`x := def(); use1(x); use2(x)`, there would be edges from the definition of :code:`x` to each use. Now there is an edge from the definition to the first use, then another from the first use to the second, and so on. This means that data-flow barriers work differently - flow will not reach any uses after the barrier node. Where this is not desired it may be necessary to add an additional flow step to propagate the flow forward. Additionally, when a variable may be subject to a side-effect, such as updating an array, passing a pointer to a function that might write through it or writing to a field of a struct, there is now a dedicated post-update node representing the variable after this side-effect has taken place. Previously post-update nodes were aliases for either a variable's definition, or were equal to the pre-update node. This led to backwards steps in the data-flow graph, which could cause false positives. For example, in the previous code there would be an edge from :code:`x` in :code:`use2(x)` back to the definition of :code:`x`. If we define our sources as any argument of :code:`use2` and our sinks as any argument of :code:`use1` then this would lead to a false positive path. Now there are distinct post-update nodes and no backwards edge to the definition, so we will not find this false positive path.
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
C#
""
* The extraction of location information for parameters, fields, constructors, destructors and user operators has been optimized. Previously, location information was extracted multiple times for each bound generic. Now, only the location of the unbound generic declaration is extracted during the extraction phase, and the QL library explicitly reuses this location for all bound instances of the same generic.
* The extraction of location information for type parameters and tuples types has been optimized. Previously, location information was extracted multiple times for each type when it was declared across multiple files. Now, the extraction context is respected during the extraction phase, ensuring locations are only extracted within the appropriate context. This change should be transparent to end-users but may improve extraction performance in some cases.
* The extraction of location information for named types (classes, structs, etc.) has been optimized. Previously, location information was extracted multiple times for each type when it was declared across multiple files. Now, the extraction context is respected during the extraction phase, ensuring locations are only extracted within the appropriate context. This change should be transparent to end-users but may improve extraction performance in some cases.
* The extraction of the location for bound generic entities (methods, accessors, indexers, properties, and events) has been optimized. Previously, location information was extracted multiple times for each bound generic. Now, only the location of the unbound generic declaration is extracted during the extraction phase, and the QL library explicitly reuses this location for all bound instances of the same generic.
Golang
""""""
* The query :code:`go/request-forgery` will no longer report alerts when the user input is of a simple type, like a number or a boolean.
* For the query :code:`go/unvalidated-url-redirection`, when untrusted data is assigned to the :code:`Host` field of a :code:`url.URL` struct, we consider the whole struct untrusted. We now also include the case when this happens during struct initialization, for example :code:`&url.URL{Host: untrustedData}`.
* :code:`go/unvalidated-url-redirection` and :code:`go/request-forgery` have a shared notion of a safe URL, which is known to not be malicious. Some URLs which were incorrectly considered safe are now correctly considered unsafe. This may lead to more alerts for those two queries.
Java/Kotlin
"""""""""""
* Fields of certain objects are considered tainted if the object is tainted. This holds, for example, for objects that occur directly as sources in the active threat model (for instance, a remote flow source). This has now been amended to also include array types, such that if an array like :code:`MyPojo[]` is a source, then fields of a tainted :code:`MyPojo` are now also considered tainted.
Rust
""""
* Improve data flow through functions being passed as function pointers.
Deprecated APIs
~~~~~~~~~~~~~~~
Golang
""""""
* The class :code:`SqlInjection::NumericOrBooleanSanitizer` has been deprecated. Use :code:`SimpleTypeSanitizer` from :code:`semmle.go.security.Sanitizers` instead.
* The member predicate :code:`writesComponent` on :code:`DataFlow::Write` has been deprecated. Instead, use :code:`writesFieldPreUpdate` and :code:`writesElementPreUpdate`, or their new versions :code:`writesField` and :code:`writesElement`.
New Features
~~~~~~~~~~~~
C/C++
"""""
* C/C++ :code:`build-mode: none` support is now generally available.
Rust
""""
* Rust analysis is now Generally Available (GA).

View File

@@ -11,6 +11,7 @@ A list of queries for each suite and language `is available here <https://docs.g
.. toctree::
:maxdepth: 1
codeql-cli-2.23.3
codeql-cli-2.23.2
codeql-cli-2.23.1
codeql-cli-2.23.0

View File

@@ -0,0 +1,4 @@
---
category: majorAnalysis
---
* Resolution of calls to functions has been improved in a number of ways, to make it more aligned with the behavior of the Rust compiler. This may impact queries that rely on call resolution, such as data flow queries.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added `ExtractedFile::hasSemantics` and `ExtractedFile::isSkippedByCompilation` predicates.

View File

@@ -71,6 +71,25 @@ class File extends Container, Impl::File {
*/
class ExtractedFile extends File {
ExtractedFile() { this.fromSource() }
private Diagnostic getNoSemanticsDiagnostic() {
result.getTag() = "semantics" and result.getLocation().getFile() = this
}
/**
* Holds if we have semantical information about this file, which means
* we should be able to
* * expand any macros
* * skip any blocks that are conditionally compiled out
*/
predicate hasSemantics() { not exists(this.getNoSemanticsDiagnostic()) }
/**
* Holds if we know this file was skipped by conditional compilation.
* This is not the same as `not this.hasSemantics()`, as a file
* might not have semantics because of some error.
*/
predicate isSkippedByCompilation() { this.getNoSemanticsDiagnostic().getSeverityText() = "Info" }
}
/**

View File

@@ -12,7 +12,7 @@ private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
* the canonical path `path` and the method name `method`, and if it borrows its
* first `borrows` arguments.
*/
private predicate isOverloaded(string op, int arity, string path, string method, int borrows) {
predicate isOverloaded(string op, int arity, string path, string method, int borrows) {
arity = 1 and
(
// Negation

View File

@@ -47,6 +47,9 @@ module Impl {
*/
TypeBound getATypeBound() { result = this.getTypeBound(_) }
/** Holds if this type parameter has at least one type bound. */
predicate hasTypeBound() { exists(this.getATypeBound()) }
override string toAbbreviatedString() { result = this.getName().getText() }
override string toStringImpl() { result = this.getName().getText() }

View File

@@ -213,3 +213,96 @@ class StringStruct extends Struct {
pragma[nomagic]
StringStruct() { this.getCanonicalPath() = "alloc::string::String" }
}
/**
* The [`Deref` trait][1].
*
* [1]: https://doc.rust-lang.org/core/ops/trait.Deref.html
*/
class DerefTrait extends Trait {
pragma[nomagic]
DerefTrait() { this.getCanonicalPath() = "core::ops::deref::Deref" }
/** Gets the `deref` function. */
Function getDerefFunction() { result = this.(TraitItemNode).getAssocItem("deref") }
/** Gets the `Target` associated type. */
pragma[nomagic]
TypeAlias getTargetType() {
result = this.getAssocItemList().getAnAssocItem() and
result.getName().getText() = "Target"
}
}
/**
* The [`Index` trait][1].
*
* [1]: https://doc.rust-lang.org/std/ops/trait.Index.html
*/
class IndexTrait extends Trait {
pragma[nomagic]
IndexTrait() { this.getCanonicalPath() = "core::ops::index::Index" }
/** Gets the `index` function. */
Function getIndexFunction() { result = this.(TraitItemNode).getAssocItem("index") }
/** Gets the `Output` associated type. */
pragma[nomagic]
TypeAlias getOutputType() {
result = this.getAssocItemList().getAnAssocItem() and
result.getName().getText() = "Output"
}
}
/**
* The [`Box` struct][1].
*
* [1]: https://doc.rust-lang.org/std/boxed/struct.Box.html
*/
class BoxStruct extends Struct {
pragma[nomagic]
BoxStruct() { this.getCanonicalPath() = "alloc::boxed::Box" }
}
/**
* The [`Rc` struct][1].
*
* [1]: https://doc.rust-lang.org/std/rc/struct.Rc.html
*/
class RcStruct extends Struct {
pragma[nomagic]
RcStruct() { this.getCanonicalPath() = "alloc::rc::Rc" }
}
/**
* The [`Arc` struct][1].
*
* [1]: https://doc.rust-lang.org/std/sync/struct.Arc.html
*/
class ArcStruct extends Struct {
pragma[nomagic]
ArcStruct() { this.getCanonicalPath() = "alloc::sync::Arc" }
}
/**
* The [`Pin` struct][1].
*
* [1]: https://doc.rust-lang.org/std/pin/struct.Pin.html
*/
class PinStruct extends Struct {
pragma[nomagic]
PinStruct() { this.getCanonicalPath() = "core::pin::Pin" }
}
/**
* The [`Vec` struct][1].
*
* [1]: https://doc.rust-lang.org/alloc/vec/struct.Vec.html
*/
class Vec extends Struct {
pragma[nomagic]
Vec() { this.getCanonicalPath() = "alloc::vec::Vec" }
/** Gets the type parameter representing the element type. */
TypeParam getElementTypeParam() { result = this.getGenericParamList().getTypeParam(0) }
}

View File

@@ -840,7 +840,7 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
}
}
final private class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
final class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
pragma[nomagic]
Path getABoundPath() {
result = super.getTypeBoundList().getABound().getTypeRepr().(PathTypeRepr).getPath()
@@ -963,7 +963,9 @@ final class TraitItemNode extends ImplOrTraitItemNode, TypeItemNode instanceof T
Path getABoundPath() { result = super.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() }
pragma[nomagic]
ItemNode resolveABound() { result = resolvePath(this.getABoundPath()) }
ItemNode resolveBound(Path path) { path = this.getABoundPath() and result = resolvePath(path) }
ItemNode resolveABound() { result = this.resolveBound(_) }
override AssocItemNode getAnAssocItem() { result = this.getADescendant() }
@@ -1643,25 +1645,55 @@ signature predicate relevantTraitVisibleSig(Element element, Trait trait);
* at a given element.
*/
module TraitIsVisible<relevantTraitVisibleSig/2 relevantTraitVisible> {
/** Holds if the trait might be looked up in `encl`. */
private predicate traitLookup(ItemNode encl, Element element, Trait trait) {
// lookup in immediately enclosing item
relevantTraitVisible(element, trait) and
encl.getADescendant() = element
private newtype TNode =
TTrait(Trait t) { relevantTraitVisible(_, t) } or
TItemNode(ItemNode i) or
TElement(Element e) { relevantTraitVisible(e, _) }
private predicate isTrait(TNode n) { n instanceof TTrait }
private predicate step(TNode n1, TNode n2) {
exists(Trait t1, ItemNode i2 |
n1 = TTrait(t1) and
n2 = TItemNode(i2) and
t1 = i2.getASuccessor(_, _, _)
)
or
// lookup in an outer scope, but only if the trait is not declared in inner scope
exists(ItemNode mid |
traitLookup(mid, element, trait) and
not trait = mid.getASuccessor(_, _, _) and
encl = getOuterScope(mid)
exists(ItemNode i1, ItemNode i2 |
n1 = TItemNode(i1) and
n2 = TItemNode(i2) and
i1 = getOuterScope(i2)
)
or
exists(ItemNode i1, Element e2 |
n1 = TItemNode(i1) and
n2 = TElement(e2) and
i1.getADescendant() = e2
)
}
private predicate isElement(TNode n) { n instanceof TElement }
private predicate traitIsVisibleTC(TNode trait, TNode element) =
doublyBoundedFastTC(step/2, isTrait/1, isElement/1)(trait, element)
pragma[nomagic]
private predicate relevantTraitVisibleLift(TNode trait, TElement element) {
exists(Trait t, Element e |
trait = TTrait(t) and
element = TElement(e) and
relevantTraitVisible(e, t)
)
}
/** Holds if the trait `trait` is visible at `element`. */
pragma[nomagic]
predicate traitIsVisible(Element element, Trait trait) {
exists(ItemNode encl |
traitLookup(encl, element, trait) and trait = encl.getASuccessor(_, _, _)
exists(TNode t, TNode e |
traitIsVisibleTC(t, e) and
relevantTraitVisibleLift(t, e) and
t = TTrait(trait) and
e = TElement(element)
)
}
}
@@ -2101,7 +2133,7 @@ private predicate builtin(string name, ItemNode i) {
/** Provides predicates for debugging the path resolution implementation. */
private module Debug {
private Locatable getRelevantLocatable() {
Locatable getRelevantLocatable() {
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
filepath.matches("%/main.rs") and

View File

@@ -6,6 +6,7 @@ private import TypeMention
private import codeql.rust.internal.CachedStages
private import codeql.rust.elements.internal.generated.Raw
private import codeql.rust.elements.internal.generated.Synth
private import codeql.rust.frameworks.stdlib.Stdlib
/**
* Holds if a dyn trait type should have a type parameter associated with `n`. A
@@ -624,3 +625,32 @@ final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeR
implTraitTypeParam(this, _, result.(TypeParamTypeParameter).getTypeParam())
}
}
/**
* Holds if `t` is a valid complex [`self` root type][1].
*
* [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html#r-items.associated.fn.method.self-ty
*/
pragma[nomagic]
predicate validSelfType(Type t) {
t instanceof RefType
or
exists(Struct s | t = TStruct(s) |
s instanceof BoxStruct or
s instanceof RcStruct or
s instanceof ArcStruct or
s instanceof PinStruct
)
}
/**
* Holds if `root` is a valid complex [`self` root type][1], with type
* parameter `tp`.
*
* [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html#r-items.associated.fn.method.self-ty
*/
pragma[nomagic]
predicate complexSelfRoot(Type root, TypeParameter tp) {
validSelfType(root) and
tp = root.getPositionalTypeParameter(0)
}

File diff suppressed because it is too large Load Diff

View File

@@ -9,9 +9,11 @@ private import TypeInference
/** An AST node that may mention a type. */
abstract class TypeMention extends AstNode {
/** Gets the type at `path` that this mention resolves to, if any. */
pragma[nomagic]
abstract Type resolveTypeAt(TypePath path);
/** Gets the type that this node resolves to, if any. */
pragma[nomagic]
final Type resolveType() { result = this.resolveTypeAt(TypePath::nil()) }
}
@@ -92,7 +94,6 @@ class AliasPathTypeMention extends PathTypeMention {
* Holds if this path resolved to a type alias with a rhs. that has the
* resulting type at `typePath`.
*/
pragma[nomagic]
override Type resolveTypeAt(TypePath typePath) {
result = rhs.resolveTypeAt(typePath) and
not result = pathGetTypeParameter(resolved, _)
@@ -112,7 +113,8 @@ class NonAliasPathTypeMention extends PathTypeMention {
NonAliasPathTypeMention() {
resolved = [resolvePath(this), resolvePath(this).(Variant).getEnum().(TypeItemNode)] and
not exists(resolved.(TypeAlias).getTypeRepr())
not exists(resolved.(TypeAlias).getTypeRepr()) and
not this = any(ImplItemNode i).getASelfPath() // handled by `ImplSelfMention`
}
TypeItemNode getResolved() { result = resolved }
@@ -144,23 +146,6 @@ class NonAliasPathTypeMention extends PathTypeMention {
private TypeMention getPositionalTypeArgument0(int i) {
result = this.getSegment().getGenericArgList().getTypeArg(i)
or
// `Self` paths inside `impl` blocks have implicit type arguments that are
// the type parameters of the `impl` block. For example, in
//
// ```rust
// impl<T> Foo<T> {
// fn m(self) -> Self {
// self
// }
// }
// ```
//
// the `Self` return type is shorthand for `Foo<T>`.
exists(ImplItemNode node |
this = node.getASelfPath() and
result = node.(ImplItemNode).getSelfPath().getSegment().getGenericArgList().getTypeArg(i)
)
or
// `Option::<i32>::Some` is valid in addition to `Option::Some::<i32>`
resolvePath(this) instanceof Variant and
result = this.getQualifier().getSegment().getGenericArgList().getTypeArg(i)
@@ -259,6 +244,19 @@ class NonAliasPathTypeMention extends PathTypeMention {
}
}
pragma[nomagic]
private Type resolveImplSelfTypeAt(Impl i, TypePath path) {
result = i.getSelfTy().(TypeMention).resolveTypeAt(path)
}
class ImplSelfMention extends PathTypeMention {
private ImplItemNode impl;
ImplSelfMention() { this = impl.getASelfPath() }
override Type resolveTypeAt(TypePath typePath) { result = resolveImplSelfTypeAt(impl, typePath) }
}
class PathTypeReprMention extends TypeMention, PathTypeRepr {
private PathTypeMention path;
@@ -329,6 +327,69 @@ class SelfTypeParameterMention extends TypeMention instanceof Name {
}
}
/**
* Gets the type at `path` of the type being implemented in `i`, when
* `i` is an `impl` block, or the synthetic `Self` type parameter when
* `i` is a trait.
*/
pragma[nomagic]
Type resolveImplOrTraitType(ImplOrTraitItemNode i, TypePath path) {
result = resolveImplSelfTypeAt(i, path)
or
result = TSelfTypeParameter(i) and path.isEmpty()
}
pragma[nomagic]
private ImplOrTraitItemNode getSelfParamEnclosingImplOrTrait(SelfParam self) {
self = result.getAnAssocItem().(Function).getSelfParam()
}
/**
* An element used to represent the type of a `self` parameter that uses [shorthand
* syntax][1], which is sugar for an explicit annotation.
*
* [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html#r-associated.fn.method.self-pat-shorthands
*/
class ShorthandSelfParameterMention extends TypeMention instanceof SelfParam {
private ImplOrTraitItemNode encl;
ShorthandSelfParameterMention() {
not super.hasTypeRepr() and
encl = getSelfParamEnclosingImplOrTrait(this) and
(
not encl instanceof Impl
or
// avoid generating a type mention if the type being implemented does not have a type mention
encl.(Impl).getSelfTy() instanceof TypeMention
)
}
private Type resolveSelfType(TypePath path) { result = resolveImplOrTraitType(encl, path) }
override Type resolveTypeAt(TypePath typePath) {
if super.isRef()
then
// `fn f(&self, ...)`
typePath.isEmpty() and
result = TRefType()
or
exists(TypePath suffix |
result = this.resolveSelfType(suffix) and
typePath = TypePath::cons(TRefTypeParameter(), suffix)
)
else
// `fn f(self, ...)`
result = this.resolveSelfType(typePath)
}
}
pragma[nomagic]
TypeMention getSelfParamTypeMention(SelfParam self) {
result = self.(ShorthandSelfParameterMention)
or
result = self.getTypeRepr()
}
class DynTraitTypeReprMention extends TypeMention instanceof DynTraitTypeRepr {
private DynTraitType dynType;

View File

@@ -0,0 +1,135 @@
/**
* Provides logic for checking argument types against constraints of
* [blanket implementations][1].
*
* [1]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
*/
private import rust
private import codeql.rust.internal.PathResolution
private import codeql.rust.internal.Type
private import codeql.rust.internal.TypeMention
private import codeql.rust.internal.TypeInference
/**
* Holds if `traitBound` is the first non-trivial trait bound of `tp`.
*/
pragma[nomagic]
private predicate hasFirstNonTrivialTraitBound(TypeParamItemNode tp, Trait traitBound) {
traitBound =
min(Trait trait, int i |
trait = tp.resolveBound(i) and
// Exclude traits that are known to not narrow things down very much.
not trait.getName().getText() =
[
"Sized", "Clone",
// The auto traits
"Send", "Sync", "Unpin", "UnwindSafe", "RefUnwindSafe"
]
|
trait order by i
)
}
/**
* Holds if `i` is a blanket-like implementation, meaning either an actual
* blanket implementation, or an implementation for a type like `&` where
* we want to check against the trait bounds of the blanket type parameter.
*
* `blanketSelfPath` points to the type parameter `blanketTypeParam` inside the
* self type of `i` (`blanketSelfPath` is empty for actual blanket implementations).
*/
pragma[nomagic]
predicate isBlanketLike(ImplItemNode i, TypePath blanketSelfPath, TypeParam blanketTypeParam) {
blanketTypeParam = i.getBlanketImplementationTypeParam() and
blanketSelfPath.isEmpty()
or
exists(TypeMention tm, Type root, TypeParameter tp |
tm = i.(Impl).getSelfTy() and
complexSelfRoot(root, tp) and
tm.resolveType() = root and
tm.resolveTypeAt(blanketSelfPath) = TTypeParamTypeParameter(blanketTypeParam) and
blanketSelfPath = TypePath::singleton(tp) and
hasFirstNonTrivialTraitBound(blanketTypeParam, _)
)
}
signature module SatisfiesBlanketConstraintInputSig<HasTypeTreeSig ArgumentType> {
/**
* Holds if a call with argument type `at` may potentially target a function belonging
* to blanket implementation `impl` with type parameter `blanketTypeParam`.
*
* `blanketPath` points to the type `blanketTypeParam` inside the type of the parameter
* at the matching position.
*/
predicate hasBlanketCandidate(
ArgumentType at, ImplItemNode impl, TypePath blanketPath, TypeParam blanketTypeParam
);
}
module SatisfiesBlanketConstraint<
HasTypeTreeSig ArgumentType, SatisfiesBlanketConstraintInputSig<ArgumentType> Input>
{
private predicate hasBlanketCandidate(
ArgumentType at, ImplItemNode impl, TypePath blanketPath, TypeParam blanketTypeParam
) {
Input::hasBlanketCandidate(at, impl, blanketPath, blanketTypeParam) and
exists(at.getTypeAt(blanketPath))
}
private newtype TArgumentTypeAndBlanketOffset =
MkArgumentTypeAndBlanketOffset(ArgumentType at, TypePath blanketPath) {
hasBlanketCandidate(at, _, blanketPath, _)
}
private class ArgumentTypeAndBlanketOffset extends MkArgumentTypeAndBlanketOffset {
ArgumentType at;
TypePath blanketPath;
ArgumentTypeAndBlanketOffset() { this = MkArgumentTypeAndBlanketOffset(at, blanketPath) }
Location getLocation() { result = at.getLocation() }
Type getTypeAt(TypePath path) { result = at.getTypeAt(blanketPath.appendInverse(path)) }
string toString() { result = at.toString() + " [blanket at " + blanketPath.toString() + "]" }
}
private module SatisfiesBlanketConstraintInput implements
SatisfiesConstraintInputSig<ArgumentTypeAndBlanketOffset>
{
pragma[nomagic]
additional predicate relevantConstraint(
ArgumentTypeAndBlanketOffset ato, ImplItemNode impl, Trait traitBound
) {
exists(ArgumentType at, TypePath blanketPath, TypeParam blanketTypeParam |
ato = MkArgumentTypeAndBlanketOffset(at, blanketPath) and
hasBlanketCandidate(at, impl, blanketPath, blanketTypeParam) and
hasFirstNonTrivialTraitBound(blanketTypeParam, traitBound)
)
}
pragma[nomagic]
predicate relevantConstraint(ArgumentTypeAndBlanketOffset ato, Type constraint) {
relevantConstraint(ato, _, constraint.(TraitType).getTrait())
}
predicate useUniversalConditions() { none() }
}
private module SatisfiesBlanketConstraint =
SatisfiesConstraint<ArgumentTypeAndBlanketOffset, SatisfiesBlanketConstraintInput>;
/**
* Holds if the argument type `at` satisfies the first non-trivial blanket
* constraint of `impl`.
*/
pragma[nomagic]
predicate satisfiesBlanketConstraint(ArgumentType at, ImplItemNode impl) {
exists(ArgumentTypeAndBlanketOffset ato, Trait traitBound |
ato = MkArgumentTypeAndBlanketOffset(at, _) and
SatisfiesBlanketConstraintInput::relevantConstraint(ato, impl, traitBound) and
SatisfiesBlanketConstraint::satisfiesConstraintType(ato, TTrait(traitBound), _, _)
)
}
}

View File

@@ -0,0 +1,127 @@
/**
* Provides logic for identifying functions that are overloaded based on their
* non-`self` parameter types. While Rust does not allow for overloading inside a single
* `impl` block, it is still possible for a trait to have multiple implementations
* that differ only in the types of non-`self` parameters.
*/
private import rust
private import codeql.rust.internal.PathResolution
private import codeql.rust.internal.Type
private import codeql.rust.internal.TypeMention
private import codeql.rust.internal.TypeInference
private import FunctionType
pragma[nomagic]
private Type resolveNonTypeParameterTypeAt(TypeMention tm, TypePath path) {
result = tm.resolveTypeAt(path) and
not result instanceof TypeParameter
}
bindingset[t1, t2]
private predicate typeMentionEqual(TypeMention t1, TypeMention t2) {
forex(TypePath path, Type type | resolveNonTypeParameterTypeAt(t1, path) = type |
resolveNonTypeParameterTypeAt(t2, path) = type
)
}
pragma[nomagic]
private predicate implSiblingCandidate(
Impl impl, TraitItemNode trait, Type rootType, TypeMention selfTy
) {
trait = impl.(ImplItemNode).resolveTraitTy() and
selfTy = impl.getSelfTy() and
rootType = selfTy.resolveType()
}
/**
* Holds if `impl1` and `impl2` are a sibling implementations of `trait`. We
* consider implementations to be siblings if they implement the same trait for
* the same type. In that case `Self` is the same type in both implementations,
* and method calls to the implementations cannot be resolved unambiguously
* based only on the receiver type.
*/
pragma[inline]
private predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
exists(Type rootType, TypeMention selfTy1, TypeMention selfTy2 |
impl1 != impl2 and
implSiblingCandidate(impl1, trait, rootType, selfTy1) and
implSiblingCandidate(impl2, trait, rootType, selfTy2) and
// In principle the second conjunct below should be superflous, but we still
// have ill-formed type mentions for types that we don't understand. For
// those checking both directions restricts further. Note also that we check
// syntactic equality, whereas equality up to renaming would be more
// correct.
typeMentionEqual(selfTy1, selfTy2) and
typeMentionEqual(selfTy2, selfTy1)
)
}
/**
* Holds if `impl` is an implementation of `trait` and if another implementation
* exists for the same type.
*/
pragma[nomagic]
private predicate implHasSibling(Impl impl, Trait trait) { implSiblings(trait, impl, _) }
/**
* Holds if type parameter `tp` of `trait` occurs in the function `f` with the name
* `functionName` at position `pos` and path `path`.
*
* Note that `pos` can also be the special `return` position, which is sometimes
* needed to disambiguate associated function calls like `Default::default()`
* (in this case, `tp` is the special `Self` type parameter).
*/
bindingset[trait]
pragma[inline_late]
predicate traitTypeParameterOccurrence(
TraitItemNode trait, Function f, string functionName, FunctionPosition pos, TypePath path,
TypeParameter tp
) {
f = trait.getASuccessor(functionName) and
assocFunctionTypeAt(f, trait, pos, path, tp) and
tp = trait.(TraitTypeAbstraction).getATypeParameter()
}
/**
* Holds if resolving the function `f` in `impl` with the name `functionName`
* requires inspecting the type of applied _arguments_ at position `pos` in
* order to determine whether it is the correct resolution.
*/
pragma[nomagic]
predicate functionResolutionDependsOnArgument(
ImplItemNode impl, Function f, FunctionPosition pos, TypePath path, Type type
) {
/*
* As seen in the example below, when an implementation has a sibling for a
* trait we find occurrences of a type parameter of the trait in a function
* signature in the trait. We then find the type given in the implementation
* at the same position, which is a position that might disambiguate the
* function from its siblings.
*
* ```rust
* trait MyTrait<T> {
* fn method(&self, value: Foo<T>) -> Self;
* // ^^^^^^^^^^^^^ `pos` = 0
* // ^ `path` = "T"
* }
* impl MyAdd<i64> for i64 {
* fn method(&self, value: Foo<i64>) -> Self { ... }
* // ^^^ `type` = i64
* }
* ```
*
* Note that we only check the root type symbol at the position. If the type
* at that position is a type constructor (for instance `Vec<..>`) then
* inspecting the entire type tree could be necessary to disambiguate the
* method. In that case we will still resolve several methods.
*/
exists(TraitItemNode trait, string functionName |
implHasSibling(impl, trait) and
traitTypeParameterOccurrence(trait, _, functionName, pos, path, _) and
assocFunctionTypeAt(f, impl, pos, path, type) and
f = impl.getASuccessor(functionName) and
pos.isPosition()
)
}

View File

@@ -0,0 +1,420 @@
private import rust
private import codeql.rust.internal.TypeInference
private import codeql.rust.internal.PathResolution
private import codeql.rust.internal.Type
private import codeql.rust.internal.TypeMention
private import codeql.rust.elements.Call
private newtype TFunctionPosition =
TArgumentFunctionPosition(ArgumentPosition pos) or
TReturnFunctionPosition()
/**
* A position of a type related to a function.
*
* Either `self`, `return`, or a positional parameter index.
*/
class FunctionPosition extends TFunctionPosition {
predicate isSelf() { this.asArgumentPosition().isSelf() }
int asPosition() { result = this.asArgumentPosition().asPosition() }
predicate isPosition() { exists(this.asPosition()) }
ArgumentPosition asArgumentPosition() { this = TArgumentFunctionPosition(result) }
predicate isReturn() { this = TReturnFunctionPosition() }
/** Gets the corresponding position when `f` is invoked via a function call. */
bindingset[f]
FunctionPosition getFunctionCallAdjusted(Function f) {
this.isReturn() and
result = this
or
if f.hasSelfParam()
then
this.isSelf() and result.asPosition() = 0
or
result.asPosition() = this.asPosition() + 1
else result = this
}
TypeMention getTypeMention(Function f) {
this.isSelf() and
result = getSelfParamTypeMention(f.getSelfParam())
or
result = f.getParam(this.asPosition()).getTypeRepr()
or
this.isReturn() and
result = f.getRetType().getTypeRepr()
}
string toString() {
result = this.asArgumentPosition().toString()
or
this.isReturn() and
result = "(return)"
}
}
/**
* A helper module for implementing `Matching(WithEnvironment)InputSig` with
* `DeclarationPosition = AccessPosition = FunctionPosition`.
*/
module FunctionPositionMatchingInput {
class DeclarationPosition = FunctionPosition;
class AccessPosition = DeclarationPosition;
predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) {
apos = dpos
}
}
private newtype TAssocFunctionType =
MkAssocFunctionType(Function f, FunctionPosition pos, ImplOrTraitItemNode i) {
f = i.getAnAssocItem() and
exists(pos.getTypeMention(f))
} or
MkInheritedAssocFunctionType(
Function f, FunctionPosition pos, TypeMention parentMention, TraitItemNode parent,
ImplOrTraitItemNode i
) {
exists(AssocFunctionType inherited |
inherited.appliesTo(f, pos, parent) and
f = i.getASuccessor(_)
|
parent = i.(ImplItemNode).resolveTraitTy() and
parentMention = i.(ImplItemNode).getTraitPath()
or
parent = i.(TraitItemNode).resolveBound(parentMention)
)
}
/**
* The type of an associated function at a given position, when viewed as a member
* of a given trait or `impl` block.
*
* Example:
*
* ```rust
* trait T1 {
* fn m1(self); // self1
*
* fn m2(self) { ... } // self2
* }
*
* trait T2 : T1 {
* fn m3(self); // self3
* }
*
* impl T2 for X {
* fn m1(self) { ... } // self4
*
* fn m3(self) { ... } // self5
* }
* ```
*
* param | `impl` or trait | type
* ------- | --------------- | ----
* `self1` | `trait T1` | `T1`
* `self1` | `trait T2` | `T2`
* `self2` | `trait T1` | `T1`
* `self2` | `trait T2` | `T2`
* `self2` | `impl T2 for X` | `X`
* `self3` | `trait T2` | `T2`
* `self4` | `impl T2 for X` | `X`
* `self5` | `impl T2 for X` | `X`
*/
class AssocFunctionType extends TAssocFunctionType {
private predicate isFunctionType(Function f, FunctionPosition pos, ImplOrTraitItemNode i) {
this = MkAssocFunctionType(f, pos, i)
}
private predicate isInheritedFunctionType(
Function f, FunctionPosition pos, TypeMention parentMention, TraitItemNode parent,
ImplOrTraitItemNode i
) {
this = MkInheritedAssocFunctionType(f, pos, parentMention, parent, i)
}
/**
* Holds if this function type applies to the function `f` at position `pos`,
* when viewed as a member of the `impl` or trait item `i`.
*/
predicate appliesTo(Function f, FunctionPosition pos, ImplOrTraitItemNode i) {
this.isFunctionType(f, pos, i)
or
this.isInheritedFunctionType(f, pos, _, _, i)
}
/** Gets the type at the given path. */
pragma[nomagic]
Type getDeclaredTypeAt(TypePath path) {
exists(Function f, FunctionPosition pos |
this.isFunctionType(f, pos, _) and
result = pos.getTypeMention(f).resolveTypeAt(path)
)
or
exists(
Function f, FunctionPosition pos, TypeMention parentMention, TraitItemNode parent,
AssocFunctionType parentType, ImplOrTraitItemNode i
|
this.isInheritedFunctionType(f, pos, parentMention, parent, i) and
parentType.appliesTo(f, pos, parent)
|
result = parentType.getDeclaredTypeAt(path) and
not result instanceof TypeParameter
or
exists(TypePath prefix, TypePath suffix | path = prefix.append(suffix) |
parentType.hasSelfTypeParameterAt(prefix) and
result = resolveImplOrTraitType(i, suffix)
or
exists(TypeParameter tp |
tp = parentType.getTypeParameterAt(prefix) and
result = parentMention.resolveTypeAt(TypePath::singleton(tp).appendInverse(suffix))
)
)
)
}
pragma[nomagic]
private TypeParameter getTypeParameterAt(TypePath path) { result = this.getDeclaredTypeAt(path) }
pragma[nomagic]
private predicate hasSelfTypeParameterAt(TypePath path) {
this.getTypeParameterAt(path) = TSelfTypeParameter(_)
}
/**
* Gets the type at the given path.
*
* For functions belonging to a trait, we use the type of the trait itself instead
* of the implicit `Self` type parameter, as otherwise any type will match.
*
* Calls should use `substituteLookupTraits` to map receiver types to the relevant
* traits when matching.
*/
Type getTypeAt(TypePath path) {
exists(Type t | t = this.getDeclaredTypeAt(path) |
not t instanceof SelfTypeParameter and
result = t
or
result = TTrait(t.(SelfTypeParameter).getTrait())
)
}
private TypeMention getTypeMention() {
exists(Function f, FunctionPosition pos |
this.appliesTo(f, pos, _) and
result = pos.getTypeMention(f)
)
}
string toString() { result = this.getTypeMention().toString() }
Location getLocation() { result = this.getTypeMention().getLocation() }
}
/**
* Holds if the type of the function `f` at position `pos` and path `path` inside
* `i` is `type`.
*/
pragma[nomagic]
predicate assocFunctionTypeAt(
Function f, ImplOrTraitItemNode i, FunctionPosition pos, TypePath path, Type type
) {
exists(AssocFunctionType aft |
aft.appliesTo(f, pos, i) and
type = aft.getDeclaredTypeAt(path)
)
}
private Trait getALookupTrait(Type t) {
result = t.(TypeParamTypeParameter).getTypeParam().(TypeParamItemNode).resolveABound()
or
result = t.(SelfTypeParameter).getTrait()
or
result = t.(ImplTraitType).getImplTraitTypeRepr().(ImplTraitTypeReprItemNode).resolveABound()
or
result = t.(DynTraitType).getTrait()
}
/**
* Gets the type obtained by substituting in relevant traits in which to do function
* lookup, or `t` itself when no such trait exist.
*/
bindingset[t]
Type substituteLookupTraits(Type t) {
not exists(getALookupTrait(t)) and
result = t
or
result = TTrait(getALookupTrait(t))
}
/**
* A wrapper around `IsInstantiationOf` which ensures to substitute in lookup
* traits when checking whether argument types are instantiations of function
* types.
*/
module ArgIsInstantiationOf<
HasTypeTreeSig Arg, IsInstantiationOfInputSig<Arg, AssocFunctionType> Input>
{
final private class ArgFinal = Arg;
private class ArgSubst extends ArgFinal {
Type getTypeAt(TypePath path) { result = substituteLookupTraits(super.getTypeAt(path)) }
}
private module IsInstantiationOfInput implements
IsInstantiationOfInputSig<ArgSubst, AssocFunctionType>
{
pragma[nomagic]
predicate potentialInstantiationOf(
ArgSubst arg, TypeAbstraction abs, AssocFunctionType constraint
) {
Input::potentialInstantiationOf(arg, abs, constraint)
}
predicate relevantConstraint(AssocFunctionType constraint) {
Input::relevantConstraint(constraint)
}
}
private module ArgSubstIsInstantiationOf =
IsInstantiationOf<ArgSubst, AssocFunctionType, IsInstantiationOfInput>;
predicate argIsInstantiationOf(Arg arg, ImplOrTraitItemNode i, AssocFunctionType constraint) {
ArgSubstIsInstantiationOf::isInstantiationOf(arg, i, constraint)
}
predicate argIsNotInstantiationOf(Arg arg, ImplOrTraitItemNode i, AssocFunctionType constraint) {
ArgSubstIsInstantiationOf::isNotInstantiationOf(arg, i, constraint)
}
}
/**
* Provides the input for `ArgsAreInstantiationsOf`.
*/
signature module ArgsAreInstantiationsOfInputSig {
/**
* Holds if types need to be matched against the type `t` at position `pos` of
* `f` inside `i`.
*/
predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t);
/** A call whose argument types are to be checked. */
class Call {
string toString();
Location getLocation();
Type getArgType(FunctionPosition pos, TypePath path);
predicate hasTargetCand(ImplOrTraitItemNode i, Function f);
}
}
/**
* Provides logic for checking that a set of arguments have types that are
* instantiations of the types at the corresponding positions in a function
* type.
*/
module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
pragma[nomagic]
private predicate toCheckRanked(ImplOrTraitItemNode i, Function f, FunctionPosition pos, int rnk) {
Input::toCheck(i, f, pos, _) and
pos =
rank[rnk + 1](FunctionPosition pos0, int j |
Input::toCheck(i, f, pos0, _) and
(
j = pos0.asPosition()
or
pos0.isSelf() and j = -1
or
pos0.isReturn() and j = -2
)
|
pos0 order by j
)
}
private newtype TCallAndPos =
MkCallAndPos(Input::Call call, FunctionPosition pos) { exists(call.getArgType(pos, _)) }
/** A call tagged with a position. */
private class CallAndPos extends MkCallAndPos {
Input::Call call;
FunctionPosition pos;
CallAndPos() { this = MkCallAndPos(call, pos) }
Input::Call getCall() { result = call }
FunctionPosition getPos() { result = pos }
Location getLocation() { result = call.getLocation() }
Type getTypeAt(TypePath path) { result = call.getArgType(pos, path) }
string toString() { result = call.toString() + " [arg " + pos + "]" }
}
private module ArgIsInstantiationOfInput implements
IsInstantiationOfInputSig<CallAndPos, AssocFunctionType>
{
pragma[nomagic]
private predicate potentialInstantiationOf0(
CallAndPos cp, Input::Call call, FunctionPosition pos, int rnk, Function f,
TypeAbstraction abs, AssocFunctionType constraint
) {
cp = MkCallAndPos(call, pos) and
call.hasTargetCand(abs, f) and
toCheckRanked(abs, f, pos, rnk) and
Input::toCheck(abs, f, pos, constraint)
}
pragma[nomagic]
predicate potentialInstantiationOf(
CallAndPos cp, TypeAbstraction abs, AssocFunctionType constraint
) {
exists(Input::Call call, int rnk, Function f |
potentialInstantiationOf0(cp, call, _, rnk, f, abs, constraint)
|
rnk = 0
or
argsAreInstantiationsOfFromIndex(call, abs, f, rnk - 1)
)
}
predicate relevantConstraint(AssocFunctionType constraint) {
Input::toCheck(_, _, _, constraint)
}
}
private module ArgIsInstantiationOfFromIndex =
ArgIsInstantiationOf<CallAndPos, ArgIsInstantiationOfInput>;
pragma[nomagic]
private predicate argsAreInstantiationsOfFromIndex(
Input::Call call, ImplOrTraitItemNode i, Function f, int rnk
) {
exists(FunctionPosition pos |
ArgIsInstantiationOfFromIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and
call.hasTargetCand(i, f) and
toCheckRanked(i, f, pos, rnk)
)
}
/**
* Holds if all arguments of `call` have types that are instantiations of the
* types of the corresponding parameters of `f` inside `i`.
*/
pragma[nomagic]
predicate argsAreInstantiationsOf(Input::Call call, ImplOrTraitItemNode i, Function f) {
exists(int rnk |
argsAreInstantiationsOfFromIndex(call, i, f, rnk) and
rnk = max(int r | toCheckRanked(i, f, _, r))
)
}
}

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The "Low Rust analysis quality" query (`rust/diagnostic/database-quality`), used by the tool status page, has been extended with a measure of successful type inference.

View File

@@ -6,6 +6,7 @@
import rust
import codeql.util.ReportStats
import codeql.rust.internal.TypeInference as TypeInference
module CallTargetStats implements StatsSig {
int getNumberOfOk() { result = count(CallExprBase c | exists(c.getStaticTarget())) }
@@ -41,6 +42,20 @@ module MacroCallTargetStats implements StatsSig {
string getNotOkText() { result = "macro calls with missing call target" }
}
private predicate hasGoodType(Expr e) { exists(TypeInference::inferType(e, _)) }
module ExprTypeStats implements StatsSig {
int getNumberOfOk() { result = count(Expr e | e.fromSource() and hasGoodType(e)) }
int getNumberOfNotOk() { result = count(Expr e | e.fromSource() and not hasGoodType(e)) }
string getOkText() { result = "expressions with known type" }
string getNotOkText() { result = "expressions with unknown type" }
}
module CallTargetStatsReport = ReportStats<CallTargetStats>;
module MacroCallTargetStatsReport = ReportStats<MacroCallTargetStats>;
module ExprTypeStatsReport = ReportStats<ExprTypeStats>;

View File

@@ -13,6 +13,8 @@ private predicate diagnostic(string msg, float value, float threshold) {
CallTargetStatsReport::percentageOfOk(msg, value) and threshold = 50
or
MacroCallTargetStatsReport::percentageOfOk(msg, value) and threshold = 50
or
ExprTypeStatsReport::percentageOfOk(msg, value) and threshold = 20
}
private string getDbHealth() {

View File

@@ -54,7 +54,10 @@ where
CallTargetStatsReport::percentageOfOk(key, value) or
MacroCallTargetStatsReport::numberOfOk(key, value) or
MacroCallTargetStatsReport::numberOfNotOk(key, value) or
MacroCallTargetStatsReport::percentageOfOk(key, value)
MacroCallTargetStatsReport::percentageOfOk(key, value) or
ExprTypeStatsReport::numberOfOk(key, value) or
ExprTypeStatsReport::numberOfNotOk(key, value) or
ExprTypeStatsReport::percentageOfOk(key, value)
) and
/* Infinity */
value != 1.0 / 0.0 and

View File

@@ -0,0 +1,2 @@
extractionWarning
| bad_cargo/src/no_semantics.rs:1:1:1:1 | semantic analyzer unavailable (unable to load manifest) |

View File

@@ -1,6 +1,9 @@
| Cargo.toml:0:0:0:0 | Cargo.toml | fromSource: no |
| a_file.rs:0:0:0:0 | a_file.rs | fromSource: yes |
| another_file.rs:0:0:0:0 | another_file.rs | fromSource: yes |
| lib.rs:0:0:0:0 | lib.rs | fromSource: yes |
| nested.rs:0:0:0:0 | nested.rs | fromSource: yes |
| nested/file.rs:0:0:0:0 | nested/file.rs | fromSource: yes |
| Cargo.toml:0:0:0:0 | Cargo.toml | fromSource: no | hasSemantics: no | isSkippedByCompilation: no |
| a_file.rs:0:0:0:0 | a_file.rs | fromSource: yes | hasSemantics: yes | isSkippedByCompilation: no |
| another_file.rs:0:0:0:0 | another_file.rs | fromSource: yes | hasSemantics: yes | isSkippedByCompilation: no |
| bad_cargo/Cargo.toml:0:0:0:0 | bad_cargo/Cargo.toml | fromSource: no | hasSemantics: no | isSkippedByCompilation: no |
| bad_cargo/src/no_semantics.rs:0:0:0:0 | bad_cargo/src/no_semantics.rs | fromSource: yes | hasSemantics: no | isSkippedByCompilation: no |
| lib.rs:0:0:0:0 | lib.rs | fromSource: yes | hasSemantics: yes | isSkippedByCompilation: no |
| nested.rs:0:0:0:0 | nested.rs | fromSource: yes | hasSemantics: yes | isSkippedByCompilation: no |
| nested/file.rs:0:0:0:0 | nested/file.rs | fromSource: yes | hasSemantics: yes | isSkippedByCompilation: no |
| nested/not_compiled.rs:0:0:0:0 | nested/not_compiled.rs | fromSource: yes | hasSemantics: no | isSkippedByCompilation: yes |

View File

@@ -1,7 +1,15 @@
import rust
from File f, string fromSource
from File f, string fromSource, string hasSemantics, string isSkippedByCompilation
where
exists(f.getRelativePath()) and
if f.fromSource() then fromSource = "fromSource: yes" else fromSource = "fromSource: no"
select f, fromSource
(if f.fromSource() then fromSource = "fromSource: yes" else fromSource = "fromSource: no") and
(
if f.(ExtractedFile).hasSemantics()
then hasSemantics = "hasSemantics: yes"
else hasSemantics = "hasSemantics: no"
) and
if f.(ExtractedFile).isSkippedByCompilation()
then isSkippedByCompilation = "isSkippedByCompilation: yes"
else isSkippedByCompilation = "isSkippedByCompilation: no"
select f, fromSource, hasSemantics, isSkippedByCompilation

View File

@@ -0,0 +1 @@
!/Cargo.toml

View File

@@ -0,0 +1 @@
wrong

View File

@@ -1,2 +0,0 @@
multipleCallTargets
| main.rs:272:14:272:29 | ...::deref(...) |

View File

@@ -59,8 +59,6 @@
| main.rs:212:13:212:34 | ...::new(...) | main.rs:205:5:208:5 | fn new |
| main.rs:212:24:212:33 | source(...) | main.rs:1:1:3:1 | fn source |
| main.rs:214:5:214:11 | sink(...) | main.rs:5:1:7:1 | fn sink |
| main.rs:228:10:228:14 | * ... | main.rs:235:5:237:5 | fn deref |
| main.rs:236:11:236:15 | * ... | main.rs:235:5:237:5 | fn deref |
| main.rs:242:28:242:36 | source(...) | main.rs:1:1:3:1 | fn source |
| main.rs:244:13:244:17 | ... + ... | main.rs:220:5:223:5 | fn add |
| main.rs:245:5:245:17 | sink(...) | main.rs:5:1:7:1 | fn sink |

View File

@@ -1,2 +0,0 @@
multipleCallTargets
| main.rs:483:18:483:24 | n.len() |

View File

@@ -1034,24 +1034,29 @@ readStep
| main.rs:482:44:482:55 | this | main.rs:479:9:479:20 | captured default_name | main.rs:482:44:482:55 | default_name |
| main.rs:483:18:483:18 | [post] receiver for n | file://:0:0:0:0 | &ref | main.rs:483:18:483:18 | [post] n |
| main.rs:506:13:506:13 | [post] receiver for a | file://:0:0:0:0 | &ref | main.rs:506:13:506:13 | [post] a |
| main.rs:507:13:507:13 | [post] receiver for b | file://:0:0:0:0 | &ref | main.rs:507:13:507:13 | [post] b |
| main.rs:508:18:508:18 | [post] receiver for b | file://:0:0:0:0 | &ref | main.rs:508:18:508:18 | [post] b |
| main.rs:519:10:519:11 | vs | file://:0:0:0:0 | element | main.rs:519:10:519:14 | vs[0] |
| main.rs:520:11:520:35 | ... .unwrap() | file://:0:0:0:0 | &ref | main.rs:520:10:520:35 | * ... |
| main.rs:520:11:520:35 | [post] receiver for ... .unwrap() | file://:0:0:0:0 | &ref | main.rs:520:11:520:35 | [post] ... .unwrap() |
| main.rs:521:11:521:35 | ... .unwrap() | file://:0:0:0:0 | &ref | main.rs:521:10:521:35 | * ... |
| main.rs:521:11:521:35 | [post] receiver for ... .unwrap() | file://:0:0:0:0 | &ref | main.rs:521:11:521:35 | [post] ... .unwrap() |
| main.rs:523:14:523:15 | vs | file://:0:0:0:0 | element | main.rs:523:9:523:9 | v |
| main.rs:526:9:526:10 | &... | file://:0:0:0:0 | &ref | main.rs:526:10:526:10 | v |
| main.rs:526:15:526:23 | vs.iter() | file://:0:0:0:0 | element | main.rs:526:9:526:10 | &... |
| main.rs:531:9:531:10 | &... | file://:0:0:0:0 | &ref | main.rs:531:10:531:10 | v |
| main.rs:531:15:531:17 | vs2 | file://:0:0:0:0 | element | main.rs:531:9:531:10 | &... |
| main.rs:535:29:535:29 | [post] receiver for x | file://:0:0:0:0 | &ref | main.rs:535:29:535:29 | [post] x |
| main.rs:535:29:535:29 | x | file://:0:0:0:0 | &ref | main.rs:535:28:535:29 | * ... |
| main.rs:536:34:536:34 | [post] receiver for x | file://:0:0:0:0 | &ref | main.rs:536:34:536:34 | [post] x |
| main.rs:536:34:536:34 | x | file://:0:0:0:0 | &ref | main.rs:536:33:536:34 | * ... |
| main.rs:538:14:538:27 | vs.into_iter() | file://:0:0:0:0 | element | main.rs:538:9:538:9 | v |
| main.rs:544:10:544:15 | vs_mut | file://:0:0:0:0 | element | main.rs:544:10:544:18 | vs_mut[0] |
| main.rs:545:11:545:39 | ... .unwrap() | file://:0:0:0:0 | &ref | main.rs:545:10:545:39 | * ... |
| main.rs:545:11:545:39 | [post] receiver for ... .unwrap() | file://:0:0:0:0 | &ref | main.rs:545:11:545:39 | [post] ... .unwrap() |
| main.rs:546:11:546:39 | ... .unwrap() | file://:0:0:0:0 | &ref | main.rs:546:10:546:39 | * ... |
| main.rs:546:11:546:39 | [post] receiver for ... .unwrap() | file://:0:0:0:0 | &ref | main.rs:546:11:546:39 | [post] ... .unwrap() |
| main.rs:548:9:548:14 | &mut ... | file://:0:0:0:0 | &ref | main.rs:548:14:548:14 | v |
| main.rs:548:19:548:35 | vs_mut.iter_mut() | file://:0:0:0:0 | element | main.rs:548:9:548:14 | &mut ... |
| main.rs:562:11:562:15 | [post] receiver for c_ref | file://:0:0:0:0 | &ref | main.rs:562:11:562:15 | [post] c_ref |
| main.rs:562:11:562:15 | c_ref | file://:0:0:0:0 | &ref | main.rs:562:10:562:15 | * ... |
storeStep
| main.rs:116:11:116:11 | i | file://:0:0:0:0 | &ref | main.rs:116:11:116:11 | receiver for i |
@@ -1138,16 +1143,21 @@ storeStep
| main.rs:482:44:482:55 | default_name | file://:0:0:0:0 | &ref | main.rs:482:44:482:55 | receiver for default_name |
| main.rs:483:18:483:18 | n | file://:0:0:0:0 | &ref | main.rs:483:18:483:18 | receiver for n |
| main.rs:506:13:506:13 | a | file://:0:0:0:0 | &ref | main.rs:506:13:506:13 | receiver for a |
| main.rs:507:13:507:13 | b | file://:0:0:0:0 | &ref | main.rs:507:13:507:13 | receiver for b |
| main.rs:508:18:508:18 | b | file://:0:0:0:0 | &ref | main.rs:508:18:508:18 | receiver for b |
| main.rs:517:15:517:24 | source(...) | file://:0:0:0:0 | element | main.rs:517:14:517:34 | [...] |
| main.rs:517:27:517:27 | 2 | file://:0:0:0:0 | element | main.rs:517:14:517:34 | [...] |
| main.rs:517:30:517:30 | 3 | file://:0:0:0:0 | element | main.rs:517:14:517:34 | [...] |
| main.rs:517:33:517:33 | 4 | file://:0:0:0:0 | element | main.rs:517:14:517:34 | [...] |
| main.rs:520:11:520:35 | ... .unwrap() | file://:0:0:0:0 | &ref | main.rs:520:11:520:35 | receiver for ... .unwrap() |
| main.rs:521:11:521:35 | ... .unwrap() | file://:0:0:0:0 | &ref | main.rs:521:11:521:35 | receiver for ... .unwrap() |
| main.rs:535:29:535:29 | x | file://:0:0:0:0 | &ref | main.rs:535:29:535:29 | receiver for x |
| main.rs:536:34:536:34 | x | file://:0:0:0:0 | &ref | main.rs:536:34:536:34 | receiver for x |
| main.rs:542:23:542:32 | source(...) | file://:0:0:0:0 | element | main.rs:542:22:542:42 | [...] |
| main.rs:542:35:542:35 | 2 | file://:0:0:0:0 | element | main.rs:542:22:542:42 | [...] |
| main.rs:542:38:542:38 | 3 | file://:0:0:0:0 | element | main.rs:542:22:542:42 | [...] |
| main.rs:542:41:542:41 | 4 | file://:0:0:0:0 | element | main.rs:542:22:542:42 | [...] |
| main.rs:545:11:545:39 | ... .unwrap() | file://:0:0:0:0 | &ref | main.rs:545:11:545:39 | receiver for ... .unwrap() |
| main.rs:546:11:546:39 | ... .unwrap() | file://:0:0:0:0 | &ref | main.rs:546:11:546:39 | receiver for ... .unwrap() |
| main.rs:557:18:557:18 | c | file://:0:0:0:0 | &ref | main.rs:557:17:557:18 | &c |
| main.rs:560:15:560:15 | b | file://:0:0:0:0 | &ref | main.rs:560:14:560:15 | &b |
| main.rs:562:11:562:15 | c_ref | file://:0:0:0:0 | &ref | main.rs:562:11:562:15 | receiver for c_ref |
| main.rs:583:27:583:27 | 0 | {EXTERNAL LOCATION} | Some | main.rs:583:22:583:28 | Some(...) |

View File

@@ -1,3 +1,2 @@
multipleCallTargets
| main.rs:52:14:52:29 | ...::from(...) |
| main.rs:64:16:64:25 | s.as_str() |

View File

@@ -6,9 +6,8 @@ models
| 5 | Summary: <alloc::string::String as core::convert::From>::from; Argument[0].Reference; ReturnValue; value |
| 6 | Summary: <alloc::string::String as core::ops::arith::Add>::add; Argument[self]; ReturnValue; value |
| 7 | Summary: <alloc::string::String>::as_str; Argument[self]; ReturnValue; value |
| 8 | Summary: <core::str>::as_str; Argument[self]; ReturnValue; value |
| 9 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
| 10 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
| 8 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
| 9 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
edges
| main.rs:26:9:26:9 | s | main.rs:27:19:27:25 | s[...] | provenance | |
| main.rs:26:13:26:22 | source(...) | main.rs:26:9:26:9 | s | provenance | |
@@ -38,35 +37,33 @@ edges
| main.rs:58:14:58:27 | s1.to_string() | main.rs:58:9:58:10 | s2 | provenance | |
| main.rs:63:9:63:9 | s | main.rs:64:16:64:16 | s | provenance | |
| main.rs:63:9:63:9 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:7 |
| main.rs:63:9:63:9 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:8 |
| main.rs:63:13:63:22 | source(...) | main.rs:63:9:63:9 | s | provenance | |
| main.rs:64:16:64:16 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:7 |
| main.rs:64:16:64:16 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:8 |
| main.rs:68:9:68:9 | s | main.rs:70:34:70:61 | MacroExpr | provenance | |
| main.rs:68:9:68:9 | s | main.rs:73:34:73:59 | MacroExpr | provenance | |
| main.rs:68:13:68:22 | source(...) | main.rs:68:9:68:9 | s | provenance | |
| main.rs:70:9:70:18 | formatted1 | main.rs:71:10:71:19 | formatted1 | provenance | |
| main.rs:70:22:70:62 | ...::format(...) | main.rs:70:9:70:18 | formatted1 | provenance | |
| main.rs:70:34:70:61 | MacroExpr | main.rs:70:22:70:62 | ...::format(...) | provenance | MaD:9 |
| main.rs:70:34:70:61 | MacroExpr | main.rs:70:22:70:62 | ...::format(...) | provenance | MaD:8 |
| main.rs:73:9:73:18 | formatted2 | main.rs:74:10:74:19 | formatted2 | provenance | |
| main.rs:73:22:73:60 | ...::format(...) | main.rs:73:9:73:18 | formatted2 | provenance | |
| main.rs:73:34:73:59 | MacroExpr | main.rs:73:22:73:60 | ...::format(...) | provenance | MaD:9 |
| main.rs:73:34:73:59 | MacroExpr | main.rs:73:22:73:60 | ...::format(...) | provenance | MaD:8 |
| main.rs:76:9:76:13 | width | main.rs:77:34:77:74 | MacroExpr | provenance | |
| main.rs:76:17:76:32 | source_usize(...) | main.rs:76:9:76:13 | width | provenance | |
| main.rs:77:9:77:18 | formatted3 | main.rs:78:10:78:19 | formatted3 | provenance | |
| main.rs:77:22:77:75 | ...::format(...) | main.rs:77:9:77:18 | formatted3 | provenance | |
| main.rs:77:34:77:74 | MacroExpr | main.rs:77:22:77:75 | ...::format(...) | provenance | MaD:9 |
| main.rs:77:34:77:74 | MacroExpr | main.rs:77:22:77:75 | ...::format(...) | provenance | MaD:8 |
| main.rs:82:9:82:10 | s1 | main.rs:86:18:86:25 | MacroExpr | provenance | |
| main.rs:82:9:82:10 | s1 | main.rs:87:18:87:32 | MacroExpr | provenance | |
| main.rs:82:14:82:23 | source(...) | main.rs:82:9:82:10 | s1 | provenance | |
| main.rs:86:18:86:25 | ...::format(...) | main.rs:86:18:86:25 | { ... } | provenance | |
| main.rs:86:18:86:25 | ...::must_use(...) | main.rs:86:10:86:26 | MacroExpr | provenance | |
| main.rs:86:18:86:25 | MacroExpr | main.rs:86:18:86:25 | ...::format(...) | provenance | MaD:9 |
| main.rs:86:18:86:25 | { ... } | main.rs:86:18:86:25 | ...::must_use(...) | provenance | MaD:10 |
| main.rs:86:18:86:25 | MacroExpr | main.rs:86:18:86:25 | ...::format(...) | provenance | MaD:8 |
| main.rs:86:18:86:25 | { ... } | main.rs:86:18:86:25 | ...::must_use(...) | provenance | MaD:9 |
| main.rs:87:18:87:32 | ...::format(...) | main.rs:87:18:87:32 | { ... } | provenance | |
| main.rs:87:18:87:32 | ...::must_use(...) | main.rs:87:10:87:33 | MacroExpr | provenance | |
| main.rs:87:18:87:32 | MacroExpr | main.rs:87:18:87:32 | ...::format(...) | provenance | MaD:9 |
| main.rs:87:18:87:32 | { ... } | main.rs:87:18:87:32 | ...::must_use(...) | provenance | MaD:10 |
| main.rs:87:18:87:32 | MacroExpr | main.rs:87:18:87:32 | ...::format(...) | provenance | MaD:8 |
| main.rs:87:18:87:32 | { ... } | main.rs:87:18:87:32 | ...::must_use(...) | provenance | MaD:9 |
nodes
| main.rs:26:9:26:9 | s | semmle.label | s |
| main.rs:26:13:26:22 | source(...) | semmle.label | source(...) |

View File

@@ -1,9 +0,0 @@
multipleCallTargets
| main.rs:22:18:22:31 | query.as_str() |
| main.rs:23:24:23:37 | query.as_str() |
| main.rs:25:18:25:31 | query.as_str() |
| main.rs:28:16:28:29 | query.as_str() |
| main.rs:29:20:29:33 | query.as_str() |
| main.rs:30:20:30:33 | query.as_str() |
| main.rs:32:20:32:33 | query.as_str() |
| main.rs:33:22:33:35 | query.as_str() |

View File

@@ -1,2 +1,6 @@
multipleCallTargets
| main.rs:125:9:125:11 | f(...) |
| main.rs:365:9:367:16 | ...::f(...) |
| main.rs:368:9:370:16 | ...::f(...) |
| main.rs:447:9:451:16 | ...::f(...) |
| main.rs:452:9:456:16 | ...::f(...) |

View File

@@ -1,29 +0,0 @@
multipleCallTargets
| test.rs:56:7:56:26 | ... .as_str() |
| test.rs:57:7:57:21 | ... .as_str() |
| test.rs:73:7:73:26 | ... .as_str() |
| test.rs:74:7:74:36 | ... .as_str() |
| test.rs:75:7:75:34 | ... .as_str() |
| test.rs:76:7:76:27 | ... .as_str() |
| test.rs:262:7:262:36 | ... .as_str() |
| test.rs:264:7:264:33 | ... .as_str() |
| test.rs:265:7:265:36 | ... .as_str() |
| test.rs:266:7:266:26 | ... .as_str() |
| test.rs:270:7:270:28 | ... .as_str() |
| test.rs:271:7:271:37 | ... .as_str() |
| test.rs:272:7:272:36 | ... .as_str() |
| test.rs:275:7:275:32 | ... .as_str() |
| test.rs:285:7:285:34 | ... .as_str() |
| test.rs:288:7:288:36 | ... .as_str() |
| test.rs:292:7:292:39 | ... .as_str() |
| test.rs:299:7:299:53 | ... .as_str() |
| test.rs:300:7:300:45 | ... .as_str() |
| test.rs:302:7:302:39 | ... .as_str() |
| test.rs:303:7:303:34 | ... .as_str() |
| test.rs:304:7:304:42 | ... .as_str() |
| test.rs:306:7:306:48 | ... .as_str() |
| test.rs:307:7:307:35 | ... .as_str() |
| test.rs:308:7:308:35 | ... .as_str() |
| test.rs:317:8:317:19 | num.as_str() |
| test.rs:328:8:328:19 | num.as_str() |
| test.rs:347:7:347:39 | ... .as_str() |

View File

@@ -1,8 +1,13 @@
multipleCallTargets
| dereference.rs:61:15:61:24 | e1.deref() |
| main.rs:2357:13:2357:31 | ...::from(...) |
| main.rs:2358:13:2358:31 | ...::from(...) |
| main.rs:2359:13:2359:31 | ...::from(...) |
| main.rs:2365:13:2365:31 | ...::from(...) |
| main.rs:2366:13:2366:31 | ...::from(...) |
| main.rs:2367:13:2367:31 | ...::from(...) |
| dereference.rs:69:15:69:24 | e1.deref() |
| dereference.rs:182:17:182:26 | ... .foo() |
| dereference.rs:183:17:183:23 | S.foo() |
| dereference.rs:184:17:184:30 | ... .foo() |
| dereference.rs:186:17:186:25 | S.bar(...) |
| dereference.rs:187:17:187:29 | S.bar(...) |
| main.rs:2437:13:2437:31 | ...::from(...) |
| main.rs:2438:13:2438:31 | ...::from(...) |
| main.rs:2439:13:2439:31 | ...::from(...) |
| main.rs:2445:13:2445:31 | ...::from(...) |
| main.rs:2446:13:2446:31 | ...::from(...) |
| main.rs:2447:13:2447:31 | ...::from(...) |

View File

@@ -1,9 +1,22 @@
// Tests for method resolution targeting blanket trait implementations
mod basic_blanket_impl {
use std::ops::Deref;
#[derive(Debug, Copy, Clone)]
struct S1;
#[derive(Debug, Copy, Clone)]
struct S2;
impl Deref for S2 {
type Target = S1;
fn deref(&self) -> &Self::Target {
&S1
}
}
trait Clone1 {
fn clone1(&self) -> Self;
}
@@ -21,7 +34,7 @@ mod basic_blanket_impl {
}
}
// Blanket implementation for all types that implement Display and Clone
// Blanket implementation for all types that implement Clone1
impl<T: Clone1> Duplicatable for T {
// Clone1duplicate
fn duplicate(&self) -> Self {
@@ -30,10 +43,58 @@ mod basic_blanket_impl {
}
pub fn test_basic_blanket() {
let x = S1.clone1(); // $ target=S1::clone1
println!("{x:?}");
let y = S1.duplicate(); // $ target=Clone1duplicate
println!("{y:?}");
let x1 = S1.clone1(); // $ target=S1::clone1
println!("{x1:?}");
let x2 = (&S1).clone1(); // $ target=S1::clone1
println!("{x2:?}");
let x3 = S1.duplicate(); // $ target=Clone1duplicate
println!("{x3:?}");
let x4 = (&S1).duplicate(); // $ target=Clone1duplicate
println!("{x4:?}");
let x5 = S1::duplicate(&S1); // $ target=Clone1duplicate
println!("{x5:?}");
let x6 = S2.duplicate(); // $ MISSING: target=Clone1duplicate
println!("{x6:?}");
let x7 = (&S2).duplicate(); // $ MISSING: target=Clone1duplicate
println!("{x7:?}");
}
}
mod assoc_blanket_impl {
#[derive(Debug, Copy, Clone)]
struct S1;
trait Trait1 {
fn assoc_func1(x: i64, y: Self) -> Self;
}
trait Trait2 {
fn assoc_func2(x: i64, y: Self) -> Self;
}
impl Trait1 for S1 {
// S1::assoc_func1
fn assoc_func1(x: i64, y: Self) -> Self {
y
}
}
impl<T: Trait1> Trait2 for T {
// Blanket_assoc_func2
fn assoc_func2(x: i64, y: Self) -> Self {
T::assoc_func1(x, y) // $ target=assoc_func1
}
}
pub fn test_assoc_blanket() {
let x1 = S1::assoc_func1(1, S1); // $ target=S1::assoc_func1
println!("{x1:?}");
let x2 = Trait1::assoc_func1(1, S1); // $ target=S1::assoc_func1
println!("{x2:?}");
let x3 = S1::assoc_func2(1, S1); // $ target=Blanket_assoc_func2
println!("{x3:?}");
let x4 = Trait2::assoc_func2(1, S1); // $ target=Blanket_assoc_func2
println!("{x4:?}");
}
}
@@ -151,11 +212,11 @@ pub mod sql_exec {
let c = MySqlConnection {}; // $ certainType=c:MySqlConnection
c.execute1(); // $ target=execute1
MySqlConnection::execute1(&c); // $ MISSING: target=execute1
MySqlConnection::execute1(&c); // $ target=execute1
c.execute2("SELECT * FROM users"); // $ target=execute2
c.execute2::<&str>("SELECT * FROM users"); // $ target=execute2
MySqlConnection::execute2(&c, "SELECT * FROM users"); // $ MISSING: target=execute2
MySqlConnection::execute2::<&str>(&c, "SELECT * FROM users"); // $ MISSING: target=execute2
MySqlConnection::execute2(&c, "SELECT * FROM users"); // $ target=execute2
MySqlConnection::execute2::<&str>(&c, "SELECT * FROM users"); // $ target=execute2
}
}

View File

@@ -27,6 +27,14 @@ impl<T> Deref for MySmartPointer<T> {
}
}
struct S<T>(T);
impl<T> S<T> {
fn foo(&self) -> &T {
&self.0 // $ fieldof=S
}
}
fn explicit_monomorphic_dereference() {
// Dereference with method call
let a1 = MyIntPointer { value: 34i64 };
@@ -58,7 +66,7 @@ fn explicit_polymorphic_dereference() {
fn explicit_ref_dereference() {
// Explicit dereference with type parameter
let e1 = &'a';
let _f1 = e1.deref(); // $ target=deref MISSING: type=_f1:&T.char
let _f1 = e1.deref(); // $ target=deref type=_f1:&T.char
// Explicit dereference with type parameter
let e2 = &'a';
@@ -91,6 +99,9 @@ fn implicit_dereference() {
// Call method on implicitly dereferenced value
let x = MySmartPointer { value: 34i64 };
let _y = x.is_positive(); // $ MISSING: target=is_positive type=_y:bool
let z = MySmartPointer { value: S(0i64) };
let z_ = z.foo(); // $ MISSING: target=foo type=z_:&T.i64
}
mod implicit_deref_coercion_cycle {
@@ -128,6 +139,83 @@ mod implicit_deref_coercion_cycle {
}
}
mod ref_vs_mut_ref {
trait MyTrait1<T> {
fn foo(self) -> T;
}
struct S;
impl MyTrait1<S> for &S {
// MyTrait1::foo1
fn foo(self) -> S {
S
}
}
impl MyTrait1<i64> for &mut S {
// MyTrait1::foo2
fn foo(self) -> i64 {
42
}
}
trait MyTrait2<T1, T2> {
fn bar(self, arg: T1) -> T2;
}
impl MyTrait2<&S, S> for S {
// MyTrait2::bar1
fn bar(self, arg: &S) -> S {
S
}
}
impl MyTrait2<&mut S, i64> for S {
// MyTrait2::bar2
fn bar(self, arg: &mut S) -> i64 {
42
}
}
pub fn test() {
let x = (&S).foo(); // $ target=MyTrait1::foo1 type=x:S $ SPURIOUS: target=MyTrait1::foo2
let y = S.foo(); // $ target=MyTrait1::foo1 type=y:S $ SPURIOUS: target=MyTrait1::foo2
let z = (&mut S).foo(); // $ target=MyTrait1::foo2 type=z:i64 $ SPURIOUS: target=MyTrait1::foo1
let x = S.bar(&S); // $ target=MyTrait2::bar1 type=x:S $ SPURIOUS: target=MyTrait2::bar2
let y = S.bar(&mut S); // $ target=MyTrait2::bar2 type=y:i64 $ SPURIOUS: target=MyTrait2::bar1
}
}
// from https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.candidate-search
mod rust_reference_example {
struct Foo {}
trait Bar {
fn bar(&self);
}
impl Foo {
// bar1
fn bar(&mut self) {
println!("In struct impl!")
}
}
impl Bar for Foo {
// bar2
fn bar(&self) {
println!("In trait impl!")
}
}
pub fn main() {
let mut f = Foo {};
f.bar(); // $ SPURIOUS: target=bar1 $ MISSING: target=bar2
}
}
pub fn test() {
explicit_monomorphic_dereference(); // $ target=explicit_monomorphic_dereference
explicit_polymorphic_dereference(); // $ target=explicit_polymorphic_dereference
@@ -135,4 +223,6 @@ pub fn test() {
explicit_box_dereference(); // $ target=explicit_box_dereference
implicit_dereference(); // $ target=implicit_dereference
implicit_deref_coercion_cycle::test(); // $ target=test
ref_vs_mut_ref::test(); // $ target=test
rust_reference_example::main(); // $ target=main
}

View File

@@ -0,0 +1,93 @@
// The code in this file is not valid Rust code
// test that our type inference implementation does not run into an infinite loop.
mod type_loop {
struct S<T>(T);
trait T1<T>: T2<S<T>> {
fn foo(self) {}
}
trait T2<T>: T1<S<T>> {
fn bar(self) {
self.foo() // $ target=foo
}
}
}
mod op_blanket_impl {
use std::ops::Add;
#[derive(Debug, Copy, Clone)]
struct Num(i32);
trait AddAlias {
fn add_alias(self, other: Self) -> Self;
}
impl AddAlias for Num {
fn add_alias(self, other: Self) -> Self {
Num(self.0 + other.0) // $ fieldof=Num $ target=add
}
}
// this is not valid in Rust, because of coherence
impl<T: AddAlias> Add for T {
type Output = Self;
// BlanketAdd
fn add(self, other: Self) -> Self {
self.add_alias(other) // $ target=add_alias
}
}
pub fn test_op_blanket() {
let a = Num(5);
let b = Num(10);
let c = a + b; // $ target=BlanketAdd
println!("{c:?}");
}
}
mod impl_specialization {
#[derive(Debug, Copy, Clone)]
struct S1;
trait Clone1 {
fn clone1(&self) -> Self;
}
trait Duplicatable {
fn duplicate(&self) -> Self
where
Self: Sized;
}
impl Clone1 for S1 {
// S1::clone1
fn clone1(&self) -> Self {
*self // $ target=deref
}
}
impl Duplicatable for S1 {
// S1::duplicate
fn duplicate(&self) -> Self {
*self // $ target=deref
}
}
// Blanket implementation for all types that implement Clone1
impl<T: Clone1> Duplicatable for T {
// Clone1duplicate
fn duplicate(&self) -> Self {
self.clone1() // $ target=clone1
}
}
pub fn test_basic_blanket() {
// this call should target the specialized implementation of Duplicatable for S1,
// not the blanket implementation
let x = S1.duplicate(); // $ target=S1::duplicate
}
}

View File

@@ -1,14 +0,0 @@
// The code in this file is not valid Rust code, but it is used to test that
// our type inference implementation does not run into an infinite loop.
struct S<T>(T);
trait T1<T>: T2<S<T>> {
fn foo(self) {}
}
trait T2<T>: T1<S<T>> {
fn bar(self) {
self.foo() // $ target=foo
}
}

View File

@@ -538,16 +538,22 @@ mod impl_overlap {
pub fn f() {
let x = S1;
println!("{:?}", x.common_method()); // $ target=S1::common_method
println!("{:?}", S1::common_method(x)); // $ target=S1::common_method
println!("{:?}", x.common_method_2()); // $ target=S1::common_method_2
println!("{:?}", S1::common_method_2(x)); // $ target=S1::common_method_2
let y = S2(S1);
println!("{:?}", y.common_method()); // $ target=<S2<S1>_as_OverlappingTrait>::common_method
println!("{:?}", S2::<S1>::common_method(S2(S1))); // $ target=<S2<S1>_as_OverlappingTrait>::common_method
let z = S2(0);
println!("{:?}", z.common_method()); // $ target=S2<i32>::common_method
println!("{:?}", S2::common_method(S2(0))); // $ target=S2<i32>::common_method
println!("{:?}", S2::<i32>::common_method(S2(0))); // $ target=S2<i32>::common_method
let w = S3(S1);
println!("{:?}", w.m(x)); // $ target=S3<T>::m
println!("{:?}", S3::m(&w, x)); // $ target=S3<T>::m
}
}
@@ -647,14 +653,14 @@ mod type_parameter_bounds {
}
mod function_trait_bounds {
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
struct MyThing<T> {
a: T,
}
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
struct S1;
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
struct S2;
trait MyTrait<A> {
@@ -666,12 +672,35 @@ mod function_trait_bounds {
{
self.m1() // $ target=m1
}
fn assoc(x: Self) -> A;
}
// Type parameter with bound occurs in the root of a parameter type.
fn call_trait_m1<T1, T2: MyTrait<T1>>(x: T2) -> T1 {
x.m1() // $ target=m1 type=x.m1():T1
fn call_trait_m1<T1, T2: MyTrait<T1> + Copy>(x: T2) -> T1 {
x.m1(); // $ target=m1 type=x.m1():T1
x.m1() // $ target=m1
}
fn call_trait_m1_2<T1, T2: MyTrait<T1> + Copy>(x: T2) -> T1 {
let y = T2::m1(x); // $ target=m1
y; // $ type=y:T1
T2::m1(x) // $ target=m1
}
fn call_trait_m1_3<T1, T2: MyTrait<T1> + Copy>(x: T2) -> T1 {
let y = MyTrait::m1(x); // $ target=m1
y; // $ type=y:T1
MyTrait::m1(x) // $ target=m1
}
fn call_trait_assoc_1<T1, T2: MyTrait<T1> + Copy>(x: T2) -> T1 {
let y = T2::assoc(x); // $ target=assoc
y; // $ type=y:T1
T2::assoc(x) // $ target=assoc
}
fn call_trait_assoc_2<T1, T2: MyTrait<T1> + Copy>(x: T2) -> T1 {
let y = MyTrait::assoc(x); // $ target=assoc
y; // $ type=y:T1
MyTrait::assoc(x) // $ target=assoc
}
// Type parameter with bound occurs nested within another type.
@@ -679,11 +708,21 @@ mod function_trait_bounds {
fn call_trait_thing_m1<T1, T2: MyTrait<T1>>(x: MyThing<T2>) -> T1 {
x.a.m1() // $ fieldof=MyThing target=m1
}
fn call_trait_thing_m1_2<T1, T2: MyTrait<T1>>(x: MyThing<T2>) -> T1 {
T2::m1(x.a) // $ fieldof=MyThing target=m1
}
fn call_trait_thing_m1_3<T1, T2: MyTrait<T1>>(x: MyThing<T2>) -> T1 {
MyTrait::m1(x.a) // $ fieldof=MyThing target=m1
}
impl<T> MyTrait<T> for MyThing<T> {
fn m1(self) -> T {
self.a // $ fieldof=MyThing
}
fn assoc(x: Self) -> T {
x.a // $ fieldof=MyThing
}
}
pub fn f() {
@@ -702,8 +741,26 @@ mod function_trait_bounds {
let x2 = MyThing { a: S1 };
let y2 = MyThing { a: S2 };
println!("{:?}", call_trait_m1(x2)); // $ target=call_trait_m1
println!("{:?}", call_trait_m1(y2)); // $ target=call_trait_m1
let a = call_trait_m1(x2); // $ type=a:S1 target=call_trait_m1
println!("{:?}", a);
let a = call_trait_m1_2(x2); // $ type=a:S1 target=call_trait_m1_2
println!("{:?}", a);
let a = call_trait_m1_3(x2); // $ type=a:S1 target=call_trait_m1_3
println!("{:?}", a);
let a = call_trait_m1(y2); // $ type=a:S2 target=call_trait_m1
println!("{:?}", a);
let a = call_trait_m1_2(y2); // $ type=a:S2 target=call_trait_m1_2
println!("{:?}", a);
let a = call_trait_m1_3(y2); // $ type=a:S2 target=call_trait_m1_3
println!("{:?}", a);
let a = call_trait_assoc_1(x2); // $ type=a:S1 target=call_trait_assoc_1
println!("{:?}", a);
let a = call_trait_assoc_2(x2); // $ type=a:S1 target=call_trait_assoc_2
println!("{:?}", a);
let a = call_trait_assoc_1(y2); // $ type=a:S2 target=call_trait_assoc_1
println!("{:?}", a);
let a = call_trait_assoc_2(y2); // $ type=a:S2 target=call_trait_assoc_2
println!("{:?}", a);
let x3 = MyThing {
a: MyThing { a: S1 },
@@ -714,8 +771,16 @@ mod function_trait_bounds {
let a = call_trait_thing_m1(x3); // $ type=a:S1 target=call_trait_thing_m1
println!("{:?}", a);
let a = call_trait_thing_m1_2(x3); // $ type=a:S1 target=call_trait_thing_m1_2
println!("{:?}", a);
let a = call_trait_thing_m1_3(x3); // $ type=a:S1 target=call_trait_thing_m1_3
println!("{:?}", a);
let b = call_trait_thing_m1(y3); // $ type=b:S2 target=call_trait_thing_m1
println!("{:?}", b);
let b = call_trait_thing_m1_2(y3); // $ type=b:S2 target=call_trait_thing_m1_2
println!("{:?}", b);
let b = call_trait_thing_m1_3(y3); // $ type=b:S2 target=call_trait_thing_m1_3
println!("{:?}", b);
}
}
@@ -958,19 +1023,19 @@ mod generic_enum {
}
mod method_supertraits {
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
struct MyThing<A> {
a: A,
}
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
struct MyThing2<A> {
a: A,
}
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
struct S1;
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
struct S2;
trait MyTrait1<Tr1> {
@@ -978,16 +1043,16 @@ mod method_supertraits {
fn m1(self) -> Tr1;
}
trait MyTrait2<Tr2>: MyTrait1<Tr2> {
trait MyTrait2<Tr2>: MyTrait1<Tr2> + Copy {
#[rustfmt::skip]
fn m2(self) -> Tr2
fn m2(&self) -> Tr2
where
Self: Sized,
{
if 3 > 2 { // $ target=gt
self.m1() // $ target=MyTrait1::m1
} else {
Self::m1(self) // $ target=MyTrait1::m1
Self::m1(*self) // $ target=deref target=MyTrait1::m1
}
}
}
@@ -1001,7 +1066,7 @@ mod method_supertraits {
if 3 > 2 { // $ target=gt
self.m2().a // $ target=m2 $ fieldof=MyThing
} else {
Self::m2(self).a // $ target=m2 fieldof=MyThing
Self::m2(&self).a // $ target=m2 fieldof=MyThing
}
}
}
@@ -1013,7 +1078,7 @@ mod method_supertraits {
}
}
impl<T> MyTrait2<T> for MyThing<T> {}
impl<T: Copy> MyTrait2<T> for MyThing<T> {}
impl<T> MyTrait1<MyThing<T>> for MyThing2<T> {
// MyThing2::m1
@@ -1022,9 +1087,9 @@ mod method_supertraits {
}
}
impl<T> MyTrait2<MyThing<T>> for MyThing2<T> {}
impl<T: Copy> MyTrait2<MyThing<T>> for MyThing2<T> {}
impl<T> MyTrait3<T> for MyThing2<T> {}
impl<T: Copy> MyTrait3<T> for MyThing2<T> {}
fn call_trait_m1<T1, T2: MyTrait1<T1>>(x: T2) -> T1 {
x.m1() // $ target=MyTrait1::m1
@@ -1384,12 +1449,12 @@ mod method_call_type_conversion {
let my_thing = &MyInt { a: 37 };
// implicit borrow of a `&`
let a = my_thing.method_on_borrow(); // $ MISSING: target=MyInt::method_on_borrow
let a = my_thing.method_on_borrow(); // $ target=MyInt::method_on_borrow
println!("{:?}", a);
// no implicit borrow
let my_thing = &MyInt { a: 38 };
let a = my_thing.method_not_on_borrow(); // $ MISSING: target=MyInt::method_not_on_borrow
let a = my_thing.method_not_on_borrow(); // $ target=MyInt::method_not_on_borrow
println!("{:?}", a);
}
}
@@ -1819,6 +1884,11 @@ mod overloadable_operators {
self.x >= other.x && self.y >= other.y // $ fieldof=Vec2 target=ge
}
}
fn param_add<T: Add>(a: T, b: T) -> T::Output {
a + b // $ target=add
}
pub fn f() {
// Test for all overloadable operators on `i64`
@@ -1836,6 +1906,7 @@ mod overloadable_operators {
let i64_mul = 17i64 * 18i64; // $ type=i64_mul:i64 target=mul
let i64_div = 19i64 / 20i64; // $ type=i64_div:i64 target=div
let i64_rem = 21i64 % 22i64; // $ type=i64_rem:i64 target=rem
let i64_param_add = param_add(1i64, 2i64); // $ target=param_add $ MISSING: type=i64_param_add:i64
// Arithmetic assignment operators
let mut i64_add_assign = 23i64;
@@ -2083,7 +2154,7 @@ mod impl_trait {
mod indexers {
use std::ops::Index;
#[derive(Debug)]
#[derive(Debug, Copy, Clone)]
struct S;
impl S {
@@ -2120,6 +2191,13 @@ mod indexers {
let x = slice[0].foo(); // $ target=foo type=x:S target=index
}
fn param_index<T: Index<usize>>(a: T, b: usize) -> T::Output
where
<T as Index<usize>>::Output: Sized + Copy,
{
a[b] // $ target=index
}
pub fn f() {
let mut vec = MyVec::new(); // $ type=vec:T.S target=new
vec.push(S); // $ target=push
@@ -2128,6 +2206,8 @@ mod indexers {
let xs: [S; 1] = [S];
let x = xs[0].foo(); // $ target=foo type=x:S target=index
let y = param_index(vec, 0); // $ target=param_index $ MISSING: type=y:S
analyze_slice(&xs); // $ target=analyze_slice
}
}
@@ -2366,9 +2446,9 @@ mod loops {
String::from("bar"), // $ target=from
String::from("baz"), // $ target=from
];
for s in strings3 {} // $ MISSING: type=s:String
for s in strings3 {} // $ type=s:&T.String
let callables = [MyCallable::new(), MyCallable::new(), MyCallable::new()]; // $ target=new $ MISSING: type=callables:[T;...].MyCallable; 3
let callables = [MyCallable::new(), MyCallable::new(), MyCallable::new()]; // $ target=new $ type=callables:[T;...].MyCallable
for c // $ type=c:MyCallable
in callables
{
@@ -2422,10 +2502,10 @@ mod loops {
let mut map1 = std::collections::HashMap::new(); // $ target=new type=map1:K.i32 type=map1:V.Box $ MISSING: type=map1:Hashmap type1=map1:V.T.&T.str
map1.insert(1, Box::new("one")); // $ target=insert target=new
map1.insert(2, Box::new("two")); // $ target=insert target=new
for key in map1.keys() {} // $ target=keys MISSING: type=key:i32
for value in map1.values() {} // $ target=values MISSING: type=value:Box type=value:T.&T.str
for (key, value) in map1.iter() {} // $ target=iter MISSING: type=key:i32 type=value:Box type=value:T.&T.str
for (key, value) in &map1 {} // $ MISSING: type=key:i32 type=value:Box type=value:T.&T.str
for key in map1.keys() {} // $ target=keys type=key:&T.i32
for value in map1.values() {} // $ target=values type=value:&T.Box type=value:&T.T.&T.str
for (key, value) in map1.iter() {} // $ target=iter type=key:&T.i32 type=value:&T.Box type=value:&T.T.&T.str
for (key, value) in &map1 {} // $ type=key:&T.i32 type=value:&T.Box type=value:&T.T.&T.str
// while loops
@@ -2491,6 +2571,7 @@ mod explicit_type_args {
field: S2::default(), // $ target=default
};
let x14 = foo::<i32>(Default::default()); // $ certainType=x14:i32 target=default target=foo
let x15 = S1::<S2>::default(); // $ certainType=x15:T.S2 target=default
}
}
@@ -2615,10 +2696,10 @@ pub mod path_buf {
}
}
mod blanket_impl;
mod closure;
mod dereference;
mod dyn_type;
mod blanket_impl;
fn main() {
field_access::f(); // $ target=f

View File

@@ -3,19 +3,6 @@ multipleCallTargets
| mysql.rs:16:26:16:85 | ...::from(...) |
| mysql.rs:18:13:18:66 | ...::from(...) |
| mysql.rs:19:30:19:83 | ...::from(...) |
| mysql.rs:22:38:22:56 | safe_query.as_str() |
| mysql.rs:25:38:25:58 | unsafe_query.as_str() |
| mysql.rs:26:64:26:84 | unsafe_query.as_str() |
| mysql.rs:27:25:27:45 | unsafe_query.as_str() |
| mysql.rs:28:39:28:59 | unsafe_query.as_str() |
| mysql.rs:29:65:29:85 | unsafe_query.as_str() |
| mysql.rs:30:33:30:53 | unsafe_query.as_str() |
| mysql.rs:32:13:32:33 | unsafe_query.as_str() |
| mysql.rs:36:33:36:53 | unsafe_query.as_str() |
| mysql.rs:37:32:37:52 | unsafe_query.as_str() |
| mysql.rs:39:13:39:33 | unsafe_query.as_str() |
| mysql.rs:42:39:42:59 | unsafe_query.as_str() |
| mysql.rs:45:30:45:52 | prepared_query.as_str() |
| mysql.rs:46:45:46:66 | remote_string.as_str() |
| mysql.rs:47:71:47:92 | remote_string.as_str() |
| mysql.rs:48:46:48:67 | remote_string.as_str() |
@@ -27,21 +14,10 @@ multipleCallTargets
| mysql.rs:66:40:66:61 | remote_string.as_str() |
| mysql.rs:67:39:67:60 | remote_string.as_str() |
| mysql.rs:70:14:70:35 | remote_string.as_str() |
| mysql.rs:75:31:75:51 | unsafe_query.as_str() |
| mysql.rs:80:26:80:46 | unsafe_query.as_str() |
| mysql.rs:100:24:100:39 | ...::from(...) |
| mysql.rs:101:26:101:85 | ...::from(...) |
| mysql.rs:103:13:103:66 | ...::from(...) |
| mysql.rs:104:30:104:83 | ...::from(...) |
| mysql.rs:107:38:107:56 | safe_query.as_str() |
| mysql.rs:110:38:110:58 | unsafe_query.as_str() |
| mysql.rs:111:25:111:45 | unsafe_query.as_str() |
| mysql.rs:112:47:112:67 | unsafe_query.as_str() |
| mysql.rs:114:25:114:45 | unsafe_query.as_str() |
| mysql.rs:116:33:116:53 | unsafe_query.as_str() |
| mysql.rs:118:40:118:60 | unsafe_query.as_str() |
| mysql.rs:121:24:121:44 | unsafe_query.as_str() |
| mysql.rs:125:30:125:52 | prepared_query.as_str() |
| mysql.rs:126:45:126:66 | remote_string.as_str() |
| mysql.rs:128:38:128:59 | remote_string.as_str() |
| mysql.rs:130:33:130:54 | remote_string.as_str() |
@@ -50,8 +26,6 @@ multipleCallTargets
| mysql.rs:140:40:140:61 | remote_string.as_str() |
| mysql.rs:142:62:142:83 | remote_string.as_str() |
| mysql.rs:145:31:145:52 | remote_string.as_str() |
| mysql.rs:149:31:149:51 | unsafe_query.as_str() |
| mysql.rs:154:26:154:46 | unsafe_query.as_str() |
| sqlx.rs:46:24:46:44 | ...::from(...) |
| sqlx.rs:47:56:47:76 | ...::from(...) |
| sqlx.rs:48:97:48:117 | ...::from(...) |
@@ -59,64 +33,18 @@ multipleCallTargets
| sqlx.rs:51:24:51:77 | ...::from(...) |
| sqlx.rs:55:26:55:79 | ...::from(...) |
| sqlx.rs:61:28:61:81 | ...::from(...) |
| sqlx.rs:64:57:64:77 | safe_query_1.as_str() |
| sqlx.rs:65:26:65:46 | safe_query_2.as_str() |
| sqlx.rs:66:26:66:46 | safe_query_3.as_str() |
| sqlx.rs:67:26:67:48 | unsafe_query_1.as_str() |
| sqlx.rs:69:30:69:52 | unsafe_query_2.as_str() |
| sqlx.rs:70:30:70:52 | unsafe_query_3.as_str() |
| sqlx.rs:71:30:71:52 | unsafe_query_4.as_str() |
| sqlx.rs:75:25:75:45 | safe_query_1.as_str() |
| sqlx.rs:76:25:76:45 | safe_query_2.as_str() |
| sqlx.rs:77:25:77:45 | safe_query_3.as_str() |
| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() |
| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() |
| sqlx.rs:81:29:81:51 | unsafe_query_3.as_str() |
| sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() |
| sqlx.rs:84:25:84:49 | prepared_query_1.as_str() |
| sqlx.rs:85:25:85:49 | prepared_query_1.as_str() |
| sqlx.rs:87:29:87:53 | prepared_query_1.as_str() |
| sqlx.rs:88:29:88:53 | prepared_query_1.as_str() |
| sqlx.rs:99:24:99:44 | ...::from(...) |
| sqlx.rs:100:97:100:117 | ...::from(...) |
| sqlx.rs:101:24:101:77 | ...::from(...) |
| sqlx.rs:102:26:102:79 | ...::from(...) |
| sqlx.rs:103:28:103:81 | ...::from(...) |
| sqlx.rs:106:26:106:46 | safe_query_1.as_str() |
| sqlx.rs:108:30:108:52 | unsafe_query_1.as_str() |
| sqlx.rs:111:27:111:47 | safe_query_1.as_str() |
| sqlx.rs:113:31:113:53 | unsafe_query_1.as_str() |
| sqlx.rs:117:25:117:45 | safe_query_1.as_str() |
| sqlx.rs:118:25:118:49 | prepared_query_1.as_str() |
| sqlx.rs:120:29:120:51 | unsafe_query_1.as_str() |
| sqlx.rs:121:29:121:53 | prepared_query_1.as_str() |
| sqlx.rs:124:25:124:45 | safe_query_1.as_str() |
| sqlx.rs:125:25:125:49 | prepared_query_1.as_str() |
| sqlx.rs:127:29:127:51 | unsafe_query_1.as_str() |
| sqlx.rs:128:29:128:53 | prepared_query_1.as_str() |
| sqlx.rs:131:54:131:74 | safe_query_1.as_str() |
| sqlx.rs:133:54:133:78 | prepared_query_1.as_str() |
| sqlx.rs:136:55:136:77 | unsafe_query_1.as_str() |
| sqlx.rs:137:55:137:79 | prepared_query_1.as_str() |
| sqlx.rs:140:54:140:74 | safe_query_1.as_str() |
| sqlx.rs:142:54:142:78 | prepared_query_1.as_str() |
| sqlx.rs:145:55:145:77 | unsafe_query_1.as_str() |
| sqlx.rs:146:55:146:79 | prepared_query_1.as_str() |
| sqlx.rs:149:25:149:45 | safe_query_1.as_str() |
| sqlx.rs:150:25:150:49 | prepared_query_1.as_str() |
| sqlx.rs:153:29:153:51 | unsafe_query_1.as_str() |
| sqlx.rs:154:29:154:53 | prepared_query_1.as_str() |
| sqlx.rs:172:24:172:44 | ...::from(...) |
| sqlx.rs:173:97:173:117 | ...::from(...) |
| sqlx.rs:174:24:174:77 | ...::from(...) |
| sqlx.rs:175:26:175:79 | ...::from(...) |
| sqlx.rs:176:28:176:82 | ...::from(...) |
| sqlx.rs:179:26:179:46 | safe_query_1.as_str() |
| sqlx.rs:181:30:181:52 | unsafe_query_1.as_str() |
| sqlx.rs:185:25:185:45 | safe_query_1.as_str() |
| sqlx.rs:186:25:186:49 | prepared_query_1.as_str() |
| sqlx.rs:188:29:188:51 | unsafe_query_1.as_str() |
| sqlx.rs:189:29:189:53 | prepared_query_1.as_str() |
| sqlx.rs:202:57:202:85 | ...::from(...) |
multiplePathResolutions
| mysql.rs:5:37:5:74 | Result::<...> |

View File

@@ -41,126 +41,74 @@ edges
| mysql.rs:12:33:14:19 | ... .text() [Ok] | mysql.rs:12:33:15:40 | ... .unwrap_or(...) | provenance | MaD:32 |
| mysql.rs:12:33:15:40 | ... .unwrap_or(...) | mysql.rs:12:13:12:29 | mut remote_string | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:25:38:25:49 | unsafe_query | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:25:38:25:58 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:25:38:25:58 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:25:38:25:58 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:26:64:26:75 | unsafe_query | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:26:64:26:84 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:26:64:26:84 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:26:64:26:84 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:27:25:27:36 | unsafe_query | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:27:25:27:45 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:27:25:27:45 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:27:25:27:45 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:28:39:28:50 | unsafe_query | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:28:39:28:59 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:28:39:28:59 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:28:39:28:59 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:29:65:29:76 | unsafe_query | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:29:65:29:85 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:29:65:29:85 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:29:65:29:85 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:30:33:30:44 | unsafe_query | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:30:33:30:53 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:30:33:30:53 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:30:33:30:53 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:32:13:32:24 | unsafe_query | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:32:13:32:33 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:32:13:32:33 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:32:13:32:33 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:36:33:36:44 | unsafe_query | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:36:33:36:53 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:36:33:36:53 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:36:33:36:53 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:37:32:37:43 | unsafe_query | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:37:32:37:52 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:37:32:37:52 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:37:32:37:52 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:39:13:39:24 | unsafe_query | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:39:13:39:33 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:39:13:39:33 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:39:13:39:33 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:42:39:42:50 | unsafe_query | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:42:39:42:59 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:42:39:42:59 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:42:39:42:59 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:75:31:75:42 | unsafe_query | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:75:31:75:51 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:75:31:75:51 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:75:31:75:51 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:80:26:80:37 | unsafe_query | provenance | |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:80:26:80:46 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:80:26:80:46 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:80:26:80:46 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:18:13:18:83 | ... + ... | mysql.rs:17:13:17:24 | unsafe_query | provenance | |
| mysql.rs:18:13:18:83 | ... + ... | mysql.rs:18:13:18:89 | ... + ... | provenance | MaD:27 |
| mysql.rs:18:13:18:83 | ... + ... | mysql.rs:18:13:18:89 | ... + ... | provenance | MaD:28 |
| mysql.rs:18:13:18:89 | ... + ... | mysql.rs:17:13:17:24 | unsafe_query | provenance | |
| mysql.rs:18:70:18:83 | &remote_string [&ref] | mysql.rs:18:13:18:83 | ... + ... | provenance | MaD:26 |
| mysql.rs:18:71:18:83 | remote_string | mysql.rs:18:70:18:83 | &remote_string [&ref] | provenance | |
| mysql.rs:25:38:25:49 | unsafe_query | mysql.rs:25:38:25:58 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:25:38:25:49 | unsafe_query | mysql.rs:25:38:25:58 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:25:38:25:49 | unsafe_query | mysql.rs:25:38:25:58 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:25:38:25:58 | unsafe_query.as_str() | mysql.rs:25:32:25:36 | query | provenance | MaD:1 Sink:MaD:1 |
| mysql.rs:25:38:25:58 | unsafe_query.as_str() [&ref] | mysql.rs:25:32:25:36 | query | provenance | MaD:1 Sink:MaD:1 |
| mysql.rs:26:64:26:75 | unsafe_query | mysql.rs:26:64:26:84 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:26:64:26:75 | unsafe_query | mysql.rs:26:64:26:84 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:26:64:26:75 | unsafe_query | mysql.rs:26:64:26:84 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:26:64:26:84 | unsafe_query.as_str() | mysql.rs:26:54:26:62 | query_opt | provenance | MaD:9 Sink:MaD:9 |
| mysql.rs:26:64:26:84 | unsafe_query.as_str() [&ref] | mysql.rs:26:54:26:62 | query_opt | provenance | MaD:9 Sink:MaD:9 |
| mysql.rs:27:25:27:36 | unsafe_query | mysql.rs:27:25:27:45 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:27:25:27:36 | unsafe_query | mysql.rs:27:25:27:45 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:27:25:27:36 | unsafe_query | mysql.rs:27:25:27:45 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:27:25:27:45 | unsafe_query.as_str() | mysql.rs:27:14:27:23 | query_drop | provenance | MaD:2 Sink:MaD:2 |
| mysql.rs:27:25:27:45 | unsafe_query.as_str() [&ref] | mysql.rs:27:14:27:23 | query_drop | provenance | MaD:2 Sink:MaD:2 |
| mysql.rs:28:39:28:50 | unsafe_query | mysql.rs:28:39:28:59 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:28:39:28:50 | unsafe_query | mysql.rs:28:39:28:59 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:28:39:28:50 | unsafe_query | mysql.rs:28:39:28:59 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:28:39:28:59 | unsafe_query.as_str() | mysql.rs:28:27:28:37 | query_first | provenance | MaD:3 Sink:MaD:3 |
| mysql.rs:28:39:28:59 | unsafe_query.as_str() [&ref] | mysql.rs:28:27:28:37 | query_first | provenance | MaD:3 Sink:MaD:3 |
| mysql.rs:29:65:29:76 | unsafe_query | mysql.rs:29:65:29:85 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:29:65:29:76 | unsafe_query | mysql.rs:29:65:29:85 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:29:65:29:76 | unsafe_query | mysql.rs:29:65:29:85 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:29:65:29:85 | unsafe_query.as_str() | mysql.rs:29:49:29:63 | query_first_opt | provenance | MaD:4 Sink:MaD:4 |
| mysql.rs:29:65:29:85 | unsafe_query.as_str() [&ref] | mysql.rs:29:49:29:63 | query_first_opt | provenance | MaD:4 Sink:MaD:4 |
| mysql.rs:30:33:30:44 | unsafe_query | mysql.rs:30:33:30:53 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:30:33:30:44 | unsafe_query | mysql.rs:30:33:30:53 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:30:33:30:44 | unsafe_query | mysql.rs:30:33:30:53 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:30:33:30:53 | unsafe_query.as_str() | mysql.rs:30:22:30:31 | query_fold | provenance | MaD:5 Sink:MaD:5 |
| mysql.rs:30:33:30:53 | unsafe_query.as_str() [&ref] | mysql.rs:30:22:30:31 | query_fold | provenance | MaD:5 Sink:MaD:5 |
| mysql.rs:32:13:32:24 | unsafe_query | mysql.rs:32:13:32:33 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:32:13:32:24 | unsafe_query | mysql.rs:32:13:32:33 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:32:13:32:24 | unsafe_query | mysql.rs:32:13:32:33 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:32:13:32:33 | unsafe_query.as_str() | mysql.rs:31:22:31:35 | query_fold_opt | provenance | MaD:6 Sink:MaD:6 |
| mysql.rs:32:13:32:33 | unsafe_query.as_str() [&ref] | mysql.rs:31:22:31:35 | query_fold_opt | provenance | MaD:6 Sink:MaD:6 |
| mysql.rs:36:33:36:44 | unsafe_query | mysql.rs:36:33:36:53 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:36:33:36:44 | unsafe_query | mysql.rs:36:33:36:53 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:36:33:36:44 | unsafe_query | mysql.rs:36:33:36:53 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:36:33:36:53 | unsafe_query.as_str() | mysql.rs:36:22:36:31 | query_iter | provenance | MaD:17 Sink:MaD:17 |
| mysql.rs:36:33:36:53 | unsafe_query.as_str() [&ref] | mysql.rs:36:22:36:31 | query_iter | provenance | MaD:17 Sink:MaD:17 |
| mysql.rs:37:32:37:43 | unsafe_query | mysql.rs:37:32:37:52 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:37:32:37:43 | unsafe_query | mysql.rs:37:32:37:52 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:37:32:37:43 | unsafe_query | mysql.rs:37:32:37:52 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:37:32:37:52 | unsafe_query.as_str() | mysql.rs:37:22:37:30 | query_map | provenance | MaD:7 Sink:MaD:7 |
| mysql.rs:37:32:37:52 | unsafe_query.as_str() [&ref] | mysql.rs:37:22:37:30 | query_map | provenance | MaD:7 Sink:MaD:7 |
| mysql.rs:39:13:39:24 | unsafe_query | mysql.rs:39:13:39:33 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:39:13:39:24 | unsafe_query | mysql.rs:39:13:39:33 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:39:13:39:24 | unsafe_query | mysql.rs:39:13:39:33 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:39:13:39:33 | unsafe_query.as_str() | mysql.rs:38:22:38:34 | query_map_opt | provenance | MaD:8 Sink:MaD:8 |
| mysql.rs:39:13:39:33 | unsafe_query.as_str() [&ref] | mysql.rs:38:22:38:34 | query_map_opt | provenance | MaD:8 Sink:MaD:8 |
| mysql.rs:42:39:42:50 | unsafe_query | mysql.rs:42:39:42:59 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:42:39:42:50 | unsafe_query | mysql.rs:42:39:42:59 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:42:39:42:50 | unsafe_query | mysql.rs:42:39:42:59 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:42:39:42:59 | unsafe_query.as_str() | mysql.rs:42:33:42:37 | query | provenance | MaD:1 Sink:MaD:1 |
| mysql.rs:42:39:42:59 | unsafe_query.as_str() [&ref] | mysql.rs:42:33:42:37 | query | provenance | MaD:1 Sink:MaD:1 |
| mysql.rs:75:31:75:42 | unsafe_query | mysql.rs:75:31:75:51 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:75:31:75:42 | unsafe_query | mysql.rs:75:31:75:51 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:75:31:75:42 | unsafe_query | mysql.rs:75:31:75:51 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:75:31:75:51 | unsafe_query.as_str() | mysql.rs:75:26:75:29 | prep | provenance | MaD:16 Sink:MaD:16 |
| mysql.rs:75:31:75:51 | unsafe_query.as_str() [&ref] | mysql.rs:75:26:75:29 | prep | provenance | MaD:16 Sink:MaD:16 |
| mysql.rs:80:26:80:37 | unsafe_query | mysql.rs:80:26:80:46 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:80:26:80:37 | unsafe_query | mysql.rs:80:26:80:46 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:80:26:80:37 | unsafe_query | mysql.rs:80:26:80:46 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:80:26:80:46 | unsafe_query.as_str() | mysql.rs:80:15:80:24 | query_drop | provenance | MaD:2 Sink:MaD:2 |
| mysql.rs:80:26:80:46 | unsafe_query.as_str() [&ref] | mysql.rs:80:15:80:24 | query_drop | provenance | MaD:2 Sink:MaD:2 |
| mysql.rs:97:13:97:29 | mut remote_string | mysql.rs:103:71:103:83 | remote_string | provenance | |
@@ -170,90 +118,54 @@ edges
| mysql.rs:97:33:99:19 | ... .text() [Ok] | mysql.rs:97:33:100:40 | ... .unwrap_or(...) | provenance | MaD:32 |
| mysql.rs:97:33:100:40 | ... .unwrap_or(...) | mysql.rs:97:13:97:29 | mut remote_string | provenance | |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:110:38:110:49 | unsafe_query | provenance | |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:110:38:110:58 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:110:38:110:58 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:110:38:110:58 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:111:25:111:36 | unsafe_query | provenance | |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:111:25:111:45 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:111:25:111:45 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:111:25:111:45 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:112:47:112:58 | unsafe_query | provenance | |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:112:47:112:67 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:112:47:112:67 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:112:47:112:67 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:114:25:114:36 | unsafe_query | provenance | |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:114:25:114:45 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:114:25:114:45 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:114:25:114:45 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:116:33:116:44 | unsafe_query | provenance | |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:116:33:116:53 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:116:33:116:53 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:116:33:116:53 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:118:40:118:51 | unsafe_query | provenance | |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:118:40:118:60 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:118:40:118:60 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:118:40:118:60 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:121:24:121:35 | unsafe_query | provenance | |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:121:24:121:44 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:121:24:121:44 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:121:24:121:44 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:149:31:149:42 | unsafe_query | provenance | |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:149:31:149:51 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:149:31:149:51 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:149:31:149:51 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:154:26:154:37 | unsafe_query | provenance | |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:154:26:154:46 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:154:26:154:46 | unsafe_query.as_str() | provenance | MaD:29 |
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:154:26:154:46 | unsafe_query.as_str() | provenance | MaD:33 |
| mysql.rs:103:13:103:83 | ... + ... | mysql.rs:102:13:102:24 | unsafe_query | provenance | |
| mysql.rs:103:13:103:83 | ... + ... | mysql.rs:103:13:103:89 | ... + ... | provenance | MaD:27 |
| mysql.rs:103:13:103:83 | ... + ... | mysql.rs:103:13:103:89 | ... + ... | provenance | MaD:28 |
| mysql.rs:103:13:103:89 | ... + ... | mysql.rs:102:13:102:24 | unsafe_query | provenance | |
| mysql.rs:103:70:103:83 | &remote_string [&ref] | mysql.rs:103:13:103:83 | ... + ... | provenance | MaD:26 |
| mysql.rs:103:71:103:83 | remote_string | mysql.rs:103:70:103:83 | &remote_string [&ref] | provenance | |
| mysql.rs:110:38:110:49 | unsafe_query | mysql.rs:110:38:110:58 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:110:38:110:49 | unsafe_query | mysql.rs:110:38:110:58 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:110:38:110:49 | unsafe_query | mysql.rs:110:38:110:58 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:110:38:110:58 | unsafe_query.as_str() | mysql.rs:110:32:110:36 | query | provenance | MaD:10 Sink:MaD:10 |
| mysql.rs:110:38:110:58 | unsafe_query.as_str() [&ref] | mysql.rs:110:32:110:36 | query | provenance | MaD:10 Sink:MaD:10 |
| mysql.rs:111:25:111:36 | unsafe_query | mysql.rs:111:25:111:45 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:111:25:111:36 | unsafe_query | mysql.rs:111:25:111:45 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:111:25:111:36 | unsafe_query | mysql.rs:111:25:111:45 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:111:25:111:45 | unsafe_query.as_str() | mysql.rs:111:14:111:23 | query_drop | provenance | MaD:11 Sink:MaD:11 |
| mysql.rs:111:25:111:45 | unsafe_query.as_str() [&ref] | mysql.rs:111:14:111:23 | query_drop | provenance | MaD:11 Sink:MaD:11 |
| mysql.rs:112:47:112:58 | unsafe_query | mysql.rs:112:47:112:67 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:112:47:112:58 | unsafe_query | mysql.rs:112:47:112:67 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:112:47:112:58 | unsafe_query | mysql.rs:112:47:112:67 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:112:47:112:67 | unsafe_query.as_str() | mysql.rs:112:35:112:45 | query_first | provenance | MaD:12 Sink:MaD:12 |
| mysql.rs:112:47:112:67 | unsafe_query.as_str() [&ref] | mysql.rs:112:35:112:45 | query_first | provenance | MaD:12 Sink:MaD:12 |
| mysql.rs:114:25:114:36 | unsafe_query | mysql.rs:114:25:114:45 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:114:25:114:36 | unsafe_query | mysql.rs:114:25:114:45 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:114:25:114:36 | unsafe_query | mysql.rs:114:25:114:45 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:114:25:114:45 | unsafe_query.as_str() | mysql.rs:114:14:114:23 | query_fold | provenance | MaD:13 Sink:MaD:13 |
| mysql.rs:114:25:114:45 | unsafe_query.as_str() [&ref] | mysql.rs:114:14:114:23 | query_fold | provenance | MaD:13 Sink:MaD:13 |
| mysql.rs:116:33:116:44 | unsafe_query | mysql.rs:116:33:116:53 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:116:33:116:44 | unsafe_query | mysql.rs:116:33:116:53 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:116:33:116:44 | unsafe_query | mysql.rs:116:33:116:53 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:116:33:116:53 | unsafe_query.as_str() | mysql.rs:116:22:116:31 | query_iter | provenance | MaD:19 Sink:MaD:19 |
| mysql.rs:116:33:116:53 | unsafe_query.as_str() [&ref] | mysql.rs:116:22:116:31 | query_iter | provenance | MaD:19 Sink:MaD:19 |
| mysql.rs:118:40:118:51 | unsafe_query | mysql.rs:118:40:118:60 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:118:40:118:51 | unsafe_query | mysql.rs:118:40:118:60 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:118:40:118:51 | unsafe_query | mysql.rs:118:40:118:60 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:118:40:118:60 | unsafe_query.as_str() | mysql.rs:118:14:118:25 | query_stream | provenance | MaD:15 Sink:MaD:15 |
| mysql.rs:118:40:118:60 | unsafe_query.as_str() [&ref] | mysql.rs:118:14:118:25 | query_stream | provenance | MaD:15 Sink:MaD:15 |
| mysql.rs:121:24:121:35 | unsafe_query | mysql.rs:121:24:121:44 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:121:24:121:35 | unsafe_query | mysql.rs:121:24:121:44 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:121:24:121:35 | unsafe_query | mysql.rs:121:24:121:44 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:121:24:121:44 | unsafe_query.as_str() | mysql.rs:121:14:121:22 | query_map | provenance | MaD:14 Sink:MaD:14 |
| mysql.rs:121:24:121:44 | unsafe_query.as_str() [&ref] | mysql.rs:121:14:121:22 | query_map | provenance | MaD:14 Sink:MaD:14 |
| mysql.rs:149:31:149:42 | unsafe_query | mysql.rs:149:31:149:51 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:149:31:149:42 | unsafe_query | mysql.rs:149:31:149:51 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:149:31:149:42 | unsafe_query | mysql.rs:149:31:149:51 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:149:31:149:51 | unsafe_query.as_str() | mysql.rs:149:26:149:29 | prep | provenance | MaD:18 Sink:MaD:18 |
| mysql.rs:149:31:149:51 | unsafe_query.as_str() [&ref] | mysql.rs:149:26:149:29 | prep | provenance | MaD:18 Sink:MaD:18 |
| mysql.rs:154:26:154:37 | unsafe_query | mysql.rs:154:26:154:46 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:154:26:154:37 | unsafe_query | mysql.rs:154:26:154:46 | unsafe_query.as_str() [&ref] | provenance | MaD:29 |
| mysql.rs:154:26:154:37 | unsafe_query | mysql.rs:154:26:154:46 | unsafe_query.as_str() [&ref] | provenance | MaD:33 |
| mysql.rs:154:26:154:46 | unsafe_query.as_str() | mysql.rs:154:15:154:24 | query_drop | provenance | MaD:11 Sink:MaD:11 |
| mysql.rs:154:26:154:46 | unsafe_query.as_str() [&ref] | mysql.rs:154:15:154:24 | query_drop | provenance | MaD:11 Sink:MaD:11 |
| sqlx.rs:47:9:47:18 | arg_string | sqlx.rs:53:27:53:36 | arg_string | provenance | |
@@ -275,16 +187,12 @@ edges
| sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | provenance | MaD:32 |
| sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | sqlx.rs:49:9:49:21 | remote_number | provenance | |
| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:36 | safe_query_3 | provenance | |
| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:33 |
| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:29 |
| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:33 |
| sqlx.rs:52:32:52:87 | ...::format(...) | sqlx.rs:52:32:52:87 | { ... } | provenance | |
| sqlx.rs:52:32:52:87 | ...::must_use(...) | sqlx.rs:52:9:52:20 | safe_query_3 | provenance | |
| sqlx.rs:52:32:52:87 | MacroExpr | sqlx.rs:52:32:52:87 | ...::format(...) | provenance | MaD:36 |
| sqlx.rs:52:32:52:87 | { ... } | sqlx.rs:52:32:52:87 | ...::must_use(...) | provenance | MaD:37 |
| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | provenance | MaD:29 |
| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:53:26:53:36 | &arg_string [&ref] | sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | provenance | |
| sqlx.rs:53:27:53:36 | arg_string | sqlx.rs:53:26:53:36 | &arg_string [&ref] | provenance | |
| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | provenance | MaD:33 |
@@ -293,9 +201,7 @@ edges
| sqlx.rs:54:26:54:39 | &remote_string [&ref] | sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | provenance | |
| sqlx.rs:54:27:54:39 | remote_string | sqlx.rs:54:26:54:39 | &remote_string [&ref] | provenance | |
| sqlx.rs:55:9:55:22 | unsafe_query_3 | sqlx.rs:81:29:81:42 | unsafe_query_3 | provenance | |
| sqlx.rs:55:9:55:22 | unsafe_query_3 | sqlx.rs:81:29:81:51 | unsafe_query_3.as_str() | provenance | MaD:33 |
| sqlx.rs:55:9:55:22 | unsafe_query_3 | sqlx.rs:81:29:81:51 | unsafe_query_3.as_str() | provenance | MaD:29 |
| sqlx.rs:55:9:55:22 | unsafe_query_3 | sqlx.rs:81:29:81:51 | unsafe_query_3.as_str() | provenance | MaD:33 |
| sqlx.rs:55:26:55:96 | ... + ... | sqlx.rs:55:9:55:22 | unsafe_query_3 | provenance | |
| sqlx.rs:55:26:55:96 | ... + ... | sqlx.rs:55:26:55:102 | ... + ... | provenance | MaD:27 |
| sqlx.rs:55:26:55:96 | ... + ... | sqlx.rs:55:26:55:102 | ... + ... | provenance | MaD:28 |
@@ -303,28 +209,20 @@ edges
| sqlx.rs:55:83:55:96 | &remote_string [&ref] | sqlx.rs:55:26:55:96 | ... + ... | provenance | MaD:26 |
| sqlx.rs:55:84:55:96 | remote_string | sqlx.rs:55:83:55:96 | &remote_string [&ref] | provenance | |
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:42 | unsafe_query_4 | provenance | |
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | provenance | MaD:33 |
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | provenance | MaD:29 |
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | provenance | MaD:33 |
| sqlx.rs:59:17:59:72 | ...::format(...) | sqlx.rs:59:17:59:72 | { ... } | provenance | |
| sqlx.rs:59:17:59:72 | ...::must_use(...) | sqlx.rs:56:9:56:22 | unsafe_query_4 | provenance | |
| sqlx.rs:59:17:59:72 | MacroExpr | sqlx.rs:59:17:59:72 | ...::format(...) | provenance | MaD:36 |
| sqlx.rs:59:17:59:72 | { ... } | sqlx.rs:59:17:59:72 | ...::must_use(...) | provenance | MaD:37 |
| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:29 |
| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:77:25:77:45 | safe_query_3.as_str() | sqlx.rs:77:13:77:23 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | sqlx.rs:77:13:77:23 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | sqlx.rs:78:13:78:23 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | sqlx.rs:80:17:80:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:81:29:81:42 | unsafe_query_3 | sqlx.rs:81:29:81:51 | unsafe_query_3.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:81:29:81:42 | unsafe_query_3 | sqlx.rs:81:29:81:51 | unsafe_query_3.as_str() [&ref] | provenance | MaD:29 |
| sqlx.rs:81:29:81:42 | unsafe_query_3 | sqlx.rs:81:29:81:51 | unsafe_query_3.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:81:29:81:51 | unsafe_query_3.as_str() | sqlx.rs:81:17:81:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:81:29:81:51 | unsafe_query_3.as_str() [&ref] | sqlx.rs:81:17:81:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:82:29:82:42 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:82:29:82:42 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | provenance | MaD:29 |
| sqlx.rs:82:29:82:42 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | sqlx.rs:82:17:82:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | sqlx.rs:82:17:82:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:100:9:100:21 | remote_string | sqlx.rs:102:84:102:96 | remote_string | provenance | |
@@ -334,63 +232,39 @@ edges
| sqlx.rs:100:25:100:85 | ... .text() [Ok] | sqlx.rs:100:25:100:118 | ... .unwrap_or(...) | provenance | MaD:32 |
| sqlx.rs:100:25:100:118 | ... .unwrap_or(...) | sqlx.rs:100:9:100:21 | remote_string | provenance | |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:113:31:113:44 | unsafe_query_1 | provenance | |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:113:31:113:53 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:113:31:113:53 | unsafe_query_1.as_str() | provenance | MaD:29 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:113:31:113:53 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:120:29:120:42 | unsafe_query_1 | provenance | |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:120:29:120:51 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:120:29:120:51 | unsafe_query_1.as_str() | provenance | MaD:29 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:120:29:120:51 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:127:29:127:42 | unsafe_query_1 | provenance | |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:127:29:127:51 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:127:29:127:51 | unsafe_query_1.as_str() | provenance | MaD:29 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:127:29:127:51 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:136:55:136:68 | unsafe_query_1 | provenance | |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:136:55:136:77 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:136:55:136:77 | unsafe_query_1.as_str() | provenance | MaD:29 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:136:55:136:77 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:145:55:145:68 | unsafe_query_1 | provenance | |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:145:55:145:77 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:145:55:145:77 | unsafe_query_1.as_str() | provenance | MaD:29 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:145:55:145:77 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:153:29:153:42 | unsafe_query_1 | provenance | |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:153:29:153:51 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:153:29:153:51 | unsafe_query_1.as_str() | provenance | MaD:29 |
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:153:29:153:51 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:102:26:102:96 | ... + ... | sqlx.rs:102:9:102:22 | unsafe_query_1 | provenance | |
| sqlx.rs:102:26:102:96 | ... + ... | sqlx.rs:102:26:102:102 | ... + ... | provenance | MaD:27 |
| sqlx.rs:102:26:102:96 | ... + ... | sqlx.rs:102:26:102:102 | ... + ... | provenance | MaD:28 |
| sqlx.rs:102:26:102:102 | ... + ... | sqlx.rs:102:9:102:22 | unsafe_query_1 | provenance | |
| sqlx.rs:102:83:102:96 | &remote_string [&ref] | sqlx.rs:102:26:102:96 | ... + ... | provenance | MaD:26 |
| sqlx.rs:102:84:102:96 | remote_string | sqlx.rs:102:83:102:96 | &remote_string [&ref] | provenance | |
| sqlx.rs:113:31:113:44 | unsafe_query_1 | sqlx.rs:113:31:113:53 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:113:31:113:44 | unsafe_query_1 | sqlx.rs:113:31:113:53 | unsafe_query_1.as_str() [&ref] | provenance | MaD:29 |
| sqlx.rs:113:31:113:44 | unsafe_query_1 | sqlx.rs:113:31:113:53 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:113:31:113:53 | unsafe_query_1.as_str() | sqlx.rs:113:17:113:29 | ...::raw_sql | provenance | MaD:22 Sink:MaD:22 |
| sqlx.rs:113:31:113:53 | unsafe_query_1.as_str() [&ref] | sqlx.rs:113:17:113:29 | ...::raw_sql | provenance | MaD:22 Sink:MaD:22 |
| sqlx.rs:120:29:120:42 | unsafe_query_1 | sqlx.rs:120:29:120:51 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:120:29:120:42 | unsafe_query_1 | sqlx.rs:120:29:120:51 | unsafe_query_1.as_str() [&ref] | provenance | MaD:29 |
| sqlx.rs:120:29:120:42 | unsafe_query_1 | sqlx.rs:120:29:120:51 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:120:29:120:51 | unsafe_query_1.as_str() | sqlx.rs:120:17:120:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:120:29:120:51 | unsafe_query_1.as_str() [&ref] | sqlx.rs:120:17:120:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:127:29:127:42 | unsafe_query_1 | sqlx.rs:127:29:127:51 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:127:29:127:42 | unsafe_query_1 | sqlx.rs:127:29:127:51 | unsafe_query_1.as_str() [&ref] | provenance | MaD:29 |
| sqlx.rs:127:29:127:42 | unsafe_query_1 | sqlx.rs:127:29:127:51 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:127:29:127:51 | unsafe_query_1.as_str() | sqlx.rs:127:17:127:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:127:29:127:51 | unsafe_query_1.as_str() [&ref] | sqlx.rs:127:17:127:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:136:55:136:68 | unsafe_query_1 | sqlx.rs:136:55:136:77 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:136:55:136:68 | unsafe_query_1 | sqlx.rs:136:55:136:77 | unsafe_query_1.as_str() [&ref] | provenance | MaD:29 |
| sqlx.rs:136:55:136:68 | unsafe_query_1 | sqlx.rs:136:55:136:77 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:136:55:136:77 | unsafe_query_1.as_str() | sqlx.rs:136:40:136:53 | ...::query_as | provenance | MaD:21 Sink:MaD:21 |
| sqlx.rs:136:55:136:77 | unsafe_query_1.as_str() [&ref] | sqlx.rs:136:40:136:53 | ...::query_as | provenance | MaD:21 Sink:MaD:21 |
| sqlx.rs:145:55:145:68 | unsafe_query_1 | sqlx.rs:145:55:145:77 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:145:55:145:68 | unsafe_query_1 | sqlx.rs:145:55:145:77 | unsafe_query_1.as_str() [&ref] | provenance | MaD:29 |
| sqlx.rs:145:55:145:68 | unsafe_query_1 | sqlx.rs:145:55:145:77 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:145:55:145:77 | unsafe_query_1.as_str() | sqlx.rs:145:40:145:53 | ...::query_as | provenance | MaD:21 Sink:MaD:21 |
| sqlx.rs:145:55:145:77 | unsafe_query_1.as_str() [&ref] | sqlx.rs:145:40:145:53 | ...::query_as | provenance | MaD:21 Sink:MaD:21 |
| sqlx.rs:153:29:153:42 | unsafe_query_1 | sqlx.rs:153:29:153:51 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:153:29:153:42 | unsafe_query_1 | sqlx.rs:153:29:153:51 | unsafe_query_1.as_str() [&ref] | provenance | MaD:29 |
| sqlx.rs:153:29:153:42 | unsafe_query_1 | sqlx.rs:153:29:153:51 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:153:29:153:51 | unsafe_query_1.as_str() | sqlx.rs:153:17:153:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:153:29:153:51 | unsafe_query_1.as_str() [&ref] | sqlx.rs:153:17:153:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:173:9:173:21 | remote_string | sqlx.rs:175:84:175:96 | remote_string | provenance | |
@@ -400,18 +274,14 @@ edges
| sqlx.rs:173:25:173:85 | ... .text() [Ok] | sqlx.rs:173:25:173:118 | ... .unwrap_or(...) | provenance | MaD:32 |
| sqlx.rs:173:25:173:118 | ... .unwrap_or(...) | sqlx.rs:173:9:173:21 | remote_string | provenance | |
| sqlx.rs:175:9:175:22 | unsafe_query_1 | sqlx.rs:188:29:188:42 | unsafe_query_1 | provenance | |
| sqlx.rs:175:9:175:22 | unsafe_query_1 | sqlx.rs:188:29:188:51 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:175:9:175:22 | unsafe_query_1 | sqlx.rs:188:29:188:51 | unsafe_query_1.as_str() | provenance | MaD:29 |
| sqlx.rs:175:9:175:22 | unsafe_query_1 | sqlx.rs:188:29:188:51 | unsafe_query_1.as_str() | provenance | MaD:33 |
| sqlx.rs:175:26:175:96 | ... + ... | sqlx.rs:175:9:175:22 | unsafe_query_1 | provenance | |
| sqlx.rs:175:26:175:96 | ... + ... | sqlx.rs:175:26:175:102 | ... + ... | provenance | MaD:27 |
| sqlx.rs:175:26:175:96 | ... + ... | sqlx.rs:175:26:175:102 | ... + ... | provenance | MaD:28 |
| sqlx.rs:175:26:175:102 | ... + ... | sqlx.rs:175:9:175:22 | unsafe_query_1 | provenance | |
| sqlx.rs:175:83:175:96 | &remote_string [&ref] | sqlx.rs:175:26:175:96 | ... + ... | provenance | MaD:26 |
| sqlx.rs:175:84:175:96 | remote_string | sqlx.rs:175:83:175:96 | &remote_string [&ref] | provenance | |
| sqlx.rs:188:29:188:42 | unsafe_query_1 | sqlx.rs:188:29:188:51 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:188:29:188:42 | unsafe_query_1 | sqlx.rs:188:29:188:51 | unsafe_query_1.as_str() [&ref] | provenance | MaD:29 |
| sqlx.rs:188:29:188:42 | unsafe_query_1 | sqlx.rs:188:29:188:51 | unsafe_query_1.as_str() [&ref] | provenance | MaD:33 |
| sqlx.rs:188:29:188:51 | unsafe_query_1.as_str() | sqlx.rs:188:17:188:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
| sqlx.rs:188:29:188:51 | unsafe_query_1.as_str() [&ref] | sqlx.rs:188:17:188:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
models

View File

@@ -1,12 +1,4 @@
multipleCallTargets
| test_logging.rs:77:20:77:36 | password.as_str() |
| test_logging.rs:78:22:78:38 | password.as_str() |
| test_logging.rs:88:18:88:34 | password.as_str() |
| test_logging.rs:229:30:229:71 | ... .as_str() |
| test_logging.rs:242:16:242:61 | ... .as_bytes() |
| test_logging.rs:245:20:245:65 | ... .as_bytes() |
| test_logging.rs:248:15:248:60 | ... .as_bytes() |
| test_logging.rs:251:15:251:60 | ... .as_bytes() |
| test_storage.rs:13:10:13:33 | ...::from(...) |
| test_storage.rs:17:10:17:35 | ...::from(...) |
| test_storage.rs:21:10:21:35 | ...::from(...) |
@@ -27,42 +19,6 @@ multipleCallTargets
| test_storage.rs:80:25:80:70 | ...::from(...) |
| test_storage.rs:81:25:81:72 | ...::from(...) |
| test_storage.rs:82:26:82:77 | ...::from(...) |
| test_storage.rs:85:27:85:48 | select_query1.as_str() |
| test_storage.rs:86:27:86:48 | select_query2.as_str() |
| test_storage.rs:87:27:87:48 | insert_query1.as_str() |
| test_storage.rs:88:27:88:48 | insert_query2.as_str() |
| test_storage.rs:89:27:89:48 | update_query1.as_str() |
| test_storage.rs:90:27:90:48 | update_query2.as_str() |
| test_storage.rs:91:27:91:48 | update_query3.as_str() |
| test_storage.rs:92:27:92:48 | update_query4.as_str() |
| test_storage.rs:93:27:93:48 | update_query5.as_str() |
| test_storage.rs:94:27:94:48 | update_query6.as_str() |
| test_storage.rs:95:27:95:48 | delete_query1.as_str() |
| test_storage.rs:96:27:96:48 | delete_query2.as_str() |
| test_storage.rs:99:25:99:46 | insert_query1.as_str() |
| test_storage.rs:100:25:100:46 | insert_query2.as_str() |
| test_storage.rs:101:25:101:47 | prepared_query.as_str() |
| test_storage.rs:102:25:102:47 | prepared_query.as_str() |
| test_storage.rs:103:25:103:47 | prepared_query.as_str() |
| test_storage.rs:104:25:104:47 | prepared_query.as_str() |
| test_storage.rs:110:27:110:48 | insert_query1.as_str() |
| test_storage.rs:111:27:111:48 | insert_query2.as_str() |
| test_storage.rs:114:27:114:48 | insert_query1.as_str() |
| test_storage.rs:115:27:115:48 | insert_query2.as_str() |
| test_storage.rs:118:25:118:46 | insert_query1.as_str() |
| test_storage.rs:119:25:119:46 | insert_query2.as_str() |
| test_storage.rs:120:25:120:47 | prepared_query.as_str() |
| test_storage.rs:121:25:121:47 | prepared_query.as_str() |
| test_storage.rs:124:25:124:46 | insert_query1.as_str() |
| test_storage.rs:125:25:125:46 | insert_query2.as_str() |
| test_storage.rs:126:25:126:47 | prepared_query.as_str() |
| test_storage.rs:127:25:127:47 | prepared_query.as_str() |
| test_storage.rs:134:27:134:48 | insert_query1.as_str() |
| test_storage.rs:135:27:135:48 | insert_query2.as_str() |
| test_storage.rs:138:25:138:46 | insert_query1.as_str() |
| test_storage.rs:139:25:139:46 | insert_query2.as_str() |
| test_storage.rs:140:25:140:47 | prepared_query.as_str() |
| test_storage.rs:141:25:141:47 | prepared_query.as_str() |
| test_storage.rs:188:29:188:86 | ...::from(...) |
| test_storage.rs:189:28:189:82 | ...::from(...) |
| test_storage.rs:190:28:190:81 | ...::from(...) |

View File

@@ -147,8 +147,8 @@ edges
| test_logging.rs:99:9:99:10 | m3 | test_logging.rs:100:11:100:18 | MacroExpr | provenance | |
| test_logging.rs:99:22:99:45 | ...::format(...) | test_logging.rs:99:22:99:45 | { ... } | provenance | |
| test_logging.rs:99:22:99:45 | ...::must_use(...) | test_logging.rs:99:9:99:10 | m3 | provenance | |
| test_logging.rs:99:22:99:45 | MacroExpr | test_logging.rs:99:22:99:45 | ...::format(...) | provenance | MaD:23 |
| test_logging.rs:99:22:99:45 | { ... } | test_logging.rs:99:22:99:45 | ...::must_use(...) | provenance | MaD:24 |
| test_logging.rs:99:22:99:45 | MacroExpr | test_logging.rs:99:22:99:45 | ...::format(...) | provenance | MaD:21 |
| test_logging.rs:99:22:99:45 | { ... } | test_logging.rs:99:22:99:45 | ...::must_use(...) | provenance | MaD:22 |
| test_logging.rs:99:38:99:45 | password | test_logging.rs:99:22:99:45 | MacroExpr | provenance | |
| test_logging.rs:100:11:100:18 | MacroExpr | test_logging.rs:100:5:100:9 | ...::log | provenance | MaD:12 Sink:MaD:12 |
| test_logging.rs:118:12:118:41 | MacroExpr | test_logging.rs:118:5:118:10 | ...::log | provenance | MaD:12 Sink:MaD:12 |
@@ -169,8 +169,8 @@ edges
| test_logging.rs:176:34:176:79 | MacroExpr | test_logging.rs:176:33:176:79 | &... [&ref] | provenance | |
| test_logging.rs:176:42:176:78 | ...::format(...) | test_logging.rs:176:42:176:78 | { ... } | provenance | |
| test_logging.rs:176:42:176:78 | ...::must_use(...) | test_logging.rs:176:34:176:79 | MacroExpr | provenance | |
| test_logging.rs:176:42:176:78 | MacroExpr | test_logging.rs:176:42:176:78 | ...::format(...) | provenance | MaD:23 |
| test_logging.rs:176:42:176:78 | { ... } | test_logging.rs:176:42:176:78 | ...::must_use(...) | provenance | MaD:24 |
| test_logging.rs:176:42:176:78 | MacroExpr | test_logging.rs:176:42:176:78 | ...::format(...) | provenance | MaD:21 |
| test_logging.rs:176:42:176:78 | { ... } | test_logging.rs:176:42:176:78 | ...::must_use(...) | provenance | MaD:22 |
| test_logging.rs:176:70:176:78 | password2 | test_logging.rs:176:42:176:78 | MacroExpr | provenance | |
| test_logging.rs:180:35:180:81 | &... | test_logging.rs:180:24:180:33 | log_expect | provenance | MaD:3 Sink:MaD:3 |
| test_logging.rs:180:35:180:81 | &... [&ref] | test_logging.rs:180:24:180:33 | log_expect | provenance | MaD:3 Sink:MaD:3 |
@@ -178,8 +178,8 @@ edges
| test_logging.rs:180:36:180:81 | MacroExpr | test_logging.rs:180:35:180:81 | &... [&ref] | provenance | |
| test_logging.rs:180:44:180:80 | ...::format(...) | test_logging.rs:180:44:180:80 | { ... } | provenance | |
| test_logging.rs:180:44:180:80 | ...::must_use(...) | test_logging.rs:180:36:180:81 | MacroExpr | provenance | |
| test_logging.rs:180:44:180:80 | MacroExpr | test_logging.rs:180:44:180:80 | ...::format(...) | provenance | MaD:23 |
| test_logging.rs:180:44:180:80 | { ... } | test_logging.rs:180:44:180:80 | ...::must_use(...) | provenance | MaD:24 |
| test_logging.rs:180:44:180:80 | MacroExpr | test_logging.rs:180:44:180:80 | ...::format(...) | provenance | MaD:21 |
| test_logging.rs:180:44:180:80 | { ... } | test_logging.rs:180:44:180:80 | ...::must_use(...) | provenance | MaD:22 |
| test_logging.rs:180:72:180:80 | password2 | test_logging.rs:180:44:180:80 | MacroExpr | provenance | |
| test_logging.rs:183:9:183:19 | err_result2 [Err] | test_logging.rs:184:13:184:23 | err_result2 [Err] | provenance | |
| test_logging.rs:183:47:183:68 | Err(...) [Err] | test_logging.rs:183:9:183:19 | err_result2 [Err] | provenance | |
@@ -230,64 +230,52 @@ edges
| test_logging.rs:226:36:226:59 | ...::Some(...) [Some] | test_logging.rs:226:13:226:28 | ...::assert_failed [Some] | provenance | MaD:10 |
| test_logging.rs:226:36:226:59 | MacroExpr | test_logging.rs:226:36:226:59 | ...::Some(...) [Some] | provenance | |
| test_logging.rs:226:52:226:59 | password | test_logging.rs:226:36:226:59 | MacroExpr | provenance | |
| test_logging.rs:229:30:229:62 | MacroExpr | test_logging.rs:229:30:229:71 | ... .as_str() [&ref] | provenance | MaD:22 |
| test_logging.rs:229:30:229:62 | MacroExpr | test_logging.rs:229:30:229:71 | ... .as_str() [&ref] | provenance | MaD:20 |
| test_logging.rs:229:30:229:62 | MacroExpr | test_logging.rs:229:30:229:71 | ... .as_str() [&ref] | provenance | MaD:22 |
| test_logging.rs:229:30:229:71 | ... .as_str() | test_logging.rs:229:23:229:28 | expect | provenance | MaD:2 Sink:MaD:2 |
| test_logging.rs:229:30:229:71 | ... .as_str() | test_logging.rs:229:23:229:28 | expect | provenance | MaD:2 Sink:MaD:2 |
| test_logging.rs:229:30:229:71 | ... .as_str() [&ref] | test_logging.rs:229:23:229:28 | expect | provenance | MaD:2 Sink:MaD:2 |
| test_logging.rs:229:30:229:71 | ... .as_str() [&ref] | test_logging.rs:229:23:229:28 | expect | provenance | MaD:2 Sink:MaD:2 |
| test_logging.rs:229:38:229:61 | ...::format(...) | test_logging.rs:229:38:229:61 | { ... } | provenance | |
| test_logging.rs:229:38:229:61 | ...::must_use(...) | test_logging.rs:229:30:229:62 | MacroExpr | provenance | |
| test_logging.rs:229:38:229:61 | ...::must_use(...) | test_logging.rs:229:30:229:71 | ... .as_str() | provenance | MaD:22 |
| test_logging.rs:229:38:229:61 | ...::must_use(...) | test_logging.rs:229:30:229:71 | ... .as_str() | provenance | MaD:20 |
| test_logging.rs:229:38:229:61 | ...::must_use(...) | test_logging.rs:229:30:229:71 | ... .as_str() | provenance | MaD:22 |
| test_logging.rs:229:38:229:61 | MacroExpr | test_logging.rs:229:38:229:61 | ...::format(...) | provenance | MaD:23 |
| test_logging.rs:229:38:229:61 | { ... } | test_logging.rs:229:38:229:61 | ...::must_use(...) | provenance | MaD:24 |
| test_logging.rs:229:38:229:61 | MacroExpr | test_logging.rs:229:38:229:61 | ...::format(...) | provenance | MaD:21 |
| test_logging.rs:229:38:229:61 | { ... } | test_logging.rs:229:38:229:61 | ...::must_use(...) | provenance | MaD:22 |
| test_logging.rs:229:54:229:61 | password | test_logging.rs:229:38:229:61 | MacroExpr | provenance | |
| test_logging.rs:242:16:242:50 | MacroExpr | test_logging.rs:242:16:242:61 | ... .as_bytes() [&ref] | provenance | MaD:21 |
| test_logging.rs:242:16:242:50 | MacroExpr | test_logging.rs:242:16:242:61 | ... .as_bytes() [&ref] | provenance | MaD:19 |
| test_logging.rs:242:16:242:61 | ... .as_bytes() | test_logging.rs:242:10:242:14 | write | provenance | MaD:7 Sink:MaD:7 |
| test_logging.rs:242:16:242:61 | ... .as_bytes() [&ref] | test_logging.rs:242:10:242:14 | write | provenance | MaD:7 Sink:MaD:7 |
| test_logging.rs:242:24:242:49 | ...::format(...) | test_logging.rs:242:24:242:49 | { ... } | provenance | |
| test_logging.rs:242:24:242:49 | ...::must_use(...) | test_logging.rs:242:16:242:50 | MacroExpr | provenance | |
| test_logging.rs:242:24:242:49 | ...::must_use(...) | test_logging.rs:242:16:242:61 | ... .as_bytes() | provenance | MaD:21 |
| test_logging.rs:242:24:242:49 | ...::must_use(...) | test_logging.rs:242:16:242:61 | ... .as_bytes() | provenance | MaD:19 |
| test_logging.rs:242:24:242:49 | MacroExpr | test_logging.rs:242:24:242:49 | ...::format(...) | provenance | MaD:23 |
| test_logging.rs:242:24:242:49 | { ... } | test_logging.rs:242:24:242:49 | ...::must_use(...) | provenance | MaD:24 |
| test_logging.rs:242:24:242:49 | MacroExpr | test_logging.rs:242:24:242:49 | ...::format(...) | provenance | MaD:21 |
| test_logging.rs:242:24:242:49 | { ... } | test_logging.rs:242:24:242:49 | ...::must_use(...) | provenance | MaD:22 |
| test_logging.rs:242:42:242:49 | password | test_logging.rs:242:24:242:49 | MacroExpr | provenance | |
| test_logging.rs:245:20:245:54 | MacroExpr | test_logging.rs:245:20:245:65 | ... .as_bytes() [&ref] | provenance | MaD:21 |
| test_logging.rs:245:20:245:54 | MacroExpr | test_logging.rs:245:20:245:65 | ... .as_bytes() [&ref] | provenance | MaD:19 |
| test_logging.rs:245:20:245:65 | ... .as_bytes() | test_logging.rs:245:10:245:18 | write_all | provenance | MaD:8 Sink:MaD:8 |
| test_logging.rs:245:20:245:65 | ... .as_bytes() [&ref] | test_logging.rs:245:10:245:18 | write_all | provenance | MaD:8 Sink:MaD:8 |
| test_logging.rs:245:28:245:53 | ...::format(...) | test_logging.rs:245:28:245:53 | { ... } | provenance | |
| test_logging.rs:245:28:245:53 | ...::must_use(...) | test_logging.rs:245:20:245:54 | MacroExpr | provenance | |
| test_logging.rs:245:28:245:53 | ...::must_use(...) | test_logging.rs:245:20:245:65 | ... .as_bytes() | provenance | MaD:21 |
| test_logging.rs:245:28:245:53 | ...::must_use(...) | test_logging.rs:245:20:245:65 | ... .as_bytes() | provenance | MaD:19 |
| test_logging.rs:245:28:245:53 | MacroExpr | test_logging.rs:245:28:245:53 | ...::format(...) | provenance | MaD:23 |
| test_logging.rs:245:28:245:53 | { ... } | test_logging.rs:245:28:245:53 | ...::must_use(...) | provenance | MaD:24 |
| test_logging.rs:245:28:245:53 | MacroExpr | test_logging.rs:245:28:245:53 | ...::format(...) | provenance | MaD:21 |
| test_logging.rs:245:28:245:53 | { ... } | test_logging.rs:245:28:245:53 | ...::must_use(...) | provenance | MaD:22 |
| test_logging.rs:245:46:245:53 | password | test_logging.rs:245:28:245:53 | MacroExpr | provenance | |
| test_logging.rs:248:15:248:49 | MacroExpr | test_logging.rs:248:15:248:60 | ... .as_bytes() [&ref] | provenance | MaD:21 |
| test_logging.rs:248:15:248:49 | MacroExpr | test_logging.rs:248:15:248:60 | ... .as_bytes() [&ref] | provenance | MaD:19 |
| test_logging.rs:248:15:248:60 | ... .as_bytes() | test_logging.rs:248:9:248:13 | write | provenance | MaD:7 Sink:MaD:7 |
| test_logging.rs:248:15:248:60 | ... .as_bytes() [&ref] | test_logging.rs:248:9:248:13 | write | provenance | MaD:7 Sink:MaD:7 |
| test_logging.rs:248:23:248:48 | ...::format(...) | test_logging.rs:248:23:248:48 | { ... } | provenance | |
| test_logging.rs:248:23:248:48 | ...::must_use(...) | test_logging.rs:248:15:248:49 | MacroExpr | provenance | |
| test_logging.rs:248:23:248:48 | ...::must_use(...) | test_logging.rs:248:15:248:60 | ... .as_bytes() | provenance | MaD:21 |
| test_logging.rs:248:23:248:48 | ...::must_use(...) | test_logging.rs:248:15:248:60 | ... .as_bytes() | provenance | MaD:19 |
| test_logging.rs:248:23:248:48 | MacroExpr | test_logging.rs:248:23:248:48 | ...::format(...) | provenance | MaD:23 |
| test_logging.rs:248:23:248:48 | { ... } | test_logging.rs:248:23:248:48 | ...::must_use(...) | provenance | MaD:24 |
| test_logging.rs:248:23:248:48 | MacroExpr | test_logging.rs:248:23:248:48 | ...::format(...) | provenance | MaD:21 |
| test_logging.rs:248:23:248:48 | { ... } | test_logging.rs:248:23:248:48 | ...::must_use(...) | provenance | MaD:22 |
| test_logging.rs:248:41:248:48 | password | test_logging.rs:248:23:248:48 | MacroExpr | provenance | |
| test_logging.rs:251:15:251:49 | MacroExpr | test_logging.rs:251:15:251:60 | ... .as_bytes() [&ref] | provenance | MaD:21 |
| test_logging.rs:251:15:251:49 | MacroExpr | test_logging.rs:251:15:251:60 | ... .as_bytes() [&ref] | provenance | MaD:19 |
| test_logging.rs:251:15:251:60 | ... .as_bytes() | test_logging.rs:251:9:251:13 | write | provenance | MaD:6 Sink:MaD:6 |
| test_logging.rs:251:15:251:60 | ... .as_bytes() [&ref] | test_logging.rs:251:9:251:13 | write | provenance | MaD:6 Sink:MaD:6 |
| test_logging.rs:251:23:251:48 | ...::format(...) | test_logging.rs:251:23:251:48 | { ... } | provenance | |
| test_logging.rs:251:23:251:48 | ...::must_use(...) | test_logging.rs:251:15:251:49 | MacroExpr | provenance | |
| test_logging.rs:251:23:251:48 | ...::must_use(...) | test_logging.rs:251:15:251:60 | ... .as_bytes() | provenance | MaD:21 |
| test_logging.rs:251:23:251:48 | ...::must_use(...) | test_logging.rs:251:15:251:60 | ... .as_bytes() | provenance | MaD:19 |
| test_logging.rs:251:23:251:48 | MacroExpr | test_logging.rs:251:23:251:48 | ...::format(...) | provenance | MaD:23 |
| test_logging.rs:251:23:251:48 | { ... } | test_logging.rs:251:23:251:48 | ...::must_use(...) | provenance | MaD:24 |
| test_logging.rs:251:23:251:48 | MacroExpr | test_logging.rs:251:23:251:48 | ...::format(...) | provenance | MaD:21 |
| test_logging.rs:251:23:251:48 | { ... } | test_logging.rs:251:23:251:48 | ...::must_use(...) | provenance | MaD:22 |
| test_logging.rs:251:41:251:48 | password | test_logging.rs:251:23:251:48 | MacroExpr | provenance | |
models
| 1 | Sink: <core::option::Option as log_err::LogErrOption>::log_expect; Argument[0]; log-injection |
@@ -310,10 +298,8 @@ models
| 18 | Summary: <_ as core::ops::arith::Add>::add; Argument[0]; ReturnValue; taint |
| 19 | Summary: <alloc::string::String>::as_bytes; Argument[self]; ReturnValue; value |
| 20 | Summary: <alloc::string::String>::as_str; Argument[self]; ReturnValue; value |
| 21 | Summary: <core::str>::as_bytes; Argument[self]; ReturnValue; value |
| 22 | Summary: <core::str>::as_str; Argument[self]; ReturnValue; value |
| 23 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
| 24 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
| 21 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
| 22 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
nodes
| test_logging.rs:42:5:42:10 | ...::log | semmle.label | ...::log |
| test_logging.rs:42:12:42:35 | MacroExpr | semmle.label | MacroExpr |

View File

@@ -9,25 +9,15 @@
| test_storage.rs:204:31:204:37 | prepare | test_storage.rs:190:86:190:103 | get_phone_number(...) | test_storage.rs:204:31:204:37 | prepare | This database operation may read or write unencrypted sensitive data from $@. | test_storage.rs:190:86:190:103 | get_phone_number(...) | get_phone_number(...) |
edges
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:100:25:100:37 | insert_query2 | provenance | |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:100:25:100:46 | insert_query2.as_str() | provenance | MaD:11 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:100:25:100:46 | insert_query2.as_str() | provenance | MaD:10 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:100:25:100:46 | insert_query2.as_str() | provenance | MaD:11 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:115:27:115:39 | insert_query2 | provenance | |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:115:27:115:48 | insert_query2.as_str() | provenance | MaD:11 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:115:27:115:48 | insert_query2.as_str() | provenance | MaD:10 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:115:27:115:48 | insert_query2.as_str() | provenance | MaD:11 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:119:25:119:37 | insert_query2 | provenance | |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:119:25:119:46 | insert_query2.as_str() | provenance | MaD:11 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:119:25:119:46 | insert_query2.as_str() | provenance | MaD:10 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:119:25:119:46 | insert_query2.as_str() | provenance | MaD:11 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:125:25:125:37 | insert_query2 | provenance | |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:125:25:125:46 | insert_query2.as_str() | provenance | MaD:11 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:125:25:125:46 | insert_query2.as_str() | provenance | MaD:10 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:125:25:125:46 | insert_query2.as_str() | provenance | MaD:11 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:139:25:139:37 | insert_query2 | provenance | |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:139:25:139:46 | insert_query2.as_str() | provenance | MaD:11 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:139:25:139:46 | insert_query2.as_str() | provenance | MaD:10 |
| test_storage.rs:71:9:71:21 | insert_query2 | test_storage.rs:139:25:139:46 | insert_query2.as_str() | provenance | MaD:11 |
| test_storage.rs:71:25:71:114 | ... + ... | test_storage.rs:71:9:71:21 | insert_query2 | provenance | |
| test_storage.rs:71:25:71:114 | ... + ... | test_storage.rs:71:25:71:121 | ... + ... | provenance | MaD:8 |
| test_storage.rs:71:25:71:114 | ... + ... | test_storage.rs:71:25:71:121 | ... + ... | provenance | MaD:9 |
@@ -39,29 +29,19 @@ edges
| test_storage.rs:71:96:71:114 | &... [&ref] | test_storage.rs:71:25:71:114 | ... + ... | provenance | MaD:6 |
| test_storage.rs:71:97:71:114 | get_phone_number(...) | test_storage.rs:71:96:71:114 | &... | provenance | Config |
| test_storage.rs:71:97:71:114 | get_phone_number(...) | test_storage.rs:71:96:71:114 | &... [&ref] | provenance | |
| test_storage.rs:100:25:100:37 | insert_query2 | test_storage.rs:100:25:100:46 | insert_query2.as_str() [&ref] | provenance | MaD:11 |
| test_storage.rs:100:25:100:37 | insert_query2 | test_storage.rs:100:25:100:46 | insert_query2.as_str() [&ref] | provenance | MaD:10 |
| test_storage.rs:100:25:100:37 | insert_query2 | test_storage.rs:100:25:100:46 | insert_query2.as_str() [&ref] | provenance | MaD:11 |
| test_storage.rs:100:25:100:46 | insert_query2.as_str() | test_storage.rs:100:13:100:23 | ...::query | provenance | MaD:4 Sink:MaD:4 |
| test_storage.rs:100:25:100:46 | insert_query2.as_str() [&ref] | test_storage.rs:100:13:100:23 | ...::query | provenance | MaD:4 Sink:MaD:4 |
| test_storage.rs:115:27:115:39 | insert_query2 | test_storage.rs:115:27:115:48 | insert_query2.as_str() [&ref] | provenance | MaD:11 |
| test_storage.rs:115:27:115:39 | insert_query2 | test_storage.rs:115:27:115:48 | insert_query2.as_str() [&ref] | provenance | MaD:10 |
| test_storage.rs:115:27:115:39 | insert_query2 | test_storage.rs:115:27:115:48 | insert_query2.as_str() [&ref] | provenance | MaD:11 |
| test_storage.rs:115:27:115:48 | insert_query2.as_str() | test_storage.rs:115:13:115:25 | ...::raw_sql | provenance | MaD:5 Sink:MaD:5 |
| test_storage.rs:115:27:115:48 | insert_query2.as_str() [&ref] | test_storage.rs:115:13:115:25 | ...::raw_sql | provenance | MaD:5 Sink:MaD:5 |
| test_storage.rs:119:25:119:37 | insert_query2 | test_storage.rs:119:25:119:46 | insert_query2.as_str() [&ref] | provenance | MaD:11 |
| test_storage.rs:119:25:119:37 | insert_query2 | test_storage.rs:119:25:119:46 | insert_query2.as_str() [&ref] | provenance | MaD:10 |
| test_storage.rs:119:25:119:37 | insert_query2 | test_storage.rs:119:25:119:46 | insert_query2.as_str() [&ref] | provenance | MaD:11 |
| test_storage.rs:119:25:119:46 | insert_query2.as_str() | test_storage.rs:119:13:119:23 | ...::query | provenance | MaD:4 Sink:MaD:4 |
| test_storage.rs:119:25:119:46 | insert_query2.as_str() [&ref] | test_storage.rs:119:13:119:23 | ...::query | provenance | MaD:4 Sink:MaD:4 |
| test_storage.rs:125:25:125:37 | insert_query2 | test_storage.rs:125:25:125:46 | insert_query2.as_str() [&ref] | provenance | MaD:11 |
| test_storage.rs:125:25:125:37 | insert_query2 | test_storage.rs:125:25:125:46 | insert_query2.as_str() [&ref] | provenance | MaD:10 |
| test_storage.rs:125:25:125:37 | insert_query2 | test_storage.rs:125:25:125:46 | insert_query2.as_str() [&ref] | provenance | MaD:11 |
| test_storage.rs:125:25:125:46 | insert_query2.as_str() | test_storage.rs:125:13:125:23 | ...::query | provenance | MaD:4 Sink:MaD:4 |
| test_storage.rs:125:25:125:46 | insert_query2.as_str() [&ref] | test_storage.rs:125:13:125:23 | ...::query | provenance | MaD:4 Sink:MaD:4 |
| test_storage.rs:139:25:139:37 | insert_query2 | test_storage.rs:139:25:139:46 | insert_query2.as_str() [&ref] | provenance | MaD:11 |
| test_storage.rs:139:25:139:37 | insert_query2 | test_storage.rs:139:25:139:46 | insert_query2.as_str() [&ref] | provenance | MaD:10 |
| test_storage.rs:139:25:139:37 | insert_query2 | test_storage.rs:139:25:139:46 | insert_query2.as_str() [&ref] | provenance | MaD:11 |
| test_storage.rs:139:25:139:46 | insert_query2.as_str() | test_storage.rs:139:13:139:23 | ...::query | provenance | MaD:4 Sink:MaD:4 |
| test_storage.rs:139:25:139:46 | insert_query2.as_str() [&ref] | test_storage.rs:139:13:139:23 | ...::query | provenance | MaD:4 Sink:MaD:4 |
| test_storage.rs:189:9:189:24 | insert_query_bad | test_storage.rs:194:25:194:40 | insert_query_bad | provenance | |
@@ -112,7 +92,6 @@ models
| 8 | Summary: <_ as core::ops::arith::Add>::add; Argument[self]; ReturnValue; taint |
| 9 | Summary: <alloc::string::String as core::ops::arith::Add>::add; Argument[self]; ReturnValue; value |
| 10 | Summary: <alloc::string::String>::as_str; Argument[self]; ReturnValue; value |
| 11 | Summary: <core::str>::as_str; Argument[self]; ReturnValue; value |
nodes
| test_storage.rs:71:9:71:21 | insert_query2 | semmle.label | insert_query2 |
| test_storage.rs:71:25:71:114 | ... + ... | semmle.label | ... + ... |

View File

@@ -3,7 +3,4 @@ multipleCallTargets
| deallocation.rs:261:11:261:29 | ...::from(...) |
| lifetime.rs:610:13:610:31 | ...::from(...) |
| lifetime.rs:611:13:611:31 | ...::from(...) |
| lifetime.rs:612:27:612:38 | foo.as_str() |
| lifetime.rs:612:41:612:52 | bar.as_str() |
| lifetime.rs:628:13:628:31 | ...::from(...) |
| lifetime.rs:629:32:629:43 | baz.as_str() |

View File

@@ -511,33 +511,35 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
/** Provides the input to `IsInstantiationOf`. */
signature module IsInstantiationOfInputSig<HasTypeTreeSig App, HasTypeTreeSig Constraint> {
/**
* Holds if `abs` is a type abstraction, `tm` occurs in the scope of
* Holds if `abs` is a type abstraction, `constraint` occurs in the scope of
* `abs`, and `app` is potentially an application/instantiation of `abs`.
*
* For example:
* ```rust
* impl<A> Foo<A, A> {
* // ^^^ `abs`
* // ^^^^^^^^^ `tm`
* // ^^^^^^^^^ `constraint`
* fn bar(self) { ... }
* }
* // ...
* foo.bar();
* // ^^^ `app`
* ```
* Here `abs` introduces the type parameter `A` and `tm` occurs in the
* scope of `abs` (i.e., `A` is bound in `tm` by `abs`). On the last line,
* Here `abs` introduces the type parameter `A` and `constraint` occurs in the
* scope of `abs` (i.e., `A` is bound in `constraint` by `abs`). On the last line,
* accessing the `bar` method of `foo` potentially instantiates the `impl`
* block with a type argument for `A`.
*/
predicate potentialInstantiationOf(App app, TypeAbstraction abs, Constraint tm);
predicate potentialInstantiationOf(App app, TypeAbstraction abs, Constraint constraint);
/**
* Holds if `constraint` might occur as the third argument of
* `potentialInstantiationOf`. Defaults to simply projecting the third
* argument of `potentialInstantiationOf`.
*/
default predicate relevantTypeMention(Constraint tm) { potentialInstantiationOf(_, _, tm) }
default predicate relevantConstraint(Constraint constraint) {
potentialInstantiationOf(_, _, constraint)
}
}
/**
@@ -550,38 +552,48 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
{
private import Input
/** Gets the `i`th path in `tm` per some arbitrary order. */
/** Gets the `i`th path in `constraint` per some arbitrary order. */
pragma[nomagic]
private TypePath getNthPath(Constraint tm, int i) {
private TypePath getNthPath(Constraint constraint, int i) {
result =
rank[i + 1](TypePath path | exists(tm.getTypeAt(path)) and relevantTypeMention(tm) | path)
rank[i + 1](TypePath path |
exists(constraint.getTypeAt(path)) and relevantConstraint(constraint)
|
path
)
}
pragma[nomagic]
private Type resolveTypeAt(App app, TypeAbstraction abs, Constraint constraint, TypePath path) {
potentialInstantiationOf(app, abs, constraint) and
result = constraint.getTypeAt(path)
}
pragma[nomagic]
private Type resolveNthTypeAt(
App app, TypeAbstraction abs, Constraint tm, int i, TypePath path
App app, TypeAbstraction abs, Constraint constraint, int i, TypePath path
) {
potentialInstantiationOf(app, abs, tm) and
path = getNthPath(tm, i) and
result = tm.getTypeAt(path)
path = getNthPath(constraint, i) and
result = resolveTypeAt(app, abs, constraint, path)
}
pragma[nomagic]
private predicate satisfiesConcreteTypesFromIndex(
App app, TypeAbstraction abs, Constraint tm, int i
App app, TypeAbstraction abs, Constraint constraint, int i
) {
exists(Type t, TypePath path |
t = resolveNthTypeAt(app, abs, tm, i, path) and
t = resolveNthTypeAt(app, abs, constraint, i, path) and
if t = abs.getATypeParameter() then any() else app.getTypeAt(path) = t
) and
// Recurse unless we are at the first path
if i = 0 then any() else satisfiesConcreteTypesFromIndex(app, abs, tm, i - 1)
if i = 0 then any() else satisfiesConcreteTypesFromIndex(app, abs, constraint, i - 1)
}
/** Holds if all the concrete types in `tm` also occur in `app`. */
/** Holds if all the concrete types in `constraint` also occur in `app`. */
pragma[nomagic]
private predicate satisfiesConcreteTypes(App app, TypeAbstraction abs, Constraint tm) {
satisfiesConcreteTypesFromIndex(app, abs, tm, max(int i | exists(getNthPath(tm, i))))
private predicate satisfiesConcreteTypes(App app, TypeAbstraction abs, Constraint constraint) {
satisfiesConcreteTypesFromIndex(app, abs, constraint,
max(int i | exists(getNthPath(constraint, i))))
}
private TypeParameter getNthTypeParameter(TypeAbstraction abs, int i) {
@@ -594,70 +606,74 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
}
/**
* Gets the path to the `i`th occurrence of `tp` within `tm` per some
* Gets the path to the `i`th occurrence of `tp` within `constraint` per some
* arbitrary order, if any.
*/
pragma[nomagic]
private TypePath getNthTypeParameterPath(Constraint tm, TypeParameter tp, int i) {
private TypePath getNthTypeParameterPath(Constraint constraint, TypeParameter tp, int i) {
result =
rank[i + 1](TypePath path | tp = tm.getTypeAt(path) and relevantTypeMention(tm) | path)
rank[i + 1](TypePath path |
tp = constraint.getTypeAt(path) and relevantConstraint(constraint)
|
path
)
}
pragma[nomagic]
private predicate typeParametersEqualFromIndexBase(
App app, TypeAbstraction abs, Constraint tm, TypeParameter tp, TypePath path
App app, TypeAbstraction abs, Constraint constraint, TypeParameter tp, TypePath path
) {
path = getNthTypeParameterPath(tm, tp, 0) and
satisfiesConcreteTypes(app, abs, tm) and
path = getNthTypeParameterPath(constraint, tp, 0) and
satisfiesConcreteTypes(app, abs, constraint) and
// no need to compute this predicate if there is only one path
exists(getNthTypeParameterPath(tm, tp, 1))
exists(getNthTypeParameterPath(constraint, tp, 1))
}
pragma[nomagic]
private predicate typeParametersEqualFromIndex(
App app, TypeAbstraction abs, Constraint tm, TypeParameter tp, Type t, int i
App app, TypeAbstraction abs, Constraint constraint, TypeParameter tp, Type t, int i
) {
exists(TypePath path |
t = app.getTypeAt(path) and
if i = 0
then typeParametersEqualFromIndexBase(app, abs, tm, tp, path)
then typeParametersEqualFromIndexBase(app, abs, constraint, tp, path)
else (
typeParametersEqualFromIndex(app, abs, tm, tp, t, i - 1) and
path = getNthTypeParameterPath(tm, tp, i)
typeParametersEqualFromIndex(app, abs, constraint, tp, t, i - 1) and
path = getNthTypeParameterPath(constraint, tp, i)
)
)
}
private predicate typeParametersEqual(
App app, TypeAbstraction abs, Constraint tm, TypeParameter tp
App app, TypeAbstraction abs, Constraint constraint, TypeParameter tp
) {
satisfiesConcreteTypes(app, abs, tm) and
satisfiesConcreteTypes(app, abs, constraint) and
tp = getNthTypeParameter(abs, _) and
(
not exists(getNthTypeParameterPath(tm, tp, _))
not exists(getNthTypeParameterPath(constraint, tp, _))
or
exists(int n | n = max(int i | exists(getNthTypeParameterPath(tm, tp, i))) |
exists(int n | n = max(int i | exists(getNthTypeParameterPath(constraint, tp, i))) |
// If the largest index is 0, then there are no equalities to check as
// the type parameter only occurs once.
if n = 0 then any() else typeParametersEqualFromIndex(app, abs, tm, tp, _, n)
if n = 0 then any() else typeParametersEqualFromIndex(app, abs, constraint, tp, _, n)
)
)
}
private predicate typeParametersHaveEqualInstantiationFromIndex(
App app, TypeAbstraction abs, Constraint tm, int i
App app, TypeAbstraction abs, Constraint constraint, int i
) {
exists(TypeParameter tp | tp = getNthTypeParameter(abs, i) |
typeParametersEqual(app, abs, tm, tp) and
typeParametersEqual(app, abs, constraint, tp) and
if i = 0
then any()
else typeParametersHaveEqualInstantiationFromIndex(app, abs, tm, i - 1)
else typeParametersHaveEqualInstantiationFromIndex(app, abs, constraint, i - 1)
)
}
/**
* Holds if `app` is a possible instantiation of `tm`. That is, by making
* appropriate substitutions for the free type parameters in `tm` given by
* Holds if `app` is a possible instantiation of `constraint`. That is, by making
* appropriate substitutions for the free type parameters in `constraint` given by
* `abs`, it is possible to obtain `app`.
*
* For instance, if `A` and `B` are free type parameters we have:
@@ -668,10 +684,10 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
* - `Pair<int, string>` is _not_ an instantiation of `Pair<string, string>`
*/
pragma[nomagic]
predicate isInstantiationOf(App app, TypeAbstraction abs, Constraint tm) {
predicate isInstantiationOf(App app, TypeAbstraction abs, Constraint constraint) {
// We only need to check equality if the concrete types are satisfied.
satisfiesConcreteTypes(app, abs, tm) and
// Check if all the places where the same type parameter occurs in `tm`
satisfiesConcreteTypes(app, abs, constraint) and
// Check if all the places where the same type parameter occurs in `constraint`
// are equal in `app`.
//
// TODO: As of now this only checks equality at the root of the types
@@ -681,30 +697,22 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
not exists(getNthTypeParameter(abs, _))
or
exists(int n | n = max(int i | exists(getNthTypeParameter(abs, i))) |
typeParametersHaveEqualInstantiationFromIndex(app, abs, tm, n)
typeParametersHaveEqualInstantiationFromIndex(app, abs, constraint, n)
)
)
}
/**
* Holds if `app` is _not_ a possible instantiation of `tm`.
* Holds if `app` is _not_ a possible instantiation of `constraint`.
*/
pragma[nomagic]
predicate isNotInstantiationOf(App app, TypeAbstraction abs, Constraint tm) {
// `app` and `tm` differ on a concrete type
predicate isNotInstantiationOf(App app, TypeAbstraction abs, Constraint constraint) {
// `app` and `constraint` differ on a concrete type
exists(Type t, TypePath path |
t = resolveNthTypeAt(app, abs, tm, _, path) and
t = resolveTypeAt(app, abs, constraint, path) and
not t = abs.getATypeParameter() and
not path.isEmpty() and
app.getTypeAt(path) != t
)
or
// `app` uses inconsistent type parameter instantiations
exists(TypeParameter tp |
potentialInstantiationOf(app, abs, tm) and
app.getTypeAt(getNthTypeParameterPath(tm, tp, _)) !=
app.getTypeAt(getNthTypeParameterPath(tm, tp, _))
)
}
}
@@ -956,7 +964,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
)
}
predicate relevantTypeMention(TypeMentionTypeTree constraint) {
predicate relevantConstraint(TypeMentionTypeTree constraint) {
rootTypesSatisfaction(_, _, _, constraint, _)
}
}
@@ -1121,29 +1129,6 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
bindingset[apos]
bindingset[dpos]
predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos);
/**
* Holds if matching an inferred type `t` at `path` inside an access at `apos`
* against the declaration `target` means that the type should be adjusted to
* `tAdj` at `pathAdj`.
*
* For example, in
*
* ```csharp
* void M(int? i) {}
* M(42);
* ```
*
* the inferred type of `42` is `int`, but it should be adjusted to `int?`
* when matching against `M`.
*/
bindingset[apos, target, path, t]
default predicate adjustAccessType(
AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, Type tAdj
) {
pathAdj = path and
tAdj = t
}
}
/**
@@ -1155,22 +1140,6 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
module MatchingWithEnvironment<MatchingWithEnvironmentInputSig Input> {
private import Input
/**
* Holds if `a` targets `target` in environment `e` and the type for `apos` at `path`
* in `a` is `t` after adjustment by `target`.
*/
pragma[nomagic]
private predicate adjustedAccessType(
Access a, AccessEnvironment e, AccessPosition apos, Declaration target, TypePath path,
Type t
) {
target = a.getTarget(e) and
exists(TypePath path0, Type t0 |
t0 = a.getInferredType(e, apos, path0) and
adjustAccessType(apos, target, path0, t0, path, t)
)
}
/**
* Gets the type of the type argument at `path` in `a` that corresponds to
* the type parameter `tp` in `target`, if any.
@@ -1189,6 +1158,16 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
)
}
pragma[nomagic]
private predicate directTypeMatch0(
Access a, AccessEnvironment e, Declaration target, DeclarationPosition dpos,
TypePath pathToTypeParam, TypeParameter tp
) {
not exists(getTypeArgument(a, target, tp, _)) and
tp = target.getDeclaredType(dpos, pathToTypeParam) and
target = a.getTarget(e)
}
/**
* Holds if the type `t` at `path` of `a` in environment `e` matches the type
* parameter `tp` of `target`.
@@ -1197,11 +1176,10 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
private predicate directTypeMatch(
Access a, AccessEnvironment e, Declaration target, TypePath path, Type t, TypeParameter tp
) {
not exists(getTypeArgument(a, target, tp, _)) and
exists(AccessPosition apos, DeclarationPosition dpos, TypePath pathToTypeParam |
tp = target.getDeclaredType(dpos, pathToTypeParam) and
directTypeMatch0(a, e, target, dpos, pathToTypeParam, tp) and
accessDeclarationPositionMatch(apos, dpos) and
adjustedAccessType(a, e, apos, target, pathToTypeParam.appendInverse(path), t)
t = a.getInferredType(e, apos, pathToTypeParam.appendInverse(path))
)
}
@@ -1214,7 +1192,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
Access a, AccessEnvironment e, AccessPosition apos, Type base
) {
exists(Declaration target, DeclarationPosition dpos |
adjustedAccessType(a, e, apos, target, _, _) and
target = a.getTarget(e) and
accessDeclarationPositionMatch(apos, dpos) and
declarationBaseType(target, dpos, base, _, _)
)
@@ -1291,10 +1269,8 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
}
private newtype TRelevantAccess =
MkRelevantAccess(
Access a, AccessEnvironment e, Declaration target, AccessPosition apos, TypePath path
) {
relevantAccessConstraint(a, e, target, apos, path, _)
MkRelevantAccess(Access a, AccessEnvironment e, AccessPosition apos, TypePath path) {
relevantAccessConstraint(a, e, _, apos, path, _)
}
/**
@@ -1304,18 +1280,19 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
private class RelevantAccess extends MkRelevantAccess {
Access a;
AccessEnvironment e;
Declaration target;
AccessPosition apos;
TypePath path;
RelevantAccess() { this = MkRelevantAccess(a, e, target, apos, path) }
RelevantAccess() { this = MkRelevantAccess(a, e, apos, path) }
Type getTypeAt(TypePath suffix) {
adjustedAccessType(a, e, apos, target, path.appendInverse(suffix), result)
result = a.getInferredType(e, apos, path.appendInverse(suffix))
}
/** Holds if this relevant access should satisfy `constraint`. */
Type getConstraint() { relevantAccessConstraint(a, e, target, apos, path, result) }
/** Gets the constraint that this relevant access should satisfy. */
Type getConstraint(Declaration target) {
relevantAccessConstraint(a, e, target, apos, path, result)
}
string toString() {
result = a.toString() + ", " + apos.toString() + ", " + path.toString()
@@ -1328,7 +1305,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
SatisfiesConstraintInputSig<RelevantAccess>
{
predicate relevantConstraint(RelevantAccess at, Type constraint) {
constraint = at.getConstraint()
constraint = at.getConstraint(_)
}
}
@@ -1336,8 +1313,12 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
Access a, AccessEnvironment e, Declaration target, AccessPosition apos, TypePath prefix,
Type constraint, TypePath path, Type t
) {
SatisfiesConstraint<RelevantAccess, SatisfiesConstraintInput>::satisfiesConstraintType(MkRelevantAccess(a,
e, target, apos, prefix), constraint, path, t)
exists(RelevantAccess ra |
ra = MkRelevantAccess(a, e, apos, prefix) and
SatisfiesConstraint<RelevantAccess, SatisfiesConstraintInput>::satisfiesConstraintType(ra,
constraint, path, t) and
constraint = ra.getConstraint(target)
)
}
}
@@ -1628,29 +1609,6 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
bindingset[apos]
bindingset[dpos]
predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos);
/**
* Holds if matching an inferred type `t` at `path` inside an access at `apos`
* against the declaration `target` means that the type should be adjusted to
* `tAdj` at `pathAdj`.
*
* For example, in
*
* ```csharp
* void M(int? i) {}
* M(42);
* ```
*
* the inferred type of `42` is `int`, but it should be adjusted to `int?`
* when matching against `M`.
*/
bindingset[apos, target, path, t]
default predicate adjustAccessType(
AccessPosition apos, Declaration target, TypePath path, Type t, TypePath pathAdj, Type tAdj
) {
pathAdj = path and
tAdj = t
}
}
/**
@@ -1664,8 +1622,6 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
private import codeql.util.Unit
import Input
predicate adjustAccessType = Input::adjustAccessType/6;
class AccessEnvironment = Unit;
final private class AccessFinal = Input::Access;