mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge branch 'main' into sourcestest
This commit is contained in:
4
.github/copilot-instructions.md
vendored
4
.github/copilot-instructions.md
vendored
@@ -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.
|
||||
4
.github/instructions/expected-files.instructions.md
vendored
Normal file
4
.github/instructions/expected-files.instructions.md
vendored
Normal 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.
|
||||
6
.github/instructions/ql-files.instructions.md
vendored
Normal file
6
.github/instructions/ql-files.instructions.md
vendored
Normal 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
|
||||
@@ -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(',');
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Console.WriteLine($"<arguments>{string.Join(",", args)}</arguments>");
|
||||
@@ -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>
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "10.0.100-rc.2.25502.107"
|
||||
}
|
||||
}
|
||||
6
csharp/ql/integration-tests/linux/dotnet_10_rc2/test.py
Normal file
6
csharp/ql/integration-tests/linux/dotnet_10_rc2/test.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import os
|
||||
import runs_on
|
||||
|
||||
@runs_on.linux
|
||||
def test(codeql, csharp):
|
||||
codeql.database.create()
|
||||
@@ -0,0 +1 @@
|
||||
Console.WriteLine($"<arguments>{string.Join(",", args)}</arguments>");
|
||||
@@ -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>
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "10.0.100-rc.2.25502.107"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import os
|
||||
import runs_on
|
||||
|
||||
@runs_on.windows
|
||||
def test(codeql, csharp):
|
||||
codeql.database.create()
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
---------------
|
||||
|
||||
|
||||
@@ -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
|
||||
---------------
|
||||
|
||||
|
||||
@@ -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
|
||||
---------------
|
||||
|
||||
|
||||
@@ -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
|
||||
---------------
|
||||
|
||||
|
||||
@@ -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
|
||||
---------------
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
---------------
|
||||
|
||||
|
||||
@@ -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
|
||||
---------------
|
||||
|
||||
@@ -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
|
||||
---------------
|
||||
|
||||
|
||||
@@ -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).
|
||||
@@ -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
|
||||
|
||||
4
rust/ql/lib/change-notes/2025-10-06-call-resolution.md
Normal file
4
rust/ql/lib/change-notes/2025-10-06-call-resolution.md
Normal 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.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added `ExtractedFile::hasSemantics` and `ExtractedFile::isSkippedByCompilation` predicates.
|
||||
@@ -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" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() }
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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), _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
420
rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll
Normal file
420
rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll
Normal 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))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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>;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
extractionWarning
|
||||
| bad_cargo/src/no_semantics.rs:1:1:1:1 | semantic analyzer unavailable (unable to load manifest) |
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
1
rust/ql/test/extractor-tests/File/bad_cargo/.gitignore
vendored
Normal file
1
rust/ql/test/extractor-tests/File/bad_cargo/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!/Cargo.toml
|
||||
1
rust/ql/test/extractor-tests/File/bad_cargo/Cargo.toml
Normal file
1
rust/ql/test/extractor-tests/File/bad_cargo/Cargo.toml
Normal file
@@ -0,0 +1 @@
|
||||
wrong
|
||||
@@ -1,2 +0,0 @@
|
||||
multipleCallTargets
|
||||
| main.rs:272:14:272:29 | ...::deref(...) |
|
||||
@@ -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 |
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
multipleCallTargets
|
||||
| main.rs:483:18:483:24 | n.len() |
|
||||
@@ -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(...) |
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
multipleCallTargets
|
||||
| main.rs:52:14:52:29 | ...::from(...) |
|
||||
| main.rs:64:16:64:25 | s.as_str() |
|
||||
|
||||
@@ -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(...) |
|
||||
|
||||
@@ -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() |
|
||||
@@ -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(...) |
|
||||
|
||||
@@ -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() |
|
||||
@@ -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(...) |
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
93
rust/ql/test/library-tests/type-inference/invalid/main.rs
Normal file
93
rust/ql/test/library-tests/type-inference/invalid/main.rs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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::<...> |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(...) |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 | ... + ... |
|
||||
|
||||
@@ -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() |
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user