Merge branch 'main' into rust/callable-base

This commit is contained in:
Paolo Tranquilli
2024-10-15 11:03:11 +02:00
147 changed files with 4969 additions and 978 deletions

2
Cargo.lock generated
View File

@@ -390,11 +390,13 @@ dependencies = [
"ra_ap_base_db",
"ra_ap_hir",
"ra_ap_hir_def",
"ra_ap_hir_expand",
"ra_ap_ide_db",
"ra_ap_load-cargo",
"ra_ap_parser",
"ra_ap_paths",
"ra_ap_project_model",
"ra_ap_span",
"ra_ap_syntax",
"ra_ap_vfs",
"rust-extractor-macros",

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Local source models with the `stdin` source kind have been added for the variable `os.Stdin` and the functions `fmt.Scan`, `fmt.Scanf` and `fmt.Scanln`. You can optionally include threat models as appropriate when using the CodeQL CLI and in GitHub code scanning. For more information, see [Analyzing your code with CodeQL queries](https://docs.github.com/code-security/codeql-cli/getting-started-with-the-codeql-cli/analyzing-your-code-with-codeql-queries#including-model-packs-to-add-potential-sources-of-tainted-data>) and [Customizing your advanced setup for code scanning](https://docs.github.com/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#extending-codeql-coverage-with-threat-models).

View File

@@ -112,6 +112,15 @@ module Fmt {
Scanner() { this.hasQualifiedName("fmt", ["Scan", "Scanf", "Scanln"]) }
}
private class ScannerSource extends SourceNode {
ScannerSource() {
// All of the arguments which are sources are varargs.
this.asExpr() = any(Scanner s).getACall().getAnImplicitVarargsArgument().asExpr()
}
override string getThreatModel() { result = "stdin" }
}
/**
* The `Fscan` function or one of its variants,
* all of which read from a specified `io.Reader`.

View File

@@ -43,4 +43,12 @@ module Os {
input = inp and output = outp
}
}
private class Stdin extends SourceNode {
Stdin() {
exists(Variable osStdin | osStdin.hasQualifiedName("os", "Stdin") | this = osStdin.getARead())
}
override string getThreatModel() { result = "stdin" }
}
}

View File

@@ -0,0 +1,3 @@
module test
go 1.22.6

View File

@@ -0,0 +1,3 @@
testFailures
invalidModelRow
failures

View File

@@ -0,0 +1,7 @@
extensions:
- addsTo:
pack: codeql/threat-models
extensible: threatModelConfiguration
data:
- ["stdin", true, 0]

View File

@@ -0,0 +1,19 @@
import go
import ModelValidation
import TestUtilities.InlineExpectationsTest
module SourceTest implements TestSig {
string getARelevantTag() { result = "source" }
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(ActiveThreatModelSource s |
s.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
element = s.toString() and
value = "" and
tag = "source"
)
}
}
import MakeTest<SourceTest>

View File

@@ -0,0 +1,2 @@
testFailures
invalidModelRow

View File

@@ -0,0 +1,7 @@
extensions:
- addsTo:
pack: codeql/threat-models
extensible: threatModelConfiguration
data:
- ["stdin", true, 0]

View File

@@ -0,0 +1,48 @@
package test
import (
"bufio"
"fmt"
"os"
)
func sink(string) {
}
func readStdinBuffer() {
buf := make([]byte, 1024)
n, err := os.Stdin.Read(buf) // $source
if err != nil {
return
}
sink(string(buf[:n])) // $hasTaintFlow="type conversion"
}
func readStdinBuffReader() {
buf := make([]byte, 1024)
r := bufio.NewReader(os.Stdin) // $source
n, err := r.Read(buf)
if err != nil {
return
}
sink(string(buf[:n])) // $hasTaintFlow="type conversion"
}
func scan() {
var username, email string
fmt.Scan(&username, &email) // $source
sink(username) // $hasTaintFlow="username"
}
func scanf() {
var s string
fmt.Scanf("%s", &s) // $source
sink(s) // $hasTaintFlow="s"
}
func scanl() {
var s string
fmt.Scanln(&s) // $source
sink(s) // $hasTaintFlow="s"
}

View File

@@ -0,0 +1,15 @@
import go
import semmle.go.dataflow.ExternalFlow
import ModelValidation
import experimental.frameworks.CleverGo
import TestUtilities.InlineFlowTest
module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(CallExpr c | c.getTarget().getName() = "sink").getArgument(0)
}
}
import TaintFlowTest<Config>

View File

@@ -13,10 +13,10 @@ rm -rf dbs
mkdir dbs
CODEQL_EXTRACTOR_PYTHON_DONT_EXTRACT_STDLIB=True $CODEQL database create dbs/without-stdlib --language python --source-root repo_dir/
$CODEQL database create dbs/without-stdlib --language python --source-root repo_dir/
$CODEQL query run --database dbs/without-stdlib query.ql > query.without-stdlib.actual
diff query.without-stdlib.expected query.without-stdlib.actual
LGTM_INDEX_EXCLUDE="/usr/lib/**" $CODEQL database create dbs/with-stdlib --language python --source-root repo_dir/
LGTM_INDEX_EXCLUDE="/usr/lib/**" CODEQL_EXTRACTOR_PYTHON_EXTRACT_STDLIB=True $CODEQL database create dbs/with-stdlib --language python --source-root repo_dir/
$CODEQL query run --database dbs/with-stdlib query.ql > query.with-stdlib.actual
diff query.with-stdlib.expected query.with-stdlib.actual

View File

@@ -1,5 +0,0 @@
| name |
+----------+
| dircache |
| stat |
| test |

View File

@@ -1,5 +1,3 @@
| name |
+----------+
| dircache |
| stat |
| test |
| name |
+------+
| test |

View File

@@ -1,4 +1,3 @@
| name |
+------+
| stat |
| test |

View File

@@ -102,8 +102,10 @@ def make_parser():
config_options.add_option("--colorize", dest="colorize", default=False, action="store_true",
help = """Colorize the logging output.""")
config_options.add_option("--dont-extract-stdlib", dest="extract_stdlib", default=True, action="store_false",
help="Do not extract the standard library.")
config_options.add_option("--dont-extract-stdlib", dest="extract_stdlib", action="store_false",
help="This flag is deprecated; not extracting the standard library is now the default.")
config_options.add_option("--extract-stdlib", dest="extract_stdlib", default=False, action="store_true",
help="Extract the standard library.")
parser.add_option_group(config_options)
@@ -226,8 +228,18 @@ def parse(command_line):
if 'CODEQL_EXTRACTOR_PYTHON_DONT_EXTRACT_STDLIB' in os.environ:
options.extract_stdlib = False
print ("WARNING: CODEQL_EXTRACTOR_PYTHON_DONT_EXTRACT_STDLIB is deprecated; the default is now to not extract the standard library.")
if 'CODEQL_EXTRACTOR_PYTHON_EXTRACT_STDLIB' in os.environ:
options.extract_stdlib = True
options.prune = True
if options.extract_stdlib:
print ("WARNING: The analysis will extract the standard library. This behavior is deprecated and will be removed in a future release. We expect it to be gone in CLI version 2.20.0.")
else:
print ("INFO: The Python extractor has recently stopped extracting the standard library by default. If you encounter problems, please let us know by submitting an issue to https://github.com/github/codeql. It is possible to re-enable extraction of the standard library by setting the environment variable CODEQL_EXTRACTOR_PYTHON_EXTRACT_STDLIB.")
return options, args
def split_and_flatten(options_list, div):

View File

@@ -67,7 +67,7 @@ def main(sys_path = sys.path[:]):
update_analysis_version(last_version)
found_py2 = False
if get_analysis_major_version() == 2:
if get_analysis_major_version() == 2 and options.extract_stdlib:
# Setup `sys_path` to use the Python 2 standard library
sys_path, found_py2 = get_py2_sys_path(logger, sys_path)

View File

@@ -10,7 +10,7 @@ from io import BytesIO
#Semantic version of extractor.
#Update this if any changes are made
VERSION = "6.1.2"
VERSION = "7.0.0"
PY_EXTENSIONS = ".py", ".pyw"

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Modelled that `re.finditer` returns an iterable of `re.Match` objects. This is now understood by the API graph in many cases.

View File

@@ -3284,6 +3284,18 @@ module StdlibPrivate {
}
}
/**
* A base API node for regular expression functions.
* Either the `re` module or a compiled regular expression.
*/
private API::Node re(boolean compiled) {
result = API::moduleImport("re") and
compiled = false
or
result = any(RePatternSummary c).getACall().(API::CallNode).getReturn() and
compiled = true
}
/**
* A flow summary for methods returning a `re.Match` object
*
@@ -3293,17 +3305,18 @@ module StdlibPrivate {
ReMatchSummary() { this = ["re.Match", "compiled re.Match"] }
override DataFlow::CallCfgNode getACall() {
this = "re.Match" and
result = API::moduleImport("re").getMember(["match", "search", "fullmatch"]).getACall()
or
this = "compiled re.Match" and
result =
any(RePatternSummary c)
.getACall()
.(API::CallNode)
.getReturn()
.getMember(["match", "search", "fullmatch"])
.getACall()
exists(API::Node re, boolean compiled |
re = re(compiled) and
(
compiled = false and
this = "re.Match"
or
compiled = true and
this = "compiled re.Match"
)
|
result = re.getMember(["match", "search", "fullmatch"]).getACall()
)
}
override DataFlow::ArgumentNode getACallback() { none() }
@@ -3340,6 +3353,13 @@ module StdlibPrivate {
}
}
/** An API node for a `re.Match` object */
private API::Node match() {
result = any(ReMatchSummary c).getACall().(API::CallNode).getReturn()
or
result = re(_).getMember("finditer").getReturn().getASubscript()
}
/**
* A flow summary for methods on a `re.Match` object
*
@@ -3353,15 +3373,7 @@ module StdlibPrivate {
methodName in ["expand", "group", "groups", "groupdict"]
}
override DataFlow::CallCfgNode getACall() {
result =
any(ReMatchSummary c)
.getACall()
.(API::CallNode)
.getReturn()
.getMember(methodName)
.getACall()
}
override DataFlow::CallCfgNode getACall() { result = match().getMember(methodName).getACall() }
override DataFlow::ArgumentNode getACallback() { none() }
@@ -3463,6 +3475,14 @@ module StdlibPrivate {
) and
preservesValue = false
)
or
// flow from input string to attribute on match object
exists(int arg | arg = methodName.(RegexExecutionMethod).getStringArgIndex() - offset |
input in ["Argument[" + arg + "]", "Argument[string:]"] and
methodName = "finditer" and
output = "ReturnValue.ListElement.Attribute[string]" and
preservesValue = true
)
)
}
}

View File

@@ -1,12 +1,10 @@
| mapping | builtin-class collections.defaultdict |
| mapping | builtin-class dict |
| mapping | class MyDictSubclass |
| mapping | class MyMappingABC |
| mapping | class OrderedDict |
| neither sequence nor mapping | builtin-class set |
| neither sequence nor mapping | class MyMappingABC |
| neither sequence nor mapping | class MySequenceABC |
| sequence | builtin-class list |
| sequence | builtin-class str |
| sequence | builtin-class tuple |
| sequence | builtin-class unicode |
| sequence | class MySequenceABC |
| sequence | class MySequenceImpl |

View File

@@ -44,14 +44,10 @@
| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX |
| test.py | 16 | ControlFlowNode for Attribute | class Y | ControlFlowNode for ClassExpr |
| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX |
| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | ControlFlowNode for ImportExpr |
| test.py | 19 | ControlFlowNode for tty | Module tty | ControlFlowNode for ImportExpr |
| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | ControlFlowNode for from sys import * |
| test.py | 22 | ControlFlowNode for x | Module package.x | Entry node for Module package.x |
| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | ControlFlowNode for IntegerLiteral |
| test.py | 24 | ControlFlowNode for argv | int 0 | ControlFlowNode for IntegerLiteral |
| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr |
| test.py | 31 | ControlFlowNode for argv | list object | ControlFlowNode for from sys import * |
| test.py | 33 | ControlFlowNode for ImportExpr | Module socket | ControlFlowNode for ImportExpr |
| test.py | 34 | ControlFlowNode for timeout | builtin-class socket.timeout | ControlFlowNode for from _socket import * |
| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr |

View File

@@ -44,14 +44,10 @@
| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX |
| test.py | 16 | ControlFlowNode for Attribute | class Y | builtin-class type | ControlFlowNode for ClassExpr |
| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX |
| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | builtin-class module | ControlFlowNode for ImportExpr |
| test.py | 19 | ControlFlowNode for tty | Module tty | builtin-class module | ControlFlowNode for ImportExpr |
| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | builtin-class builtin_function_or_method | ControlFlowNode for from sys import * |
| test.py | 22 | ControlFlowNode for x | Module package.x | builtin-class module | Entry node for Module package.x |
| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral |
| test.py | 24 | ControlFlowNode for argv | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral |
| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr |
| test.py | 31 | ControlFlowNode for argv | list object | builtin-class list | ControlFlowNode for from sys import * |
| test.py | 33 | ControlFlowNode for ImportExpr | Module socket | builtin-class module | ControlFlowNode for ImportExpr |
| test.py | 34 | ControlFlowNode for timeout | builtin-class socket.timeout | builtin-class type | ControlFlowNode for from _socket import * |
| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr |

View File

@@ -1,7 +1,7 @@
| six | Package six |
| six.moves | Package six.moves |
| six.moves.http_client | Module httplib |
| six.moves.http_client.HTTPConnection | class HTTPConnection |
| six.moves.http_client | Missing module httplib |
| six.moves.http_client.HTTPConnection | Missing module attribute httplib.HTTPConnection |
| six.moves.range | builtin-class xrange |
| six.moves.urllib | Package six.moves.urllib |
| six.moves.urllib.parse | Module six.moves.urllib_parse |

View File

@@ -1 +1 @@
| 38 |
| 11 |

View File

@@ -1,9 +1,6 @@
| mapping | builtin-class collections.OrderedDict |
| mapping | builtin-class collections.defaultdict |
| mapping | builtin-class dict |
| mapping | class MyDictSubclass |
| mapping | class MyMappingABC |
| mapping | class OrderedDict |
| neither sequence nor mapping | builtin-class set |
| sequence | builtin-class bytes |
| sequence | builtin-class list |

View File

@@ -44,14 +44,10 @@
| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX |
| test.py | 16 | ControlFlowNode for Attribute | class Y | ControlFlowNode for ClassExpr |
| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX |
| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | ControlFlowNode for ImportExpr |
| test.py | 19 | ControlFlowNode for tty | Module tty | ControlFlowNode for ImportExpr |
| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | ControlFlowNode for from sys import * |
| test.py | 22 | ControlFlowNode for x | Module package.x | Entry node for Module package.x |
| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | ControlFlowNode for IntegerLiteral |
| test.py | 24 | ControlFlowNode for argv | int 0 | ControlFlowNode for IntegerLiteral |
| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr |
| test.py | 31 | ControlFlowNode for argv | list object | ControlFlowNode for from sys import * |
| test.py | 33 | ControlFlowNode for ImportExpr | Module socket | ControlFlowNode for ImportExpr |
| test.py | 34 | ControlFlowNode for timeout | builtin-class TimeoutError | ControlFlowNode for from _socket import * |
| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr |

View File

@@ -44,14 +44,10 @@
| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX |
| test.py | 16 | ControlFlowNode for Attribute | class Y | builtin-class type | ControlFlowNode for ClassExpr |
| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX |
| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | builtin-class module | ControlFlowNode for ImportExpr |
| test.py | 19 | ControlFlowNode for tty | Module tty | builtin-class module | ControlFlowNode for ImportExpr |
| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | builtin-class builtin_function_or_method | ControlFlowNode for from sys import * |
| test.py | 22 | ControlFlowNode for x | Module package.x | builtin-class module | Entry node for Module package.x |
| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral |
| test.py | 24 | ControlFlowNode for argv | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral |
| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr |
| test.py | 31 | ControlFlowNode for argv | list object | builtin-class list | ControlFlowNode for from sys import * |
| test.py | 33 | ControlFlowNode for ImportExpr | Module socket | builtin-class module | ControlFlowNode for ImportExpr |
| test.py | 34 | ControlFlowNode for timeout | builtin-class TimeoutError | builtin-class type | ControlFlowNode for from _socket import * |
| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr |

View File

@@ -1,3 +1,3 @@
| mwe_failure.py:7:1:7:23 | class MyTest | <MISSING BASE TYPE> |
| mwe_failure_2.py:7:1:7:23 | class MyTest | <MISSING BASE TYPE> |
| mwe_failure.py:7:1:7:23 | class MyTest | class TestCase |
| mwe_failure_2.py:7:1:7:23 | class MyTest | class TestCase |
| mwe_success.py:7:1:7:23 | class MyTest | class TestCase |

View File

@@ -37,7 +37,6 @@
| Module package.assistant | e | Wrong() |
| Module package.assistant | f | int 1 |
| Module package.helper | __name__ | str u'package.helper' |
| Module package.helper | absolute_import | _Feature() |
| Module package.helper | assistant | Module package.assistant |
| Module package.helper | d | int 4 |
| Module package.helper | e | int 5 |

View File

@@ -1,7 +1,7 @@
| six | Package six |
| six.moves | Package six.moves |
| six.moves.http_client | Module http.client |
| six.moves.http_client.HTTPConnection | class HTTPConnection |
| six.moves.http_client | Missing module http.client |
| six.moves.http_client.HTTPConnection | Missing module attribute http.client.HTTPConnection |
| six.moves.range | builtin-class range |
| six.moves.urllib | Package six.moves.urllib |
| six.moves.urllib.parse | Module six.moves.urllib_parse |

View File

@@ -1 +1 @@
| 51 |
| 11 |

View File

@@ -1,4 +1,6 @@
| UndefinedExport.py:3:18:3:20 | StringLiteral | The name 'y' is exported by __all__ but is not defined. |
| UndefinedExport.py:3:23:3:25 | StringLiteral | The name 'z' is exported by __all__ but is not defined. |
| UndefinedExport.py:3:28:3:35 | StringLiteral | The name 'module' is exported by __all__ but is not defined. |
| enum_convert.py:8:13:8:19 | StringLiteral | The name 'Maybe' is exported by __all__ but is not defined. |
| enum_convert.py:8:22:8:32 | StringLiteral | The name 'Maybe_not' is exported by __all__ but is not defined. |
| package/__init__.py:1:23:1:34 | StringLiteral | The name 'not_exists' is exported by __all__ but is not defined. |

View File

@@ -1,7 +1,7 @@
| options.all | False |
| options.colorize | True |
| options.context_cost | 11 |
| options.extract_stdlib | True |
| options.extract_stdlib | False |
| options.guess | False |
| options.help | False |
| options.ignore_missing_modules | False |

View File

@@ -1,4 +1,3 @@
| 1 | ControlFlowNode for functools | Module functools | test.py:1 |
| 3 | ControlFlowNode for annotate | Function annotate | test.py:3 |
| 4 | ControlFlowNode for inner | Function inner | test.py:4 |
| 5 | ControlFlowNode for func | Function func1 | test.py:23 |
@@ -11,7 +10,6 @@
| 13 | ControlFlowNode for wrapper | Function wrapper | test.py:10 |
| 15 | ControlFlowNode for wraps2 | Function wraps2 | test.py:15 |
| 16 | ControlFlowNode for func | Function func3 | test.py:31 |
| 16 | ControlFlowNode for functools | Module functools | test.py:1 |
| 17 | ControlFlowNode for args | args | test.py:17 |
| 17 | ControlFlowNode for wrapper | Attribute()() | test.py:16 |
| 18 | ControlFlowNode for args | args | test.py:17 |

View File

@@ -7,8 +7,8 @@
| test.py:11:21:11:24 | ControlFlowNode for args | runtime | instance of tuple |
| test.py:13:12:13:18 | ControlFlowNode for wrapper | runtime | Function wraps1.wrapper |
| test.py:13:12:13:18 | ControlFlowNode for wrapper | test.py:26 from import | Function wraps1.wrapper |
| test.py:16:6:16:14 | ControlFlowNode for functools | runtime | Module functools |
| test.py:16:6:16:14 | ControlFlowNode for functools | test.py:30 from import | Module functools |
| test.py:16:6:16:14 | ControlFlowNode for functools | runtime | Missing module functools |
| test.py:16:6:16:14 | ControlFlowNode for functools | test.py:30 from import | Missing module functools |
| test.py:16:22:16:25 | ControlFlowNode for func | runtime | Unknown value |
| test.py:16:22:16:25 | ControlFlowNode for func | test.py:30 from import | Function func3 |
| test.py:18:21:18:24 | ControlFlowNode for args | runtime | instance of tuple |

View File

@@ -87,10 +87,6 @@
| Module pointsto_test | 69 | ControlFlowNode for X | class X |
| Module pointsto_test | 70 | ControlFlowNode for Attribute | deco() |
| Module pointsto_test | 70 | ControlFlowNode for X | class X |
| Module pointsto_test | 72 | ControlFlowNode for ImportExpr | Module abc |
| Module pointsto_test | 72 | ControlFlowNode for ImportMember | Function abstractmethod |
| Module pointsto_test | 72 | ControlFlowNode for abstractmethod | Function abstractmethod |
| Module pointsto_test | 73 | ControlFlowNode for abstractmethod | Function abstractmethod |
| Module pointsto_test | 75 | ControlFlowNode for C | class C |
| Module pointsto_test | 75 | ControlFlowNode for C() | C() |
| Module pointsto_test | 75 | ControlFlowNode for type | builtin-class type |

View File

@@ -95,10 +95,6 @@
| 69 | ControlFlowNode for X | class X |
| 70 | ControlFlowNode for Attribute | deco() |
| 70 | ControlFlowNode for X | class X |
| 72 | ControlFlowNode for ImportExpr | Module abc |
| 72 | ControlFlowNode for ImportMember | Function abstractmethod |
| 72 | ControlFlowNode for abstractmethod | Function abstractmethod |
| 73 | ControlFlowNode for abstractmethod | Function abstractmethod |
| 75 | ControlFlowNode for C | class C |
| 75 | ControlFlowNode for C() | C() |
| 75 | ControlFlowNode for type | builtin-class type |

View File

@@ -95,10 +95,6 @@
| 69 | ControlFlowNode for Attribute | Attribute | builtin-class method |
| 69 | ControlFlowNode for X | class X | builtin-class type |
| 70 | ControlFlowNode for X | class X | builtin-class type |
| 72 | ControlFlowNode for ImportExpr | Module abc | builtin-class module |
| 72 | ControlFlowNode for ImportMember | Function abstractmethod | builtin-class function |
| 72 | ControlFlowNode for abstractmethod | Function abstractmethod | builtin-class function |
| 73 | ControlFlowNode for abstractmethod | Function abstractmethod | builtin-class function |
| 75 | ControlFlowNode for C | class C | builtin-class type |
| 75 | ControlFlowNode for C() | C() | class C |
| 75 | ControlFlowNode for type | builtin-class type | builtin-class type |

View File

@@ -70,7 +70,3 @@
| type_test.py | 55 | ControlFlowNode for arg | class E | 29 |
| type_test.py | 67 | ControlFlowNode for x | float 1.0 | 62 |
| type_test.py | 67 | ControlFlowNode for x | int 0 | 62 |
| type_test.py | 77 | ControlFlowNode for IntegerLiteral | int 0 | 77 |
| type_test.py | 83 | ControlFlowNode for IntegerLiteral | int 0 | 83 |
| type_test.py | 89 | ControlFlowNode for IntegerLiteral | int 0 | 89 |
| type_test.py | 95 | ControlFlowNode for IntegerLiteral | int 0 | 95 |

View File

@@ -70,7 +70,3 @@
| type_test.py | 55 | ControlFlowNode for arg | class E | builtin-class type | 29 |
| type_test.py | 67 | ControlFlowNode for x | float 1.0 | builtin-class float | 62 |
| type_test.py | 67 | ControlFlowNode for x | int 0 | builtin-class int | 62 |
| type_test.py | 77 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 77 |
| type_test.py | 83 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 83 |
| type_test.py | 89 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 89 |
| type_test.py | 95 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 95 |

View File

@@ -85,15 +85,12 @@
| h_classes.py:23 | Class Base | __init__ | Function __init__ |
| h_classes.py:48 | Class D | m | Function f |
| h_classes.py:48 | Class D | n | Function n |
| i_imports.py:0 | Module code.i_imports | BytesIO | builtin-class _io.BytesIO |
| i_imports.py:0 | Module code.i_imports | StringIO | builtin-class _io.StringIO |
| i_imports.py:0 | Module code.i_imports | _io | Module _io |
| i_imports.py:0 | Module code.i_imports | a | int 1 |
| i_imports.py:0 | Module code.i_imports | argv | list object |
| i_imports.py:0 | Module code.i_imports | b | int 2 |
| i_imports.py:0 | Module code.i_imports | c | int 3 |
| i_imports.py:0 | Module code.i_imports | code | Module code |
| i_imports.py:0 | Module code.i_imports | io | Module io |
| i_imports.py:0 | Module code.i_imports | module1 | Module code.test_package.module1 |
| i_imports.py:0 | Module code.i_imports | module2 | Module code.test_package.module2 |
| i_imports.py:0 | Module code.i_imports | p | int 1 |

View File

@@ -475,14 +475,6 @@
| i_imports.py:31 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 31 | import |
| i_imports.py:31 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 31 | import |
| i_imports.py:31 | ControlFlowNode for _io | Module _io | builtin-class module | 29 | import |
| i_imports.py:33 | ControlFlowNode for ImportExpr | Module io | builtin-class module | 33 | import |
| i_imports.py:33 | ControlFlowNode for io | Module io | builtin-class module | 33 | import |
| i_imports.py:34 | ControlFlowNode for Attribute | builtin-class _io.StringIO | builtin-class type | 55 | import |
| i_imports.py:34 | ControlFlowNode for StringIO | builtin-class _io.StringIO | builtin-class type | 55 | import |
| i_imports.py:34 | ControlFlowNode for io | Module io | builtin-class module | 33 | import |
| i_imports.py:35 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 55 | import |
| i_imports.py:35 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 55 | import |
| i_imports.py:35 | ControlFlowNode for io | Module io | builtin-class module | 33 | import |
| i_imports.py:37 | ControlFlowNode for ImportExpr | Module code | builtin-class module | 37 | import |
| i_imports.py:37 | ControlFlowNode for code | Module code | builtin-class module | 37 | import |
| i_imports.py:38 | ControlFlowNode for Attribute | Function f2 | builtin-class function | 24 | import |

View File

@@ -572,14 +572,6 @@
| i_imports.py:31 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 31 |
| i_imports.py:31 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 31 |
| i_imports.py:31 | ControlFlowNode for _io | Module _io | builtin-class module | 29 |
| i_imports.py:33 | ControlFlowNode for ImportExpr | Module io | builtin-class module | 33 |
| i_imports.py:33 | ControlFlowNode for io | Module io | builtin-class module | 33 |
| i_imports.py:34 | ControlFlowNode for Attribute | builtin-class _io.StringIO | builtin-class type | 55 |
| i_imports.py:34 | ControlFlowNode for StringIO | builtin-class _io.StringIO | builtin-class type | 55 |
| i_imports.py:34 | ControlFlowNode for io | Module io | builtin-class module | 33 |
| i_imports.py:35 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 55 |
| i_imports.py:35 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 55 |
| i_imports.py:35 | ControlFlowNode for io | Module io | builtin-class module | 33 |
| i_imports.py:37 | ControlFlowNode for ImportExpr | Module code | builtin-class module | 37 |
| i_imports.py:37 | ControlFlowNode for code | Module code | builtin-class module | 37 |
| i_imports.py:38 | ControlFlowNode for Attribute | Function f2 | builtin-class function | 24 |

View File

@@ -373,11 +373,9 @@
| i_imports.py:30 | ControlFlowNode for _io | import | Module _io | builtin-class module |
| i_imports.py:31 | ControlFlowNode for Attribute | import | builtin-class _io.BytesIO | builtin-class type |
| i_imports.py:31 | ControlFlowNode for _io | import | Module _io | builtin-class module |
| i_imports.py:33 | ControlFlowNode for ImportExpr | import | Module io | builtin-class module |
| i_imports.py:34 | ControlFlowNode for Attribute | import | builtin-class _io.StringIO | builtin-class type |
| i_imports.py:34 | ControlFlowNode for io | import | Module io | builtin-class module |
| i_imports.py:35 | ControlFlowNode for Attribute | import | builtin-class _io.BytesIO | builtin-class type |
| i_imports.py:35 | ControlFlowNode for io | import | Module io | builtin-class module |
| i_imports.py:33 | ControlFlowNode for ImportExpr | import | Missing module io | builtin-class module |
| i_imports.py:34 | ControlFlowNode for io | import | Missing module io | builtin-class module |
| i_imports.py:35 | ControlFlowNode for io | import | Missing module io | builtin-class module |
| i_imports.py:37 | ControlFlowNode for ImportExpr | import | Package code | builtin-class module |
| i_imports.py:38 | ControlFlowNode for Attribute | import | Function f2 | builtin-class function |
| i_imports.py:38 | ControlFlowNode for Attribute | import | Module code.n_nesting | builtin-class module |

View File

@@ -1,3 +1,2 @@
| Local module | code-invalid-package-name/cmd.py:0:0:0:0 | Module cmd | referenced in external file called | pdb.py |
| Local module | code-invalid-package-name/cmd.py:0:0:0:0 | Module cmd | referenced in local file called | test_ok.py |
| Local module | code-invalid-package-name/unique_name.py:0:0:0:0 | Module unique_name | referenced in local file called | unique_name_use.py |

View File

@@ -1,3 +1,3 @@
| Module 'cmd' (local, not in stdlib, not missing) referenced in local file | code-invalid-package-name/test_ok.py:1 |
| Module 'pdb' (external, in stdlib, not missing) referenced in local file | code-invalid-package-name/test_fail.py:3 |
| Module 'pdb' (external, not in stdlib, missing) referenced in local file | code-invalid-package-name/test_fail.py:3 |
| Module 'unique_name' (local, not in stdlib, not missing) referenced in local file | code-invalid-package-name/unique_name_use.py:1 |

View File

@@ -1,2 +1,6 @@
testFailures
| classes.py:54:44:54:107 | Comment #$ arg1="with_length_hint" func=With_length_hint.__length_hint__ | Missing result:arg1="with_length_hint" |
| classes.py:54:44:54:107 | Comment #$ arg1="with_length_hint" func=With_length_hint.__length_hint__ | Missing result:func=With_length_hint.__length_hint__ |
| classes.py:71:32:71:77 | Comment #$ arg1="with_index" func=With_index.__index__ | Missing result:arg1="with_index" |
| classes.py:71:32:71:77 | Comment #$ arg1="with_index" func=With_index.__index__ | Missing result:func=With_index.__index__ |
failures

View File

@@ -1,2 +1,6 @@
testFailures
| test.py:4:17:4:60 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) |
| test.py:4:33:4:59 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) |
| test_dict.py:4:17:4:60 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) |
| test_dict.py:4:33:4:59 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) |
failures

View File

@@ -38,6 +38,12 @@ ensure_tainted(
compiled_pat.match(ts).string, # $ tainted
re.compile(ts).match("safe").re.pattern, # $ tainted
list(re.finditer(pat, ts))[0].string, # $ tainted
[m.string for m in re.finditer(pat, ts)], # $ tainted
list(re.finditer(pat, ts))[0].groups()[0], # $ MISSING: tainted // this requires list content in type tracking
[m.groups()[0] for m in re.finditer(pat, ts)], # $ tainted
)
ensure_not_tainted(
safe_match.expand("Hello \1"),

View File

@@ -37,7 +37,7 @@ explicit_argv_parsing = parser.parse_args(sys.argv) # $ threatModelSource[comman
ensure_tainted(explicit_argv_parsing.foo) # $ tainted
fake_args = parser.parse_args(["<foo>"])
ensure_not_tainted(fake_args.foo) # $ SPURIOUS: tainted
ensure_not_tainted(fake_args.foo)
########################################
# reading input from stdin

View File

@@ -1,3 +1 @@
| sqlite3 | 2 | 1 |
| sqlite3.__init__ | 2 | 1 |
| sqlite3.dump | 2 | 1 |

View File

@@ -2,6 +2,5 @@
| test.py:8:1:8:20 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. |
| test.py:9:1:9:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. |
| test.py:11:1:11:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group readable. |
| test.py:13:1:13:28 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. |
| test.py:14:1:14:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. |
| test.py:16:1:16:25 | ControlFlowNode for Attribute() | Overly permissive mask in open sets file to world readable. |

View File

@@ -1,3 +1,5 @@
| assert_raises.py:9:13:9:19 | ExprStmt | This statement has no effect. |
| assert_raises.py:11:13:11:16 | ExprStmt | This statement has no effect. |
| test.py:24:1:24:3 | ExprStmt | This statement has no effect. |
| test.py:25:1:25:13 | ExprStmt | This statement has no effect. |
| test.py:26:1:26:6 | ExprStmt | This statement has no effect. |

View File

@@ -440,8 +440,9 @@ fn write_extractor(grammar: &AstSrc) -> std::io::Result<String> {
"//! Generated by `ast-generator`, do not edit by hand.\n
#![cfg_attr(any(), rustfmt::skip)]
use crate::generated;
use super::base::{{TextValue, Translator}};
use crate::emit_detached;
use crate::generated;
use crate::trap::{{Label, TrapId}};
use ra_ap_syntax::ast::{{
HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody, HasModuleItem, HasName,
@@ -449,7 +450,7 @@ use ra_ap_syntax::ast::{{
}};
use ra_ap_syntax::{{ast, AstNode}};
impl Translator {{
impl Translator<'_> {{
fn emit_else_branch(&mut self, node: ast::ElseBranch) -> Label<generated::Expr> {{
match node {{
ast::ElseBranch::IfExpr(inner) => self.emit_if_expr(inner).into(),
@@ -550,7 +551,12 @@ impl Translator {{
writeln!(buf, " self.emit_location(label, &node);")?;
writeln!(
buf,
" self.emit_tokens(label.into(), node.syntax().children_with_tokens());"
" emit_detached!({}, self, node, label);",
class_name
)?;
writeln!(
buf,
" self.emit_tokens(&node, label.into(), node.syntax().children_with_tokens());"
)?;
writeln!(buf, " label")?;
@@ -566,9 +572,6 @@ fn main() -> std::io::Result<()> {
.parse()
.unwrap();
let mut grammar = codegen::grammar::lower(&grammar);
grammar
.nodes
.retain(|x| x.name != "MacroStmts" && x.name != "MacroItems");
grammar.enums.retain(|x| x.name != "Adt");

View File

@@ -13,12 +13,14 @@ ra_ap_base_db = "0.0.232"
ra_ap_hir = "0.0.232"
ra_ap_hir_def = "0.0.232"
ra_ap_ide_db = "0.0.232"
ra_ap_hir_expand = "0.0.232"
ra_ap_load-cargo = "0.0.232"
ra_ap_paths = "0.0.232"
ra_ap_project_model = "0.0.232"
ra_ap_syntax = "0.0.232"
ra_ap_vfs = "0.0.232"
ra_ap_parser = "0.0.232"
ra_ap_span = "0.0.232"
serde = "1.0.209"
serde_with = "3.9.0"
stderrlog = "0.6.0"

View File

@@ -1,2 +1,2 @@
mod.rs 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7
top.rs 7c68cdb6a44e3f1ac27601f006a8c583ef1e5f198fd9c30a6710ffade2612d80 7c68cdb6a44e3f1ac27601f006a8c583ef1e5f198fd9c30a6710ffade2612d80
top.rs f7bff00786adef1f7f80825d9f613a958c92d35896ea8c3c3b077b9992dca590 f7bff00786adef1f7f80825d9f613a958c92d35896ea8c3c3b077b9992dca590

View File

@@ -1068,6 +1068,110 @@ impl From<trap::Label<Lifetime>> for trap::Label<Locatable> {
}
}
#[derive(Debug)]
pub struct MacroItems {
pub id: trap::TrapId<MacroItems>,
pub items: Vec<trap::Label<Item>>,
}
impl trap::TrapEntry for MacroItems {
fn extract_id(&mut self) -> trap::TrapId<Self> {
std::mem::replace(&mut self.id, trap::TrapId::Star)
}
fn emit(self, id: trap::Label<Self>, out: &mut trap::Writer) {
out.add_tuple("macro_items", vec![id.into()]);
for (i, v) in self.items.into_iter().enumerate() {
out.add_tuple("macro_items_items", vec![id.into(), i.into(), v.into()]);
}
}
}
impl trap::TrapClass for MacroItems {
fn class_name() -> &'static str { "MacroItems" }
}
impl From<trap::Label<MacroItems>> for trap::Label<AstNode> {
fn from(value: trap::Label<MacroItems>) -> Self {
// SAFETY: this is safe because in the dbscheme MacroItems is a subclass of AstNode
unsafe {
Self::from_untyped(value.as_untyped())
}
}
}
impl From<trap::Label<MacroItems>> for trap::Label<Element> {
fn from(value: trap::Label<MacroItems>) -> Self {
// SAFETY: this is safe because in the dbscheme MacroItems is a subclass of Element
unsafe {
Self::from_untyped(value.as_untyped())
}
}
}
impl From<trap::Label<MacroItems>> for trap::Label<Locatable> {
fn from(value: trap::Label<MacroItems>) -> Self {
// SAFETY: this is safe because in the dbscheme MacroItems is a subclass of Locatable
unsafe {
Self::from_untyped(value.as_untyped())
}
}
}
#[derive(Debug)]
pub struct MacroStmts {
pub id: trap::TrapId<MacroStmts>,
pub expr: Option<trap::Label<Expr>>,
pub statements: Vec<trap::Label<Stmt>>,
}
impl trap::TrapEntry for MacroStmts {
fn extract_id(&mut self) -> trap::TrapId<Self> {
std::mem::replace(&mut self.id, trap::TrapId::Star)
}
fn emit(self, id: trap::Label<Self>, out: &mut trap::Writer) {
out.add_tuple("macro_stmts", vec![id.into()]);
if let Some(v) = self.expr {
out.add_tuple("macro_stmts_exprs", vec![id.into(), v.into()]);
}
for (i, v) in self.statements.into_iter().enumerate() {
out.add_tuple("macro_stmts_statements", vec![id.into(), i.into(), v.into()]);
}
}
}
impl trap::TrapClass for MacroStmts {
fn class_name() -> &'static str { "MacroStmts" }
}
impl From<trap::Label<MacroStmts>> for trap::Label<AstNode> {
fn from(value: trap::Label<MacroStmts>) -> Self {
// SAFETY: this is safe because in the dbscheme MacroStmts is a subclass of AstNode
unsafe {
Self::from_untyped(value.as_untyped())
}
}
}
impl From<trap::Label<MacroStmts>> for trap::Label<Element> {
fn from(value: trap::Label<MacroStmts>) -> Self {
// SAFETY: this is safe because in the dbscheme MacroStmts is a subclass of Element
unsafe {
Self::from_untyped(value.as_untyped())
}
}
}
impl From<trap::Label<MacroStmts>> for trap::Label<Locatable> {
fn from(value: trap::Label<MacroStmts>) -> Self {
// SAFETY: this is safe because in the dbscheme MacroStmts is a subclass of Locatable
unsafe {
Self::from_untyped(value.as_untyped())
}
}
}
#[derive(Debug)]
pub struct MatchArm {
pub id: trap::TrapId<MatchArm>,
@@ -8720,6 +8824,12 @@ impl trap::TrapEntry for MacroCall {
}
}
impl MacroCall {
pub fn emit_expanded(id: trap::Label<Self>, value: trap::Label<AstNode>, out: &mut trap::Writer) {
out.add_tuple("macro_call_expandeds", vec![id.into(), value.into()]);
}
}
impl trap::TrapClass for MacroCall {
fn class_name() -> &'static str { "MacroCall" }
}

View File

@@ -1,92 +1,119 @@
use std::{
collections::HashMap,
path::{Path, PathBuf},
};
use anyhow::Context;
use ra_ap_ide_db::line_index::LineIndex;
use ra_ap_parser::Edition;
use std::borrow::Cow;
use archive::Archiver;
use ra_ap_ide_db::line_index::{LineCol, LineIndex};
use ra_ap_project_model::ProjectManifest;
use rust_analyzer::{ParseResult, RustAnalyzer};
mod archive;
mod config;
pub mod generated;
mod rust_analyzer;
mod translate;
pub mod trap;
use ra_ap_syntax::ast::SourceFile;
use ra_ap_syntax::{AstNode, SyntaxError, TextRange, TextSize};
fn from_utf8_lossy(v: &[u8]) -> (Cow<'_, str>, Option<SyntaxError>) {
let mut iter = v.utf8_chunks();
let (first_valid, first_invalid) = if let Some(chunk) = iter.next() {
let valid = chunk.valid();
let invalid = chunk.invalid();
if invalid.is_empty() {
debug_assert_eq!(valid.len(), v.len());
return (Cow::Borrowed(valid), None);
}
(valid, invalid)
} else {
return (Cow::Borrowed(""), None);
};
const REPLACEMENT: &str = "\u{FFFD}";
let error_start = first_valid.len() as u32;
let error_end = error_start + first_invalid.len() as u32;
let error_range = TextRange::new(TextSize::new(error_start), TextSize::new(error_end));
let error = SyntaxError::new("invalid utf-8 sequence".to_owned(), error_range);
let mut res = String::with_capacity(v.len());
res.push_str(first_valid);
res.push_str(REPLACEMENT);
for chunk in iter {
res.push_str(chunk.valid());
if !chunk.invalid().is_empty() {
res.push_str(REPLACEMENT);
}
}
(Cow::Owned(res), Some(error))
}
fn extract(
archiver: &archive::Archiver,
rust_analyzer: &mut rust_analyzer::RustAnalyzer,
archiver: &Archiver,
traps: &trap::TrapFileProvider,
file: std::path::PathBuf,
) -> anyhow::Result<()> {
let file = std::path::absolute(&file).unwrap_or(file);
let file = std::fs::canonicalize(&file).unwrap_or(file);
archiver.archive(&file);
let input = std::fs::read(&file)?;
let (input, err) = from_utf8_lossy(&input);
let line_index = LineIndex::new(&input);
file: &std::path::Path,
) {
archiver.archive(file);
let ParseResult {
ast,
text,
errors,
file_id,
semantics,
} = rust_analyzer.parse(file);
let line_index = LineIndex::new(text.as_ref());
let display_path = file.to_string_lossy();
let mut trap = traps.create("source", &file);
let label = trap.emit_file(&file);
let mut translator = translate::Translator::new(trap, label, line_index);
if let Some(err) = err {
translator.emit_parse_error(display_path.as_ref(), err);
let mut trap = traps.create("source", file);
let label = trap.emit_file(file);
let mut translator = translate::Translator::new(
trap,
display_path.as_ref(),
label,
line_index,
file_id,
semantics,
);
for err in errors {
translator.emit_parse_error(&ast, &err);
}
let parse = ra_ap_syntax::ast::SourceFile::parse(&input, Edition::CURRENT);
for err in parse.errors() {
translator.emit_parse_error(display_path.as_ref(), err);
let no_location = (LineCol { line: 0, col: 0 }, LineCol { line: 0, col: 0 });
if translator.semantics.is_none() {
translator.emit_diagnostic(
trap::DiagnosticSeverity::Warning,
"semantics".to_owned(),
"semantic analyzer unavailable".to_owned(),
"semantic analyzer unavailable: macro expansion, call graph, and type inference will be skipped.".to_owned(),
no_location,
);
}
if let Some(ast) = SourceFile::cast(parse.syntax_node()) {
translator.emit_source_file(ast);
} else {
log::warn!("Skipped {}", display_path);
}
translator.trap.commit()?;
Ok(())
translator.emit_source_file(ast);
translator.trap.commit().unwrap_or_else(|err| {
log::error!(
"Failed to write trap file for: {}: {}",
display_path,
err.to_string()
)
});
}
fn main() -> anyhow::Result<()> {
let cfg = config::Config::extract().context("failed to load configuration")?;
stderrlog::new()
.module(module_path!())
.verbosity(2 + cfg.verbose as usize)
.verbosity(1 + cfg.verbose as usize)
.init()?;
log::info!("{cfg:?}");
let traps = trap::TrapFileProvider::new(&cfg).context("failed to set up trap files")?;
let archiver = archive::Archiver {
root: cfg.source_archive_dir,
};
for file in cfg.inputs {
extract(&archiver, &traps, file)?;
let files: Vec<PathBuf> = cfg
.inputs
.iter()
.map(|file| {
let file = std::path::absolute(file).unwrap_or(file.to_path_buf());
std::fs::canonicalize(&file).unwrap_or(file)
})
.collect();
let manifests = rust_analyzer::find_project_manifests(&files)?;
let mut map: HashMap<&Path, (&ProjectManifest, Vec<&Path>)> = manifests
.iter()
.map(|x| (x.manifest_path().parent().as_ref(), (x, Vec::new())))
.collect();
let mut other_files = Vec::new();
'outer: for file in &files {
let mut p = file.as_path();
while let Some(parent) = p.parent() {
p = parent;
if let Some((_, files)) = map.get_mut(parent) {
files.push(file);
continue 'outer;
}
}
other_files.push(file);
}
for (manifest, files) in map.values() {
if files.is_empty() {
break;
}
let mut rust_analyzer = RustAnalyzer::new(manifest, &cfg.scratch_dir);
for file in files {
extract(&mut rust_analyzer, &archiver, &traps, file);
}
}
let mut rust_analyzer = RustAnalyzer::WithoutDatabase();
for file in other_files {
extract(&mut rust_analyzer, &archiver, &traps, file);
}
Ok(())

View File

@@ -0,0 +1,160 @@
use itertools::Itertools;
use log::info;
use ra_ap_base_db::SourceDatabase;
use ra_ap_base_db::SourceDatabaseFileInputExt;
use ra_ap_hir::Semantics;
use ra_ap_ide_db::RootDatabase;
use ra_ap_load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice};
use ra_ap_paths::Utf8PathBuf;
use ra_ap_project_model::CargoConfig;
use ra_ap_project_model::ProjectManifest;
use ra_ap_project_model::RustLibSource;
use ra_ap_span::Edition;
use ra_ap_span::EditionedFileId;
use ra_ap_span::TextRange;
use ra_ap_span::TextSize;
use ra_ap_syntax::SourceFile;
use ra_ap_syntax::SyntaxError;
use ra_ap_vfs::AbsPathBuf;
use ra_ap_vfs::Vfs;
use ra_ap_vfs::VfsPath;
use std::borrow::Cow;
use std::path::{Path, PathBuf};
use triomphe::Arc;
pub enum RustAnalyzer {
WithDatabase { db: RootDatabase, vfs: Vfs },
WithoutDatabase(),
}
pub struct ParseResult<'a> {
pub ast: SourceFile,
pub text: Arc<str>,
pub errors: Vec<SyntaxError>,
pub file_id: Option<EditionedFileId>,
pub semantics: Option<Semantics<'a, RootDatabase>>,
}
impl RustAnalyzer {
pub fn new(project: &ProjectManifest, scratch_dir: &Path) -> Self {
let config = CargoConfig {
sysroot: Some(RustLibSource::Discover),
target_dir: ra_ap_paths::Utf8PathBuf::from_path_buf(scratch_dir.to_path_buf())
.map(|x| x.join("target"))
.ok(),
..Default::default()
};
let progress = |t| (log::trace!("progress: {}", t));
let load_config = LoadCargoConfig {
load_out_dirs_from_check: true,
with_proc_macro_server: ProcMacroServerChoice::Sysroot,
prefill_caches: false,
};
let manifest = project.manifest_path();
match load_workspace_at(manifest.as_ref(), &config, &load_config, &progress) {
Ok((db, vfs, _macro_server)) => RustAnalyzer::WithDatabase { db, vfs },
Err(err) => {
log::error!("failed to load workspace for {}: {}", manifest, err);
RustAnalyzer::WithoutDatabase()
}
}
}
pub fn parse(&mut self, path: &Path) -> ParseResult<'_> {
let mut errors = Vec::new();
let input = match std::fs::read(path) {
Ok(data) => data,
Err(e) => {
errors.push(SyntaxError::new(
format!("Could not read {}: {}", path.to_string_lossy(), e),
TextRange::empty(TextSize::default()),
));
vec![]
}
};
let (input, err) = from_utf8_lossy(&input);
if let RustAnalyzer::WithDatabase { vfs, db } = self {
if let Some(file_id) = Utf8PathBuf::from_path_buf(path.to_path_buf())
.ok()
.and_then(|x| AbsPathBuf::try_from(x).ok())
.map(VfsPath::from)
.and_then(|x| vfs.file_id(&x))
{
db.set_file_text(file_id, &input);
let semantics = Semantics::new(db);
let file_id = EditionedFileId::current_edition(file_id);
let source_file = semantics.parse(file_id);
errors.extend(
db.parse_errors(file_id)
.into_iter()
.flat_map(|x| x.to_vec()),
);
return ParseResult {
ast: source_file,
text: input.as_ref().into(),
errors,
file_id: Some(file_id),
semantics: Some(semantics),
};
}
}
let parse = ra_ap_syntax::ast::SourceFile::parse(&input, Edition::CURRENT);
errors.extend(parse.errors());
errors.extend(err);
ParseResult {
ast: parse.tree(),
text: input.as_ref().into(),
errors,
file_id: None,
semantics: None,
}
}
}
pub fn find_project_manifests(
files: &[PathBuf],
) -> anyhow::Result<Vec<ra_ap_project_model::ProjectManifest>> {
let current = std::env::current_dir()?;
let abs_files: Vec<_> = files
.iter()
.map(|path| AbsPathBuf::assert_utf8(current.join(path)))
.collect();
let ret = ra_ap_project_model::ProjectManifest::discover_all(&abs_files);
info!(
"found manifests: {}",
ret.iter().map(|m| format!("{m}")).join(", ")
);
Ok(ret)
}
fn from_utf8_lossy(v: &[u8]) -> (Cow<'_, str>, Option<SyntaxError>) {
let mut iter = v.utf8_chunks();
let (first_valid, first_invalid) = if let Some(chunk) = iter.next() {
let valid = chunk.valid();
let invalid = chunk.invalid();
if invalid.is_empty() {
debug_assert_eq!(valid.len(), v.len());
return (Cow::Borrowed(valid), None);
}
(valid, invalid)
} else {
return (Cow::Borrowed(""), None);
};
const REPLACEMENT: &str = "\u{FFFD}";
let error_start = first_valid.len() as u32;
let error_end = error_start + first_invalid.len() as u32;
let error_range = TextRange::new(TextSize::new(error_start), TextSize::new(error_end));
let error = SyntaxError::new("invalid utf-8 sequence".to_owned(), error_range);
let mut res = String::with_capacity(v.len());
res.push_str(first_valid);
res.push_str(REPLACEMENT);
for chunk in iter {
res.push_str(chunk.valid());
if !chunk.invalid().is_empty() {
res.push_str(REPLACEMENT);
}
}
(Cow::Owned(res), Some(error))
}

View File

@@ -1,11 +1,30 @@
use crate::generated::{self, AstNode};
use crate::generated::MacroCall;
use crate::generated::{self};
use crate::trap::{DiagnosticSeverity, TrapFile, TrapId};
use crate::trap::{Label, TrapClass};
use codeql_extractor::trap::{self};
use log::Level;
use ra_ap_hir::db::ExpandDatabase;
use ra_ap_hir::Semantics;
use ra_ap_hir_expand::ExpandTo;
use ra_ap_ide_db::line_index::{LineCol, LineIndex};
use ra_ap_ide_db::RootDatabase;
use ra_ap_parser::SyntaxKind;
use ra_ap_span::{EditionedFileId, TextSize};
use ra_ap_syntax::ast::RangeItem;
use ra_ap_syntax::{ast, NodeOrToken, SyntaxElementChildren, SyntaxError, SyntaxToken, TextRange};
use ra_ap_syntax::{
ast, AstNode, NodeOrToken, SyntaxElementChildren, SyntaxError, SyntaxNode, SyntaxToken,
TextRange,
};
#[macro_export]
macro_rules! emit_detached {
(MacroCall, $self:ident, $node:ident, $label:ident) => {
$self.extract_macro_call_expanded(&$node, $label.into());
};
($($_:tt)*) => {};
}
pub trait TextValue {
fn try_get_text(&self) -> Option<String>;
}
@@ -56,27 +75,41 @@ impl TextValue for ast::RangePat {
self.op_token().map(|x| x.text().to_string())
}
}
pub struct Translator {
pub struct Translator<'a> {
pub trap: TrapFile,
path: &'a str,
label: trap::Label,
line_index: LineIndex,
file_id: Option<EditionedFileId>,
pub semantics: Option<Semantics<'a, RootDatabase>>,
}
impl Translator {
pub fn new(trap: TrapFile, label: trap::Label, line_index: LineIndex) -> Translator {
impl<'a> Translator<'a> {
pub fn new(
trap: TrapFile,
path: &'a str,
label: trap::Label,
line_index: LineIndex,
file_id: Option<EditionedFileId>,
semantics: Option<Semantics<'a, RootDatabase>>,
) -> Translator<'a> {
Translator {
trap,
path,
label,
line_index,
file_id,
semantics,
}
}
pub fn location(&self, range: TextRange) -> (LineCol, LineCol) {
fn location(&self, range: TextRange) -> (LineCol, LineCol) {
let start = self.line_index.line_col(range.start());
let range_end = range.end();
// QL end positions are inclusive, while TextRange offsets are exclusive and point at the position
// right after the last character of the range. We need to shift the end offset one character to the left to
// get the right inclusive QL position. Unfortunately, simply subtracting `1` from the end-offset may cause
// the offset to point in the middle of a mult-byte character, resulting in a `panic`. Therefore we use `try_line_col`
// the offset to point in the middle of a multi-byte character, resulting in a `panic`. Therefore we use `try_line_col`
// with decreasing offsets to find the start of the last character included in the range.
for i in 1..4 {
if let Some(end) = range_end
@@ -89,39 +122,210 @@ impl Translator {
let end = self.line_index.line_col(range_end);
(start, end)
}
pub fn text_range_for_node(&mut self, node: &impl ast::AstNode) -> Option<TextRange> {
if let Some(semantics) = self.semantics.as_ref() {
let file_range = semantics.original_range(node.syntax());
let file_id = self.file_id?;
if file_id == file_range.file_id {
Some(file_range.range)
} else {
None
}
} else {
Some(node.syntax().text_range())
}
}
pub fn emit_location<T: TrapClass>(&mut self, label: Label<T>, node: &impl ast::AstNode) {
let (start, end) = self.location(node.syntax().text_range());
self.trap.emit_location(self.label, label, start, end)
if let Some(range) = self.text_range_for_node(node) {
let (start, end) = self.location(range);
self.trap.emit_location(self.label, label, start, end)
} else {
self.emit_diagnostic(
DiagnosticSeverity::Info,
"locations".to_owned(),
"missing location for AstNode".to_owned(),
"missing location for AstNode".to_owned(),
(LineCol { line: 0, col: 0 }, LineCol { line: 0, col: 0 }),
);
}
}
pub fn emit_location_token(&mut self, label: Label<generated::Token>, token: &SyntaxToken) {
let (start, end) = self.location(token.text_range());
self.trap.emit_location(self.label, label, start, end)
pub fn emit_location_token(
&mut self,
label: Label<generated::Token>,
parent: &impl ast::AstNode,
token: &SyntaxToken,
) {
let parent_range = parent.syntax().text_range();
let token_range = token.text_range();
if let Some(clipped_range) = token_range.intersect(parent_range) {
if let Some(parent_range2) = self.text_range_for_node(parent) {
let token_range = clipped_range + parent_range2.start() - parent_range.start();
let (start, end) = self.location(token_range);
self.trap.emit_location(self.label, label, start, end)
}
}
}
pub fn emit_parse_error(&mut self, path: &str, err: SyntaxError) {
let (start, end) = self.location(err.range());
log::warn!("{}:{}:{}: {}", path, start.line + 1, start.col + 1, err);
let message = err.to_string();
pub fn emit_diagnostic(
&mut self,
severity: DiagnosticSeverity,
error_tag: String,
error_message: String,
full_error_message: String,
location: (LineCol, LineCol),
) {
let (start, end) = location;
let level = match severity {
DiagnosticSeverity::Debug => Level::Debug,
DiagnosticSeverity::Info => Level::Info,
DiagnosticSeverity::Warning => Level::Warn,
DiagnosticSeverity::Error => Level::Error,
};
log::log!(
level,
"{}:{}:{}: {}",
self.path,
start.line + 1,
start.col + 1,
&error_message
);
let location = self.trap.emit_location_label(self.label, start, end);
self.trap.emit_diagnostic(
DiagnosticSeverity::Warning,
"parse_error".to_owned(),
message.clone(),
message,
severity,
error_tag,
error_message,
full_error_message,
location,
);
}
pub fn emit_tokens(&mut self, parent: Label<AstNode>, children: SyntaxElementChildren) {
pub fn emit_parse_error(&mut self, owner: &impl ast::AstNode, err: &SyntaxError) {
let owner_range: TextRange = owner.syntax().text_range();
let err_range = err.range();
if let Some(owner_range2) = self.text_range_for_node(owner) {
let location = if let Some(clipped_range) = err_range.intersect(owner_range) {
let err_range = clipped_range + owner_range2.start() - owner_range.start();
self.location(err_range)
} else {
self.location(owner_range2)
};
let message = err.to_string();
self.emit_diagnostic(
DiagnosticSeverity::Warning,
"parse_error".to_owned(),
message.clone(),
message,
location,
);
}
}
pub fn emit_tokens(
&mut self,
parent_node: &impl ast::AstNode,
parent_label: Label<generated::AstNode>,
children: SyntaxElementChildren,
) {
for child in children {
if let NodeOrToken::Token(token) = child {
if token.kind() == SyntaxKind::COMMENT {
let label = self.trap.emit(generated::Comment {
id: TrapId::Star,
parent,
parent: parent_label,
text: token.text().to_owned(),
});
self.emit_location_token(label.into(), &token);
self.emit_location_token(label.into(), parent_node, &token);
}
}
}
}
fn emit_macro_expansion_parse_errors(&mut self, mcall: &ast::MacroCall, expanded: &SyntaxNode) {
let semantics = self.semantics.as_ref().unwrap();
if let Some(value) = semantics
.hir_file_for(expanded)
.macro_file()
.and_then(|macro_file| {
semantics
.db
.parse_macro_expansion_error(macro_file.macro_call_id)
})
{
if let Some(err) = &value.err {
let (message, _error) = err.render_to_string(semantics.db);
if err.span().anchor.file_id == semantics.hir_file_for(mcall.syntax()) {
let location = err.span().range
+ semantics
.db
.ast_id_map(err.span().anchor.file_id.into())
.get_erased(err.span().anchor.ast_id)
.text_range()
.start();
self.emit_parse_error(mcall, &SyntaxError::new(message, location));
};
}
for err in value.value.iter() {
self.emit_parse_error(mcall, err);
}
}
}
fn emit_expanded_as(
&mut self,
expand_to: ExpandTo,
expanded: SyntaxNode,
) -> Option<Label<generated::AstNode>> {
match expand_to {
ra_ap_hir_expand::ExpandTo::Statements => {
ast::MacroStmts::cast(expanded).map(|x| self.emit_macro_stmts(x).into())
}
ra_ap_hir_expand::ExpandTo::Items => {
ast::MacroItems::cast(expanded).map(|x| self.emit_macro_items(x).into())
}
ra_ap_hir_expand::ExpandTo::Pattern => {
ast::Pat::cast(expanded).map(|x| self.emit_pat(x).into())
}
ra_ap_hir_expand::ExpandTo::Type => {
ast::Type::cast(expanded).map(|x| self.emit_type(x).into())
}
ra_ap_hir_expand::ExpandTo::Expr => {
ast::Expr::cast(expanded).map(|x| self.emit_expr(x).into())
}
}
}
pub(crate) fn extract_macro_call_expanded(
&mut self,
mcall: &ast::MacroCall,
label: Label<generated::MacroCall>,
) {
if let Some(expanded) = self.semantics.as_ref().and_then(|s| s.expand(mcall)) {
self.emit_macro_expansion_parse_errors(mcall, &expanded);
let expand_to = ra_ap_hir_expand::ExpandTo::from_call_site(mcall);
let kind = expanded.kind();
if let Some(value) = self.emit_expanded_as(expand_to, expanded) {
MacroCall::emit_expanded(label, value, &mut self.trap.writer);
} else {
let range = self.text_range_for_node(mcall);
self.emit_parse_error(mcall, &SyntaxError::new(
format!(
"macro expansion failed: the macro '{}' expands to {:?} but a {:?} was expected",
mcall.path().map(|p| p.to_string()).unwrap_or_default(),
kind, expand_to
),
range.unwrap_or_else(|| TextRange::empty(TextSize::from(0))),
));
}
} else {
let range = self.text_range_for_node(mcall);
self.emit_parse_error(
mcall,
&SyntaxError::new(
format!(
"macro expansion failed: could not resolve macro '{}'",
mcall.path().map(|p| p.to_string()).unwrap_or_default()
),
range.unwrap_or_else(|| TextRange::empty(TextSize::from(0))),
),
);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -124,7 +124,7 @@ impl<T: TrapClass> From<Label<T>> for trap::Arg {
pub struct TrapFile {
path: PathBuf,
writer: Writer,
pub writer: Writer,
compression: Compression,
}
@@ -244,7 +244,7 @@ impl TrapFileProvider {
}
pub fn create(&self, category: &str, key: &Path) -> TrapFile {
let path = file_paths::path_for(&self.trap_dir.join(category), key, ".trap");
let path = file_paths::path_for(&self.trap_dir.join(category), key, "trap");
debug!("creating trap file {}", path.display());
let mut writer = trap::Writer::new();
extractor::populate_empty_location(&mut writer);

View File

@@ -66,11 +66,13 @@ lib/codeql/rust/elements/LiteralExpr.qll 40b67404b7c2b81e5afabc53a2a93e0a503f687
lib/codeql/rust/elements/LiteralPat.qll daffb5f380a47543669c8cc92628b0e0de478c3ac82685802c63e8d75a206bed adfe9796598cf6ca4a9170c89ffd871e117f1cea6dd7dd80ecbbb947327a1a5d
lib/codeql/rust/elements/Locatable.qll 2855efa4a469b54e0ca85daa89309a8b991cded6f3f10db361010831ba1e11d3 00c3406d14603f90abea11bf074eaf2c0b623a30e29cf6afc3a247cb58b92f0f
lib/codeql/rust/elements/LoopExpr.qll 58ade0bc4a01a1cc361363682fde3ea56f4c5fbb4b28f5723ceff52ebaf897d7 fa299162c742bcf3b2211dc20821b312e3c133350c288a050eb26e6f8b5a5c78
lib/codeql/rust/elements/MacroCall.qll 16933db15c6c0dbb717ef442f751ad8f63c444f36a12f8d56b8a05a3e5f71d1b ac05cbf50e4b06f39f58817cddbeac6f804c2d1e4f60956a960d63d495e7183d
lib/codeql/rust/elements/MacroCall.qll a39a11d387355f59af3007dcbab3282e2b9e3289c1f8f4c6b96154ddb802f8c3 88d4575e462af2aa780219ba1338a790547fdfc1d267c4b84f1b929f4bc08d05
lib/codeql/rust/elements/MacroDef.qll acb39275a1a3257084314a46ad4d8477946130f57e401c70c5949ad6aafc5c5f 6a8a8db12a3ec345fede51ca36e8c6acbdce58c5144388bb94f0706416fa152a
lib/codeql/rust/elements/MacroExpr.qll ea9fed13f610bab1a2c4541c994510e0cb806530b60beef0d0c36b23e3b620f0 ad11a6bbd3a229ad97a16049cc6b0f3c8740f9f75ea61bbf4eebb072db9b12d2
lib/codeql/rust/elements/MacroItems.qll 00a5d41f7bb836d952abbd9382e42f72a9d81e65646a15a460b35ccd07a866c6 00efdb4d701b5599d76096f740da9ec157804865267b7e29bc2a214cbf03763e
lib/codeql/rust/elements/MacroPat.qll dbf193b4fb544ac0b5a7dcfc31a6652de7239b6e643ff15b05868b2c142e940c 19b45c0a1eb1198e450c05d564b5d4aa0d6da29e7db84b9521eadf901e20a932
lib/codeql/rust/elements/MacroRules.qll a94535506798077043b9c1470992ac4310bf67bcce5f722080886d1b3e6d90d1 bd8e08a7171991abc85100b45267631e66d1b332caf1e5882cd17caee5cf18a3
lib/codeql/rust/elements/MacroStmts.qll 6e9a1f90231cb72b27d3ff9479e399a9fba4abd0872a5005ab2fac45d5ca9be0 d6ca3a8254fc45794a93c451a3305c9b4be033a467ad72158d40d6f675a377a0
lib/codeql/rust/elements/MacroType.qll e5a153643e49a6be41483ad944550a030e0500764947b4e328cef6fa08c4fbd4 a42332c0a9c5cf7317fc49f3e1049e7751004fcc3efa056bbe058a8bfa2ef0cb
lib/codeql/rust/elements/MatchArm.qll c39fd6cc0da24b1ff8d1e42835bcfee7695ad13580e3c7c50acd7c881b1cd894 62a31d2bd125e6aaebefc406e541a641271d3c497a377959f94dd4735b2bfbf8
lib/codeql/rust/elements/MatchArmList.qll e6c48fd7419d88e996b82eb45e4aa2686dfd079b283b02be7710192fb2cb93a0 0ec63a0ca56f5f7f80093fd3e77b198b74c6289e67be55dc6a4deb610753c7bd
@@ -278,10 +280,14 @@ lib/codeql/rust/elements/internal/MacroDefConstructor.qll 382a3bdf46905d112ee491
lib/codeql/rust/elements/internal/MacroDefImpl.qll f26e787ffd43e8cb079db01eba04412dbf32c338938acf1bc09a2f094bbdfdfe 044f43bc94fe4b6df22afae32e9f039d1d0d9e85ad9f24b6388be71211c37ce5
lib/codeql/rust/elements/internal/MacroExprConstructor.qll b12edb21ea189a1b28d96309c69c3d08e08837621af22edd67ff9416c097d2df d35bc98e7b7b5451930214c0d93dce33a2c7b5b74f36bf99f113f53db1f19c14
lib/codeql/rust/elements/internal/MacroExprImpl.qll 92dd9f658a85ae407e055f090385f451084de59190d8a00c7e1fba453c3eced4 89d544634fecdbead2ff06a26fc8132e127dab07f38b9322fa14dc55657b9f1a
lib/codeql/rust/elements/internal/MacroItemsConstructor.qll 8e9ab7ec1e0f50a22605d4e993f99a85ca8059fbb506d67bc8f5a281af367b05 2602f9db31ea0c48192c3dde3bb5625a8ed1cae4cd3408729b9e09318d5bd071
lib/codeql/rust/elements/internal/MacroItemsImpl.qll 76fd50a1f27336e9efc6d3f73ef4d724f19627cadbaa805d1e14d2cfa4f19899 40c0e512090050b39b69128730f4f4581f51ffd3c687fb52913617bd70a144e9
lib/codeql/rust/elements/internal/MacroPatConstructor.qll 24744c1bbe21c1d249a04205fb09795ae38ed106ba1423e86ccbc5e62359eaa2 4fac3f731a1ffd87c1230d561c5236bd28dcde0d1ce0dcd7d7a84ba393669d4a
lib/codeql/rust/elements/internal/MacroPatImpl.qll 7470e2d88c38c7300a64986f058ba92bb22b4945438e2e0e268f180c4f267b71 c1507df74fc4c92887f3e0a4f857f54b61f174ffae5b1af6fb70f466175d658b
lib/codeql/rust/elements/internal/MacroRulesConstructor.qll dc04726ad59915ec980501c4cd3b3d2ad774f454ddbf138ff5808eba6bd63dea 8d6bf20feb850c47d1176237027ef131f18c5cbb095f6ab8b3ec58cea9bce856
lib/codeql/rust/elements/internal/MacroRulesImpl.qll 10c03adfb63ee7a4348ff5cffc6ef5300a531b048f28811a51e940b053e69f68 2498bd64aeaea9849c086abeaa6c248e4ce41b4436155f4bd4840965976d5d54
lib/codeql/rust/elements/internal/MacroStmtsConstructor.qll c293815cd69c002ba6de1db6018672654420f3f8bdd143f9d0c620adddd2be02 d376f8f07661a8cad1b10039076fd7fca353dcacf3ca40ed6507b8c874e849ca
lib/codeql/rust/elements/internal/MacroStmtsImpl.qll 27faff9da93ad7f22a6236c73ebb4d4631161cf4ec1b82958cdf79c85aa2087c 7e2863eaf50d4b285b9240f2c5ff9497cfb4393c8528a0738d725d00f1a78406
lib/codeql/rust/elements/internal/MacroTypeConstructor.qll 0a23573a6f69b38f3d7470050b16197601d67bdd5a4b1a43a155b0b99ccdf6b5 19b623962e8e1f73e55e3ed9712d2a3fe84b9510b99062173902feb2458ec12a
lib/codeql/rust/elements/internal/MacroTypeImpl.qll b8711279f09f521b05bb67568c089271b7913f863ee64dfdeec2c502de2cbdc8 51bd9d3a2fb2065bce7b193b485e225ca5c8ba2029e60cab427d43a90baf0880
lib/codeql/rust/elements/internal/MatchArmConstructor.qll b41c1d5822d54127ce376ef62c6a5fa60e11697319fc7d9c9c54fd313d784a93 96cca80e5684e5893c0e9c0dff365ef8ad9e15ff648c9969ba42d91f95abea05
@@ -308,7 +314,6 @@ lib/codeql/rust/elements/internal/NeverTypeImpl.qll 8c7464cb76f9d081dab318d74381
lib/codeql/rust/elements/internal/OffsetOfExprConstructor.qll 616e146562adb3ac0fba4d6f55dd6ce60518ed377c0856f1f09ba49593e7bfab 80518ce90fc6d08011d6f5fc2a543958067739e1b0a6a5f2ed90fc9b1db078f0
lib/codeql/rust/elements/internal/OffsetOfExprImpl.qll e52d4596068cc54719438121f7d5afcaab04e0c70168ac5e4df1a3a0969817a6 6ab37e659d79e02fb2685d6802ae124157bf14b6f790b31688f437c87f40f52c
lib/codeql/rust/elements/internal/OrPatConstructor.qll 4ef583e07298487c0c4c6d7c76ffcc04b1e5fe58aba0c1da3e2c8446a9e0c92b 980a6bd176ae5e5b11c134569910c5468ba91f480982d846e222d031a6a05f1a
lib/codeql/rust/elements/internal/OrPatImpl.qll 0dbc461115f62306e679f69c4354550bc3425d4291aec0124ad8f7a55c779d51 d32ebaa5a3002e87b35949cb624b20377155869ad33aec873326f60f2f0b666d
lib/codeql/rust/elements/internal/ParamConstructor.qll b98a2d8969f289fdcc8c0fb11cbd19a3b0c71be038c4a74f5988295a2bae52f0 77d81b31064167945b79b19d9697b57ca24462c3a7cc19e462c4693ce87db532
lib/codeql/rust/elements/internal/ParamImpl.qll 8a5101559f5d636b60ab80237057944b537823ce054d760c3dbd58b2acf05a46 e7a08cefeb6a290a975899045b7b19a9624f5a2b0946cba0866b1854cc0c0fb0
lib/codeql/rust/elements/internal/ParamListConstructor.qll 3123142ab3cab46fb53d7f3eff6ba2d3ff7a45b78839a53dc1979a9c6a54920e 165f3d777ea257cfcf142cc4ba9a0ebcd1902eb99842b8a6657c87087f3df6fe
@@ -515,11 +520,13 @@ lib/codeql/rust/elements/internal/generated/LiteralExpr.qll f3a564d0a3ed0d915f5a
lib/codeql/rust/elements/internal/generated/LiteralPat.qll ecc2bfe559abfce1be873fbf7b61b5728897c9afc3bb3f69551d8320d273da71 42196fb6a4a0ff9b570fd0bdbc920f24744b3f46772efbb46648af7fbfe1fbda
lib/codeql/rust/elements/internal/generated/Locatable.qll c897dc1bdd4dfcb6ded83a4a93332ca3d8f421bae02493ea2a0555023071775e b32d242f8c9480dc9b53c1e13a5cb8dcfce575b0373991c082c1db460a3e37b8
lib/codeql/rust/elements/internal/generated/LoopExpr.qll 22b755dfaf238ecea722c0c94c399992014e23481ec6fdd61f803bbec012b6f9 08731630c2dc05aa1e0ada222a6057752d9ce737329c62076708828247a358be
lib/codeql/rust/elements/internal/generated/MacroCall.qll 8b49d44e6aeac26dc2fc4b9ba03c482c65ebf0cba089d16f9d65e784e48ccbb0 9ecf6e278007adcbdc42ed1c10e7b1c0652b6c64738b780d256c9326afa3b393
lib/codeql/rust/elements/internal/generated/MacroCall.qll fc8988696493992cc4fdce8c0e5610c54ee92ea52ebb05262338f8b612353f50 188a2d7a484bd402a521787371e64f6e00e928306c8d437e6b19bf890a7aa14e
lib/codeql/rust/elements/internal/generated/MacroDef.qll e9b3f07ba41aa12a8e0bd6ec1437b26a6c363065ce134b6d059478e96c2273a6 87470dea99da1a6afb3a19565291f9382e851ba864b50a995ac6f29589efbd70
lib/codeql/rust/elements/internal/generated/MacroExpr.qll 03a1daa41866f51e479ac20f51f8406d04e9946b24f3875e3cf75a6b172c3d35 1ae8ca0ee96bd2be32575d87c07cc999a6ff7770151b66c0e3406f9454153786
lib/codeql/rust/elements/internal/generated/MacroItems.qll 894890f61e118b3727d03ca813ae7220a15e45195f2d1d059cb1bba6802128c8 db3854b347f8782a3ec9f9a1439da822727b66f0bd33727383184ab65dbf29ac
lib/codeql/rust/elements/internal/generated/MacroPat.qll 9e927e09d47029a3025eaad271c975e73479a80ea933c921381b6c9d751f2866 bdf5c58ca27743eb2e2dae2aeea3f3fc21f8a4f98fe1001598876455c88e8f69
lib/codeql/rust/elements/internal/generated/MacroRules.qll 4fbd94f22b5ee0f3e5aaae39c2b9a5e9b7bf878a1017811ca589942f6de92843 49fb69543ee867bae196febea6918e621f335afdf4d3ccbf219965b37c7537b1
lib/codeql/rust/elements/internal/generated/MacroStmts.qll cb4f3c2721a4d0c8522e51f567c675f4fc95f39bac8a2bd97e125d5553515ad2 09b5a739ccee75e6c556b34ecd6f78c7dc799029d9bc7df2e6169098d24f0ccd
lib/codeql/rust/elements/internal/generated/MacroType.qll c462824df4a002956c036966d15cd0bce206e664888f8d0c7834dedb38b3c0bf 947480f07c40128ef3d00ad4c3a29a685472b3e20a661680c22f6bb318205ed1
lib/codeql/rust/elements/internal/generated/MatchArm.qll 8fb740a0f2e308782d9cf390672969cd7cf6e698e5b847fb02ae3fa6c205646f 42bfe8dd94fc24ec925fbd44016df111600f99d1216c9a698631373bb6048830
lib/codeql/rust/elements/internal/generated/MatchArmList.qll 13362680c037fe83fef4653562cc10a4429078316b5ec7c47b076336cf4aca2e 41c674293c13eceaca62134ae0c6778541f6a5201cbc5c146f0ba01b898dc267
@@ -539,7 +546,7 @@ lib/codeql/rust/elements/internal/generated/ParamList.qll c808c9d84dd7800573832b
lib/codeql/rust/elements/internal/generated/ParenExpr.qll bc0731505bfe88516205ec360582a4222d2681d11342c93e15258590ddee82f2 d4bd6e0c80cf1d63746c88d4bcb3a01d4c75732e5da09e3ebd9437ced227fb60
lib/codeql/rust/elements/internal/generated/ParenPat.qll ce24b8f8ecbf0f204af200317405724063887257460c80cf250c39b2fdf37185 e7c87d37e1a0ca7ea03840017e1aa9ddb7f927f1f3b6396c0305b46aeee33db6
lib/codeql/rust/elements/internal/generated/ParenType.qll 9cc954d73f8330dcac7b475f97748b63af5c8766dee9d2f2872c0a7e4c903537 c07534c8a9c683c4a9b11d490095647e420de0a0bfc23273eaf6f31b00244273
lib/codeql/rust/elements/internal/generated/ParentChild.qll 4af9df75abf8215aa746c9063368911ee94f84b91d71ccf8e6f3acdab02adc03 08855e899a703d5ed63d63db7749ab353367166987ac56ae10875d93975f934a
lib/codeql/rust/elements/internal/generated/ParentChild.qll 823b35d9802fab617be5c76327d65a3e52abd4be72bbc36d93e673cea7a9baaf 9d58eb407d0a929aefc0f4d532ef39dded81f6a370b6735ef581709c82ff9bc6
lib/codeql/rust/elements/internal/generated/Pat.qll 3605ac062be2f294ee73336e9669027b8b655f4ad55660e1eab35266275154ee 7f9400db2884d336dd1d21df2a8093759c2a110be9bf6482ce8e80ae0fd74ed4
lib/codeql/rust/elements/internal/generated/Path.qll 299abce24762a5ab023f3cf1ab9718b83047e171aed42a8092e7a155914b1657 db1a23d18640c548f08c9f94823838b5e019ac85877c7b15df2d1493d1846572
lib/codeql/rust/elements/internal/generated/PathExpr.qll 17cdb0a7393258a207450f08e37178fc9d35d167f064ba6015be94246f3dc933 a75fdd280aff6d87e083a92030e041c2eb52b57cf7151d4a6989fcd31d6a64bf
@@ -551,7 +558,7 @@ lib/codeql/rust/elements/internal/generated/PtrType.qll 40099c5a4041314b66932dfd
lib/codeql/rust/elements/internal/generated/PureSynthConstructors.qll dc03515d678ba052c2ff2dd9f0883e0bce54cac740ba9a15e5173f292c1b6971 dc03515d678ba052c2ff2dd9f0883e0bce54cac740ba9a15e5173f292c1b6971
lib/codeql/rust/elements/internal/generated/RangeExpr.qll 23cca03bf43535f33b22a38894f70d669787be4e4f5b8fe5c8f7b964d30e9027 18624cef6c6b679eeace2a98737e472432e0ead354cca02192b4d45330f047c9
lib/codeql/rust/elements/internal/generated/RangePat.qll efd93730de217cf50dcba5875595263a5eadf9f7e4e1272401342a094d158614 229b251b3d118932e31e78ac4dfb75f48b766f240f20d436062785606d44467b
lib/codeql/rust/elements/internal/generated/Raw.qll ff4874c063c0338443293c807108ecdb878ff2a6a97932c2bafe1c5d2a5486ed 4db42119a06518aeb33bfe9156d884e046afff540c98f07fa81c22bb11c063ad
lib/codeql/rust/elements/internal/generated/Raw.qll 429057964308876b8186a0ca901634273d91b783e4bb85aa5e47860010f4da0b feb8231d0b724fedb1d9d2a65d4a8759ae58baec902b44e3bebdb81a7fbc1fd1
lib/codeql/rust/elements/internal/generated/RecordExpr.qll eb6cb662e463f9260efae1a6ce874fa781172063b916ef1963f861e9942d308d 1a21cbccc8f3799ff13281e822818ebfb21d81591720a427cac3625512cb9d40
lib/codeql/rust/elements/internal/generated/RecordExprField.qll 7e9f8663d3b74ebbc9603b10c9912f082febba6bd73d344b100bbd3edf837802 fbe6b578e7fd5d5a6f21bbb8c388957ab7210a6a249ec71510a50fb35b319ea1
lib/codeql/rust/elements/internal/generated/RecordExprFieldList.qll 179a97211fe7aa6265085d4d54115cdbc0e1cd7c9b2135591e8f36d6432f13d3 dd44bbbc1e83a1ed3a587afb729d7debf7aeb7b63245de181726af13090e50c0
@@ -576,8 +583,8 @@ lib/codeql/rust/elements/internal/generated/Static.qll 5fbd6879858cf356d4bdaa6da
lib/codeql/rust/elements/internal/generated/Stmt.qll 8473ff532dd5cc9d7decaddcd174b94d610f6ca0aec8e473cc051dad9f3db917 6ef7d2b5237c2dbdcacbf7d8b39109d4dc100229f2b28b5c9e3e4fbf673ba72b
lib/codeql/rust/elements/internal/generated/StmtList.qll a667193e32341e17400867c6e359878c4e645ef9f5f4d97676afc0283a33a026 a320ed678ee359302e2fc1b70a9476705cd616fcfa44a499d32f0c7715627f73
lib/codeql/rust/elements/internal/generated/Struct.qll 4d57f0db12dc7ad3e31e750a24172ef1505406b4dab16386af0674bd18bf8f4b 1a73c83df926b996f629316f74c61ea775be04532ab61b56af904223354f033e
lib/codeql/rust/elements/internal/generated/Synth.qll 277fd5258498732937682a2b6982405b6cb515f4631a6e0dc6f1a2545ffa54cb 0d3db7534cf9c1c73fc5863b9048f8bca4fe69615e9cdba8f521c36f02155878
lib/codeql/rust/elements/internal/generated/SynthConstructors.qll 518b68ccf6d0791bc0c141486261108bb1723e37743fc7f8e4167a1d61660531 518b68ccf6d0791bc0c141486261108bb1723e37743fc7f8e4167a1d61660531
lib/codeql/rust/elements/internal/generated/Synth.qll dd9d72a46cf446af025cd7b0085f3780ee7bf7d09a458d3ae6f495e999d342c8 cda06e3155f1a3eecc5ee8ec8097d5362234b44f815aff9bc3940860435262b3
lib/codeql/rust/elements/internal/generated/SynthConstructors.qll 5d30b6d4f36791637f250734ee38820102c64f196454e20f79e30097da1a8e20 5d30b6d4f36791637f250734ee38820102c64f196454e20f79e30097da1a8e20
lib/codeql/rust/elements/internal/generated/Token.qll 77a91a25ca5669703cf3a4353b591cef4d72caa6b0b9db07bb9e005d69c848d1 2fdffc4882ed3a6ca9ac6d1fb5f1ac5a471ca703e2ffdc642885fa558d6e373b
lib/codeql/rust/elements/internal/generated/TokenTree.qll 8577c2b097c1be2f0f7daa5acfcf146f78674a424d99563e08a84dd3e6d91b46 d2f30764e84dbfc0a6a5d3d8a5f935cd432413688cb32da9c94e420fbc10665c
lib/codeql/rust/elements/internal/generated/Trait.qll a570fa93d0b78a35766b00d5ca256c102f824564248b9d8b678a981d6eea3e2e d9c7475e5102e21cfdee3b1791f89a4f9cdba5a4200349ff706532b704c02664
@@ -611,7 +618,7 @@ lib/codeql/rust/elements/internal/generated/WhileExpr.qll fec8a9211b82a80601bf73
lib/codeql/rust/elements/internal/generated/WildcardPat.qll d74b70b57a0a66bfae017a329352a5b27a6b9e73dd5521d627f680e810c6c59e 4b913b548ba27ff3c82fcd32cf996ff329cb57d176d3bebd0fcef394486ea499
lib/codeql/rust/elements/internal/generated/YeetExpr.qll cac328200872a35337b4bcb15c851afb4743f82c080f9738d295571eb01d7392 94af734eea08129b587fed849b643e7572800e8330c0b57d727d41abda47930b
lib/codeql/rust/elements/internal/generated/YieldExpr.qll 37e5f0c1e373a22bbc53d8b7f2c0e1f476e5be5080b8437c5e964f4e83fad79a 4a9a68643401637bf48e5c2b2f74a6bf0ddcb4ff76f6bffb61d436b685621e85
lib/codeql/rust/elements.qll 0e469834ccc4b5db3d35d9521d98e3c8b1911f8c5cd70d35d4cd52cb81c73722 0e469834ccc4b5db3d35d9521d98e3c8b1911f8c5cd70d35d4cd52cb81c73722
lib/codeql/rust/elements.qll ef8063c90411cb957c776756837a4c7ad43aa4eeb52595786e8b2b96dc10ebff ef8063c90411cb957c776756837a4c7ad43aa4eeb52595786e8b2b96dc10ebff
test/extractor-tests/generated/Abi/Abi.ql 7f6e7dc4af86eca3ebdc79b10373988cd0871bd78b51997d3cffd969105e5fdd 2f936b6ca005c6157c755121584410c03e4a3949c23bee302fbe05ee10ce118f
test/extractor-tests/generated/Abi/Abi_getAbiString.ql a496762fcec5a0887b87023bbf93e9b650f02e20113e25c44d6e4281ae8f5335 14109c7ce11ba25e3cd6e7f1b3fcb4cb00622f2a4eac91bfe43145c5f366bc52
test/extractor-tests/generated/ArgList/ArgList.ql e412927756e72165d0e7c5c9bd3fca89d08197bbf760db8fb7683c64bb2229bc 043dba8506946fbb87753e22c387987d7eded6ddb963aa067f9e60ef9024d684
@@ -814,8 +821,9 @@ test/extractor-tests/generated/LoopExpr/LoopExpr.ql 636c28bff5f8c1ca0fb834f614b3
test/extractor-tests/generated/LoopExpr/LoopExpr_getAttr.ql d557c1a34ae8762b32702d6b50e79c25bc506275c33a896b6b94bbbe73d04c49 34846c9eefa0219f4a16e28b518b2afa23f372d0aa03b08d042c5a35375e0cd6
test/extractor-tests/generated/LoopExpr/LoopExpr_getLabel.ql 0b77b9d9fb5903d37bce5a2c0d6b276e6269da56fcb37b83cd931872fb88490f c7f09c526e59dcadec13ec9719980d68b8619d630caab2c26b8368b06c1f2cc0
test/extractor-tests/generated/LoopExpr/LoopExpr_getLoopBody.ql 0267f54077640f3dfeb38524577e4a1229115eeb1c839398d0c5f460c1d65129 96ec876635b8c561f7add19e57574444f630eae3df9ab9bc33ac180e61f3a7b8
test/extractor-tests/generated/MacroCall/MacroCall.ql d8b71880ffbfa0f9efa56c598a9bdd3f91e85129e0f8f2b30be6862556f87fcd 682736663ad11f9fdde165904324a8b2f3cdc59f91196a1accb1cd4cf5fb70d4
test/extractor-tests/generated/MacroCall/MacroCall.ql 9eca338d7bc42dcfc3cfcd7953484d724d4f06b1182c01a426925d9963820e37 25fe9e90c38d3bd0c92c70bf2af01b034e3c375f3dbd1c1b8aab1fc1aae09547
test/extractor-tests/generated/MacroCall/MacroCall_getAttr.ql c22a2a29d705e85b03a6586d1eda1a2f4f99f95f7dfeb4e6908ec3188b5ad0ad 9b8d9dcc2116a123c15c520a880efab73ade20e08197c64bc3ed0c50902c4672
test/extractor-tests/generated/MacroCall/MacroCall_getExpanded.ql 757c4a4c32888e4604044c798a3180aa6d4f73381eec9bc28ba9dc71ffcbd03a 27d5edaa2c1096a24c86744aaad0f006da20d5caa28ccfd8528e7c98aa1bead1
test/extractor-tests/generated/MacroCall/MacroCall_getPath.ql 160edc6a001a2d946da6049ffb21a84b9a3756e85f9a2fb0a4d85058124b399a 1e25dd600f19ef89a99f328f86603bce12190220168387c5a88bfb9926da56d9
test/extractor-tests/generated/MacroCall/MacroCall_getTokenTree.ql 1cbf6b1ac7fa0910ff299b939743153fc00ad7e28a9a70c69a8297c6841e8238 570380c0dc4b20fe25c0499378569720a6da14bdb058e73d757e174bdd62d0c0
test/extractor-tests/generated/MacroDef/MacroDef.ql dde2df9196800d9af9645fe21786e30245bff6cfa58117900582ce1f5c0b859d 6b87bec4e4df8e9b6ed09f18e7b7c20204c39c8d249494cc66d3a06ae39791e4
@@ -826,6 +834,8 @@ test/extractor-tests/generated/MacroDef/MacroDef_getName.ql 6bc8a17804f23782e98f
test/extractor-tests/generated/MacroDef/MacroDef_getVisibility.ql d858ccaab381432c529bf4a621afc82ea5e4b810b463f2b1f551de79908e14e7 83a85c4f90417ab44570a862642d8f8fc9208e62ba20ca69b32d39a3190381aa
test/extractor-tests/generated/MacroExpr/MacroExpr.ql 69445cf24f5bec5c3f11f0ebf13604891bb2c0dffe715612628e5572587c7a6c 5434db79d94e437c86126d9cf20bf1e86e5537f462a57b9bf6b22a2caa95cc40
test/extractor-tests/generated/MacroExpr/MacroExpr_getMacroCall.ql 8859743e23b987225a6a1933054a1ed8f5f1442b61a769599e2efd143f4feb9e d2d336135ff4d2ea65e79430dee8d0f69f9d7818a674f5446903d986f3948b92
test/extractor-tests/generated/MacroItems/MacroItems.ql 876b5d2a4ce7dcb599e022083ff3f2d57300bcb0ea05f61069d59ad58353ca69 61ea54d4633ef871d3e634069e39fbb2545f7dc2796fa66f8edbacd4e0aa4ef5
test/extractor-tests/generated/MacroItems/MacroItems_getItem.ql 53fc2db35a23b9aca6ee327d2a51202d23ddf482e6bdd92c5399b7f3a73959b1 63051c8b7a7bfbe9cc640f775e753c9a82f1eb8472989f7d3c8af94fdf26c7a0
test/extractor-tests/generated/MacroPat/MacroPat.ql d9ec72d4d6a7342ee2d9aa7e90227faa31792ca5842fe948d7fdf22597a123b7 74b0f21ef2bb6c13aae74dba1eea97451755110909a083360e2c56cfbc76fd91
test/extractor-tests/generated/MacroPat/MacroPat_getMacroCall.ql 398996f0d0f2aa6d3b58d80b26c7d1185b5094d455c6c5c7f075f6d414150aa6 b4662e57cac36ed0e692201f53ba46c3d0826bba99c5cc6dfcb302b44dd2154b
test/extractor-tests/generated/MacroRules/MacroRules.ql 0742faf18179fa34e0f43361e9e4b807bfc242d232f6b3664a35e138a47d39c5 10e1cf45f32a27cb46bd61f5dd45416e2c0c9f25e880f6d213597a7d96e19103
@@ -833,6 +843,9 @@ test/extractor-tests/generated/MacroRules/MacroRules_getAttr.ql 7de501c724e34655
test/extractor-tests/generated/MacroRules/MacroRules_getName.ql 591606e3accae8b8fb49e1218c4867a42724ac209cf99786db0e5d7ea0bf55d5 d2936ef5aa4bbf024372516dde3de578990aafb2b8675bbbf0f72e8b54eb82a8
test/extractor-tests/generated/MacroRules/MacroRules_getTokenTree.ql 7598d33c3d86f9ad8629219b90667b2b65e3a1e18c6b0887291df9455a319cab 69d90446743e78e851145683c17677497fe42ed02f61f2b2974e216dc6e05b01
test/extractor-tests/generated/MacroRules/MacroRules_getVisibility.ql 5306cc85f470d21ebcbe6e98436334b0bf5ba819a0ae186569ba7e88c31636c6 fcbf5c54e5a904767a6f4d37d853072aa0040738e622c49c9a02dec8739d6587
test/extractor-tests/generated/MacroStmts/MacroStmts.ql 991042263ba99acef0972697ce79132e5650b27bf53be2f975a0da1f29940fd8 64c44e65b3c5d3de5f9532b4ff7ce54b39442b37f63da8b10d789b9b52b85a9e
test/extractor-tests/generated/MacroStmts/MacroStmts_getExpr.ql 5717f20376600e7bf5e471beae1a7c0084f235f0931f8b3f25d2de94ebb86f8b e4685fd9d45b078a6402c285eed3a15cc4550f6656c8bc5e7e274a88d1c7e9b3
test/extractor-tests/generated/MacroStmts/MacroStmts_getStatement.ql 8958b2212776f487869c29314e7d28f5871f5c3dde62fd9d6f87fb9e94204498 6804f5d4c0c5909689bdcdd5b8ec11ca7a8c0399b47695f66d2f99e39561565a
test/extractor-tests/generated/MacroType/MacroType.ql 408327fdb4d7cf096536457401cc280f83cd7e4f6fa9aebd65e64031f6c119cf 0c502d25194ab96eb068a85e3f57a9217510a951fa923e9d7a20fd75412bd6da
test/extractor-tests/generated/MacroType/MacroType_getMacroCall.ql 565be7a72670218d7999d3f6cec4e704b754c217186243f1b24c334589fa82e2 ba413c712783320188800e2a78738b09c40fe9a6305c08d9e67e971a8fca96ee
test/extractor-tests/generated/MatchArm/MatchArm.ql 512aa404c94ba40b859564f07e9dffe6a5e687fafb039556e9145f4f3742981c 529f96e38cede8a26054f8981d4ba1d189c17d14d0f92d622eb20acd8f3d7e5d

15
rust/ql/.gitattributes generated vendored
View File

@@ -71,8 +71,10 @@
/lib/codeql/rust/elements/MacroCall.qll linguist-generated
/lib/codeql/rust/elements/MacroDef.qll linguist-generated
/lib/codeql/rust/elements/MacroExpr.qll linguist-generated
/lib/codeql/rust/elements/MacroItems.qll linguist-generated
/lib/codeql/rust/elements/MacroPat.qll linguist-generated
/lib/codeql/rust/elements/MacroRules.qll linguist-generated
/lib/codeql/rust/elements/MacroStmts.qll linguist-generated
/lib/codeql/rust/elements/MacroType.qll linguist-generated
/lib/codeql/rust/elements/MatchArm.qll linguist-generated
/lib/codeql/rust/elements/MatchArmList.qll linguist-generated
@@ -280,10 +282,14 @@
/lib/codeql/rust/elements/internal/MacroDefImpl.qll linguist-generated
/lib/codeql/rust/elements/internal/MacroExprConstructor.qll linguist-generated
/lib/codeql/rust/elements/internal/MacroExprImpl.qll linguist-generated
/lib/codeql/rust/elements/internal/MacroItemsConstructor.qll linguist-generated
/lib/codeql/rust/elements/internal/MacroItemsImpl.qll linguist-generated
/lib/codeql/rust/elements/internal/MacroPatConstructor.qll linguist-generated
/lib/codeql/rust/elements/internal/MacroPatImpl.qll linguist-generated
/lib/codeql/rust/elements/internal/MacroRulesConstructor.qll linguist-generated
/lib/codeql/rust/elements/internal/MacroRulesImpl.qll linguist-generated
/lib/codeql/rust/elements/internal/MacroStmtsConstructor.qll linguist-generated
/lib/codeql/rust/elements/internal/MacroStmtsImpl.qll linguist-generated
/lib/codeql/rust/elements/internal/MacroTypeConstructor.qll linguist-generated
/lib/codeql/rust/elements/internal/MacroTypeImpl.qll linguist-generated
/lib/codeql/rust/elements/internal/MatchArmConstructor.qll linguist-generated
@@ -310,7 +316,6 @@
/lib/codeql/rust/elements/internal/OffsetOfExprConstructor.qll linguist-generated
/lib/codeql/rust/elements/internal/OffsetOfExprImpl.qll linguist-generated
/lib/codeql/rust/elements/internal/OrPatConstructor.qll linguist-generated
/lib/codeql/rust/elements/internal/OrPatImpl.qll linguist-generated
/lib/codeql/rust/elements/internal/ParamConstructor.qll linguist-generated
/lib/codeql/rust/elements/internal/ParamImpl.qll linguist-generated
/lib/codeql/rust/elements/internal/ParamListConstructor.qll linguist-generated
@@ -520,8 +525,10 @@
/lib/codeql/rust/elements/internal/generated/MacroCall.qll linguist-generated
/lib/codeql/rust/elements/internal/generated/MacroDef.qll linguist-generated
/lib/codeql/rust/elements/internal/generated/MacroExpr.qll linguist-generated
/lib/codeql/rust/elements/internal/generated/MacroItems.qll linguist-generated
/lib/codeql/rust/elements/internal/generated/MacroPat.qll linguist-generated
/lib/codeql/rust/elements/internal/generated/MacroRules.qll linguist-generated
/lib/codeql/rust/elements/internal/generated/MacroStmts.qll linguist-generated
/lib/codeql/rust/elements/internal/generated/MacroType.qll linguist-generated
/lib/codeql/rust/elements/internal/generated/MatchArm.qll linguist-generated
/lib/codeql/rust/elements/internal/generated/MatchArmList.qll linguist-generated
@@ -818,6 +825,7 @@
/test/extractor-tests/generated/LoopExpr/LoopExpr_getLoopBody.ql linguist-generated
/test/extractor-tests/generated/MacroCall/MacroCall.ql linguist-generated
/test/extractor-tests/generated/MacroCall/MacroCall_getAttr.ql linguist-generated
/test/extractor-tests/generated/MacroCall/MacroCall_getExpanded.ql linguist-generated
/test/extractor-tests/generated/MacroCall/MacroCall_getPath.ql linguist-generated
/test/extractor-tests/generated/MacroCall/MacroCall_getTokenTree.ql linguist-generated
/test/extractor-tests/generated/MacroDef/MacroDef.ql linguist-generated
@@ -828,6 +836,8 @@
/test/extractor-tests/generated/MacroDef/MacroDef_getVisibility.ql linguist-generated
/test/extractor-tests/generated/MacroExpr/MacroExpr.ql linguist-generated
/test/extractor-tests/generated/MacroExpr/MacroExpr_getMacroCall.ql linguist-generated
/test/extractor-tests/generated/MacroItems/MacroItems.ql linguist-generated
/test/extractor-tests/generated/MacroItems/MacroItems_getItem.ql linguist-generated
/test/extractor-tests/generated/MacroPat/MacroPat.ql linguist-generated
/test/extractor-tests/generated/MacroPat/MacroPat_getMacroCall.ql linguist-generated
/test/extractor-tests/generated/MacroRules/MacroRules.ql linguist-generated
@@ -835,6 +845,9 @@
/test/extractor-tests/generated/MacroRules/MacroRules_getName.ql linguist-generated
/test/extractor-tests/generated/MacroRules/MacroRules_getTokenTree.ql linguist-generated
/test/extractor-tests/generated/MacroRules/MacroRules_getVisibility.ql linguist-generated
/test/extractor-tests/generated/MacroStmts/MacroStmts.ql linguist-generated
/test/extractor-tests/generated/MacroStmts/MacroStmts_getExpr.ql linguist-generated
/test/extractor-tests/generated/MacroStmts/MacroStmts_getStatement.ql linguist-generated
/test/extractor-tests/generated/MacroType/MacroType.ql linguist-generated
/test/extractor-tests/generated/MacroType/MacroType_getMacroCall.ql linguist-generated
/test/extractor-tests/generated/MatchArm/MatchArm.ql linguist-generated

View File

@@ -0,0 +1,19 @@
import codeql.rust.dataflow.Ssa
import codeql.rust.dataflow.internal.SsaImpl
import Consistency
class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
class MyRelevantDefinitionExt extends RelevantDefinitionExt, DefinitionExt {
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}

View File

@@ -36,7 +36,13 @@ class SimpleCompletion extends NormalCompletion, TSimpleCompletion {
// `SimpleCompletion` is the "default" completion type, thus it is valid for
// any node where there isn't another more specific completion type.
override predicate isValidFor(AstNode e) { not any(Completion c).isValidForSpecific(e) }
override predicate isValidFor(AstNode e) {
not any(Completion c).isValidForSpecific(e)
or
// A `?` expression can both proceed normally or cause an early return, so
// we explicitly allow the former here.
e instanceof TryExpr
}
override string toString() { result = "simple" }
}
@@ -62,7 +68,7 @@ abstract class ConditionalCompletion extends NormalCompletion {
abstract ConditionalCompletion getDual();
}
/** Holds if node `le` has the Boolean constant value `value`. */
/** Holds if node `le` has the constant Boolean value `value`. */
private predicate isBooleanConstant(LiteralExpr le, Boolean value) {
le.getTextValue() = value.toString()
}
@@ -117,13 +123,61 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion {
override string toString() { result = "boolean(" + value + ")" }
}
/** Holds if `pat` is guaranteed to match at the point in the AST where it occurs. */
pragma[nomagic]
private predicate isExhaustiveMatch(Pat pat) {
(
pat instanceof WildcardPat
or
pat = any(IdentPat ip | not ip.hasPat() and ip = any(Variable v).getPat())
or
pat instanceof RestPat
or
// `let` statements without an `else` branch must be exhaustive
pat = any(LetStmt let | not let.hasLetElse()).getPat()
or
// `match` expressions must be exhaustive, so last arm cannot fail
pat = any(MatchExpr me).getLastArm().getPat()
or
// macro invocations are exhaustive if their expansion is
pat = any(MacroPat mp | isExhaustiveMatch(mp.getMacroCall().getExpanded()))
or
// parameter patterns must be exhaustive
pat = any(Param p).getPat()
) and
not pat = any(ForExpr for).getPat() // workaround until `for` loops are desugared
or
exists(Pat parent | isExhaustiveMatch(parent) |
pat = parent.(BoxPat).getPat()
or
pat = parent.(IdentPat).getPat()
or
pat = parent.(MacroPat).getMacroCall().getExpanded()
or
pat = parent.(ParenPat).getPat()
or
pat = parent.(RecordPat).getRecordPatFieldList().getField(_).getPat()
or
pat = parent.(RefPat).getPat()
or
pat = parent.(TuplePat).getAField()
or
pat = parent.(TupleStructPat).getAField()
or
pat = parent.(OrPat).getLastPat()
)
}
/**
* A completion that represents the result of a pattern match.
*/
class MatchCompletion extends TMatchCompletion, ConditionalCompletion {
MatchCompletion() { this = TMatchCompletion(value) }
override predicate isValidForSpecific(AstNode e) { e instanceof Pat }
override predicate isValidForSpecific(AstNode e) {
e instanceof Pat and
if isExhaustiveMatch(e) then value = true else any()
}
override MatchSuccessor getAMatchingSuccessorType() { result.getValue() = value }
@@ -161,7 +215,9 @@ class ContinueCompletion extends TContinueCompletion, Completion {
class ReturnCompletion extends TReturnCompletion, Completion {
override ReturnSuccessor getAMatchingSuccessorType() { any() }
override predicate isValidForSpecific(AstNode e) { e instanceof ReturnExpr }
override predicate isValidForSpecific(AstNode e) {
e instanceof ReturnExpr or e instanceof TryExpr
}
override string toString() { result = "return" }
}

View File

@@ -65,9 +65,6 @@ private module CfgImpl =
import CfgImpl
/** Holds if `p` is a trivial pattern that is always guaranteed to match. */
predicate trivialPat(Pat p) { p instanceof WildcardPat or p instanceof IdentPat }
class ArrayExprTree extends StandardPostOrderTree, ArrayExpr {
override AstNode getChildNode(int i) { result = this.getExpr(i) }
}
@@ -141,11 +138,10 @@ class LogicalAndTree extends PostOrderTree, LogicalAndExpr {
class BlockExprTree extends StandardPostOrderTree, BlockExpr {
override AstNode getChildNode(int i) {
result = super.getStmtList().getStatement(i)
result = this.getStmtList().getStatement(i)
or
not exists(super.getStmtList().getStatement(i)) and
(exists(super.getStmtList().getStatement(i - 1)) or i = 0) and
result = super.getStmtList().getTailExpr()
i = this.getStmtList().getNumberOfStatements() and
result = this.getStmtList().getTailExpr()
}
override predicate propagatesAbnormal(AstNode child) { child = this.getChildNode(_) }
@@ -183,7 +179,23 @@ class CastExprTree extends StandardPostOrderTree instanceof CastExpr {
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
}
class ClosureExprTree extends LeafTree instanceof ClosureExpr { }
class ClosureExprTree extends StandardTree, ClosureExpr {
override predicate first(AstNode first) { first = this }
override predicate last(AstNode last, Completion c) {
last = this and
completionIsValidFor(c, this)
}
override predicate propagatesAbnormal(AstNode child) { none() }
override AstNode getChildNode(int i) {
result = this.getParamList().getParam(i)
or
i = this.getParamList().getNumberOfParams() and
result = this.getBody()
}
}
class ContinueExprTree extends LeafTree, ContinueExpr {
override predicate last(AstNode last, Completion c) { none() }
@@ -203,7 +215,27 @@ class FieldExprTree extends StandardPostOrderTree instanceof FieldExpr {
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
}
class FunctionTree extends LeafTree instanceof Function { }
class FunctionTree extends StandardTree, Function {
override predicate first(AstNode first) { first = this }
override predicate last(AstNode last, Completion c) {
last = this and
completionIsValidFor(c, this)
}
override predicate propagatesAbnormal(AstNode child) { none() }
override AstNode getChildNode(int i) {
result = this.getParamList().getParam(i)
or
i = this.getParamList().getNumberOfParams() and
result = this.getBody()
}
}
class ParamTree extends StandardPostOrderTree, Param {
override AstNode getChildNode(int i) { i = 0 and result = this.getPat() }
}
class IfExprTree extends PostOrderTree instanceof IfExpr {
override predicate first(AstNode node) { first(super.getCondition(), node) }
@@ -241,6 +273,14 @@ class IfExprTree extends PostOrderTree instanceof IfExpr {
}
}
class FormatArgsExprTree extends StandardPostOrderTree, FormatArgsExpr {
override AstNode getChildNode(int i) {
i = -1 and result = this.getTemplate()
or
result = this.getArg(i).getExpr()
}
}
class IndexExprTree extends StandardPostOrderTree instanceof IndexExpr {
override AstNode getChildNode(int i) {
i = 0 and result = super.getBase()
@@ -249,53 +289,53 @@ class IndexExprTree extends StandardPostOrderTree instanceof IndexExpr {
}
}
class ItemTree extends LeafTree, Item { }
class ItemTree extends LeafTree, Item {
ItemTree() {
not this instanceof MacroCall and
this = [any(StmtList s).getAStatement(), any(MacroStmts s).getAStatement()]
}
}
// `LetExpr` is a pre-order tree such that the pattern itself ends up
// dominating successors in the graph in the same way that patterns do in
// `match` expressions.
class LetExprTree extends StandardPreOrderTree instanceof LetExpr {
override AstNode getChildNode(int i) { i = 0 and result = super.getPat() }
}
// We handle `let` statements with trivial patterns separately as they don't
// lead to non-standard control flow. For instance, in `let a = ...` it is not
// interesing to create match edges as it would carry no information.
class LetStmtTreeTrivialPat extends StandardPreOrderTree instanceof LetStmt {
LetStmtTreeTrivialPat() { trivialPat(super.getPat()) }
class LetExprTree extends StandardPreOrderTree, LetExpr {
override AstNode getChildNode(int i) {
i = 0 and result = super.getInitializer()
i = 0 and
result = this.getExpr()
or
i = 1 and result = super.getPat()
i = 1 and
result = this.getPat()
}
}
// `let` statements with interesting patterns that we want to be reflected in
// the CFG.
class LetStmtTree extends PreOrderTree instanceof LetStmt {
LetStmtTree() { not trivialPat(super.getPat()) }
class LetStmtTree extends PreOrderTree, LetStmt {
final override predicate propagatesAbnormal(AstNode child) {
child = [super.getInitializer(), super.getLetElse().getBlockExpr()]
child = [this.getInitializer(), this.getLetElse().getBlockExpr()]
}
override predicate succ(AstNode pred, AstNode succ, Completion c) {
// Edge to start of initializer.
pred = this and first(super.getInitializer(), succ) and completionIsSimple(c)
pred = this and first(this.getInitializer(), succ) and completionIsSimple(c)
or
// Edge to pattern when there is no initializer.
pred = this and
first(this.getPat(), succ) and
completionIsSimple(c) and
not this.hasInitializer()
or
// Edge from end of initializer to pattern.
last(super.getInitializer(), pred, c) and first(super.getPat(), succ)
last(this.getInitializer(), pred, c) and first(this.getPat(), succ)
or
// Edge from failed pattern to `else` branch.
last(super.getPat(), pred, c) and
first(super.getLetElse().getBlockExpr(), succ) and
last(this.getPat(), pred, c) and
first(this.getLetElse().getBlockExpr(), succ) and
c.(MatchCompletion).failed()
}
override predicate last(AstNode node, Completion c) {
// Edge out of a successfully matched pattern.
last(super.getPat(), node, c) and c.(MatchCompletion).succeeded()
last(this.getPat(), node, c) and c.(MatchCompletion).succeeded()
// NOTE: No edge out of the `else` branch as that is guaranteed to diverge.
}
}
@@ -391,36 +431,66 @@ class ForExprTree extends LoopingExprTree instanceof ForExpr {
}
}
// TODO: replace with expanded macro once the extractor supports it
class MacroExprTree extends LeafTree, MacroExpr { }
class MacroCallTree extends ControlFlowTree, MacroCall {
override predicate first(AstNode first) {
first(this.getExpanded(), first)
or
not exists(this.getExpanded()) and first = this
}
class MatchArmTree extends ControlFlowTree instanceof MatchArm {
override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() }
override predicate last(AstNode last, Completion c) {
last(this.getExpanded(), last, c)
or
not exists(this.getExpanded()) and
last = this and
completionIsValidFor(c, last)
}
override predicate first(AstNode node) { node = super.getPat() }
override predicate succ(AstNode pred, AstNode succ, Completion c) { none() }
override predicate propagatesAbnormal(AstNode child) { child = this.getExpanded() }
}
class MacroExprTree extends StandardPostOrderTree, MacroExpr {
override AstNode getChildNode(int i) { i = 0 and result = this.getMacroCall() }
}
class MacroStmtsTree extends StandardPreOrderTree, MacroStmts {
override AstNode getChildNode(int i) {
result = this.getStatement(i)
or
i = this.getNumberOfStatements() and
result = this.getExpr()
}
}
class MatchArmTree extends ControlFlowTree, MatchArm {
override predicate propagatesAbnormal(AstNode child) { child = this.getExpr() }
override predicate first(AstNode node) { first(this.getPat(), node) }
override predicate succ(AstNode pred, AstNode succ, Completion c) {
// Edge from pattern to guard/arm if match succeeds.
pred = super.getPat() and
last(this.getPat(), pred, c) and
c.(MatchCompletion).succeeded() and
(
first(super.getGuard().getCondition(), succ)
first(this.getGuard().getCondition(), succ)
or
not super.hasGuard() and first(super.getExpr(), succ)
not this.hasGuard() and first(this.getExpr(), succ)
)
or
// Edge from guard to arm if the guard succeeds.
last(super.getGuard().getCondition(), pred, c) and
first(super.getExpr(), succ) and
last(this.getGuard().getCondition(), pred, c) and
first(this.getExpr(), succ) and
c.(BooleanCompletion).succeeded()
}
override predicate last(AstNode node, Completion c) {
node = super.getPat() and c.(MatchCompletion).failed()
last(this.getPat(), node, c) and c.(MatchCompletion).failed()
or
last(super.getGuard().getCondition(), node, c) and c.(BooleanCompletion).failed()
last(this.getGuard().getCondition(), node, c) and c.(BooleanCompletion).failed()
or
last(super.getExpr(), node, c)
last(this.getExpr(), node, c)
}
}
@@ -433,7 +503,9 @@ class MatchExprTree extends PostOrderTree instanceof MatchExpr {
override predicate succ(AstNode pred, AstNode succ, Completion c) {
// Edge from the scrutinee to the first arm.
last(super.getExpr(), pred, c) and succ = super.getArm(0).getPat()
last(super.getExpr(), pred, c) and
first(super.getArm(0).getPat(), succ) and
completionIsNormal(c)
or
// Edge from a failed match/guard in one arm to the beginning of the next arm.
exists(int i |
@@ -447,10 +519,12 @@ class MatchExprTree extends PostOrderTree instanceof MatchExpr {
}
}
class MethodCallExprTree extends StandardPostOrderTree instanceof MethodCallExpr {
class MethodCallExprTree extends StandardPostOrderTree, MethodCallExpr {
override AstNode getChildNode(int i) {
result = super.getReceiver() and
result = super.getArgList().getArg(i + 1)
i = 0 and
result = this.getReceiver()
or
result = this.getArgList().getArg(i + 1)
}
}
@@ -474,9 +548,6 @@ class ParenExprTree extends ControlFlowTree, ParenExpr {
override predicate succ(AstNode pred, AstNode succ, Completion c) { none() }
}
// This covers all patterns as they all extend `Pat`
class PatExprTree extends LeafTree instanceof Pat { }
class PathExprTree extends LeafTree instanceof PathExpr { }
class PrefixExprTree extends StandardPostOrderTree instanceof PrefixExpr {
@@ -501,18 +572,12 @@ class RefExprTree extends StandardPostOrderTree instanceof RefExpr {
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
}
class ReturnExprTree extends PostOrderTree instanceof ReturnExpr {
override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() }
class ReturnExprTree extends StandardPostOrderTree instanceof ReturnExpr {
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
}
override predicate first(AstNode node) {
first(super.getExpr(), node)
or
not super.hasExpr() and node = this
}
override predicate succ(AstNode pred, AstNode succ, Completion c) {
last(super.getExpr(), pred, c) and succ = this and completionIsNormal(c)
}
class TryExprTree extends StandardPostOrderTree instanceof TryExpr {
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
}
class TupleExprTree extends StandardPostOrderTree instanceof TupleExpr {
@@ -532,3 +597,166 @@ class YieldExprTree extends StandardPostOrderTree instanceof YieldExpr {
class YeetExprTree extends StandardPostOrderTree instanceof YeetExpr {
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
}
/**
* Provides `ControlFlowTree`s for patterns.
*
* Since patterns destruct values, they are modeled in pre-order, except for
* `OrPat`s and `IdentPat`s.
*/
module PatternTrees {
abstract class PreOrderPatTree extends PreOrderTree {
abstract Pat getPat(int i);
private Pat getPatRanked(int i) {
result = rank[i + 1](Pat pat, int j | pat = this.getPat(j) | pat order by j)
}
override predicate propagatesAbnormal(AstNode child) { child = this.getPatRanked(_) }
override predicate succ(AstNode pred, AstNode succ, Completion c) {
pred = this and
completionIsValidFor(c, this) and
c.(MatchCompletion).succeeded() and
first(this.getPatRanked(0), succ)
or
exists(int i | last(this.getPatRanked(i), pred, c) |
// Edge from successful pattern to the next
c.(MatchCompletion).succeeded() and
first(this.getPatRanked(i + 1), succ)
)
}
override predicate last(AstNode node, Completion c) {
node = this and
completionIsValidFor(c, this) and
c.(MatchCompletion).failed()
or
exists(int i | last(this.getPatRanked(i), node, c) |
c.(MatchCompletion).failed()
or
not exists(this.getPatRanked(i + 1)) and
completionIsNormal(c)
)
}
}
abstract class PostOrderPatTree extends PostOrderTree {
abstract Pat getPat(int i);
private Pat getPatRanked(int i) {
result = rank[i + 1](Pat pat, int j | pat = this.getPat(j) | pat order by j)
}
override predicate propagatesAbnormal(AstNode child) { child = this.getPatRanked(_) }
override predicate first(AstNode node) {
first(this.getPat(0), node)
or
not exists(this.getPat(_)) and
node = this
}
override predicate succ(AstNode pred, AstNode succ, Completion c) {
exists(int i | last(this.getPat(i), pred, c) |
// Edge from unsuccessful pattern to the next
c.(MatchCompletion).failed() and
first(this.getPat(i + 1), succ)
or
// Edge from successful pattern to this
c.(MatchCompletion).succeeded() and
succ = this
or
// Edge from last pattern to this
not exists(this.getPat(i + 1)) and
succ = this and
completionIsNormal(c)
)
}
}
class IdentPatTree extends PostOrderPatTree, IdentPat {
override Pat getPat(int i) { i = 0 and result = this.getPat() }
override predicate last(AstNode node, Completion c) {
super.last(node, c)
or
last(this.getPat(), node, c) and
c.(MatchCompletion).failed()
}
override predicate succ(AstNode pred, AstNode succ, Completion c) {
super.succ(pred, succ, c) and
not (succ = this and c.(MatchCompletion).failed())
}
}
class BoxPatTree extends PreOrderPatTree, BoxPat {
override Pat getPat(int i) { i = 0 and result = this.getPat() }
}
class RestPatTree extends LeafTree, RestPat { }
class LiteralPatTree extends LeafTree, LiteralPat { }
class MacroPatTree extends PreOrderPatTree, MacroPat {
override Pat getPat(int i) { i = 0 and result = this.getMacroCall().getExpanded() }
}
class OrPatTree extends PostOrderPatTree instanceof OrPat {
override Pat getPat(int i) { result = OrPat.super.getPat(i) }
}
class ParenPatTree extends ControlFlowTree, ParenPat {
private ControlFlowTree pat;
ParenPatTree() { pat = this.getPat() }
override predicate propagatesAbnormal(AstNode child) { pat.propagatesAbnormal(child) }
override predicate first(AstNode first) { pat.first(first) }
override predicate last(AstNode last, Completion c) { pat.last(last, c) }
override predicate succ(AstNode pred, AstNode succ, Completion c) { none() }
}
class PathPatTree extends LeafTree, PathPat { }
class WildcardPatTree extends LeafTree, WildcardPat { }
class RangePatTree extends PreOrderPatTree, RangePat {
override Pat getPat(int i) {
i = 0 and result = this.getStart()
or
i = 1 and result = this.getEnd()
}
}
class RecordPatTree extends PreOrderPatTree, RecordPat {
override Pat getPat(int i) {
result = this.getRecordPatFieldList().getField(i).getPat()
or
i = this.getRecordPatFieldList().getNumberOfFields() and
result = this.getRecordPatFieldList().getRestPat()
}
}
class RefPatTree extends PreOrderPatTree, RefPat {
override Pat getPat(int i) { i = 0 and result = super.getPat() }
}
class SlicePatTree extends PreOrderPatTree instanceof SlicePat {
override Pat getPat(int i) { result = SlicePat.super.getPat(i) }
}
class TuplePatTree extends PreOrderPatTree, TuplePat {
override Pat getPat(int i) { result = this.getField(i) }
}
class TupleStructPatTree extends PreOrderPatTree, TupleStructPat {
override Pat getPat(int i) { result = this.getField(i) }
}
class ConstBlockPatTree extends LeafTree, ConstBlockPat { } // todo?
}

View File

@@ -12,13 +12,17 @@ abstract class CfgScope extends AstNode {
}
final class FunctionScope extends CfgScope, Function {
override predicate scopeFirst(AstNode node) { first(this.getBody(), node) }
override predicate scopeFirst(AstNode node) {
first(this.(FunctionTree).getFirstChildNode(), node)
}
override predicate scopeLast(AstNode node, Completion c) { last(this.getBody(), node, c) }
}
final class ClosureScope extends CfgScope, ClosureExpr {
override predicate scopeFirst(AstNode node) { first(this.getBody(), node) }
override predicate scopeFirst(AstNode node) {
first(this.(ClosureExprTree).getFirstChildNode(), node)
}
override predicate scopeLast(AstNode node, Completion c) { last(this.getBody(), node, c) }
}

View File

@@ -78,6 +78,11 @@ module ConditionalCompletionSplitting {
child = parent.(MatchExpr).getAnArm().getExpr()
or
child = parent.(BlockExpr).getStmtList().getTailExpr()
or
child = parent.(PatternTrees::PreOrderPatTree).getPat(_) and
childCompletion.(MatchCompletion).failed()
or
child = parent.(PatternTrees::PostOrderPatTree).getPat(_)
)
}
}

View File

@@ -0,0 +1,340 @@
/**
* Provides the module `Ssa` for working with static single assignment (SSA) form.
*/
/**
* Provides classes for working with static single assignment (SSA) form.
*/
module Ssa {
private import rust
private import codeql.rust.controlflow.BasicBlocks
private import codeql.rust.controlflow.ControlFlowGraph
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as CfgImpl
private import internal.SsaImpl as SsaImpl
class Variable = SsaImpl::SsaInput::SourceVariable;
/** A static single assignment (SSA) definition. */
class Definition extends SsaImpl::Definition {
/**
* Gets the control flow node of this SSA definition, if any. Phi nodes are
* examples of SSA definitions without a control flow node, as they are
* modeled at index `-1` in the relevant basic block.
*/
final CfgNode getControlFlowNode() {
exists(BasicBlock bb, int i | this.definesAt(_, bb, i) | result = bb.getNode(i))
}
/**
* Gets a control-flow node that reads the value of this SSA definition.
*
* Example:
*
* ```rust
* fn phi(b : bool) { // defines b_0
* let mut x = 1; // defines x_0
* println!("{}", x); // reads x_0
* println!("{}", x + 1); // reads x_0
*
* if b { // reads b_0
* x = 2; // defines x_1
* println!("{}", x); // reads x_1
* println!("{}", x + 1); // reads x_1
* } else {
* x = 3; // defines x_2
* println!("{}", x); // reads x_2
* println!("{}", x + 1); // reads x_2
* }
* // defines x_3 = phi(x_1, x_2)
* println!("{}", x); // reads x_3
* }
* ```
*/
final CfgNode getARead() { result = SsaImpl::getARead(this) }
/**
* Gets a first control-flow node that reads the value of this SSA definition.
* That is, a read that can be reached from this definition without passing
* through other reads.
*
* Example:
*
* ```rust
* fn phi(b : bool) { // defines b_0
* let mut x = 1; // defines x_0
* println!("{}", x); // first read of x_0
* println!("{}", x + 1);
*
* if b { // first read of b_0
* x = 2; // defines x_1
* println!("{}", x); // first read of x_1
* println!("{}", x + 1);
* } else {
* x = 3; // defines x_2
* println!("{}", x); // first read of x_2
* println!("{}", x + 1);
* }
* // defines x_3 = phi(x_1, x_2)
* println!("{}", x); // first read of x_3
* }
* ```
*/
final CfgNode getAFirstRead() { SsaImpl::firstRead(this, result) }
/**
* Gets a last control-flow node that reads the value of this SSA definition.
* That is, a read that can reach the end of the enclosing CFG scope, or another
* SSA definition for the source variable, without passing through any other read.
*
* Example:
*
* ```rust
* fn phi(b : bool) { // defines b_0
* let mut x = 1; // defines x_0
* println!("{}", x);
* println!("{}", x + 1); // last read of x_0
*
* if b { // last read of b_0
* x = 2; // defines x_1
* println!("{}", x);
* println!("{}", x + 1); // last read of x_1
* } else {
* x = 3; // defines x_2
* println!("{}", x);
* println!("{}", x + 1); // last read of x_2
* }
* // defines x_3 = phi(x_1, x_2)
* println!("{}", x); // last read of x_3
* }
* ```
*/
final CfgNode getALastRead() { SsaImpl::lastRead(this, result) }
/**
* Holds if `read1` and `read2` are adjacent reads of this SSA definition.
* That is, `read2` can be reached from `read1` without passing through
* another read.
*
* Example:
*
* ```rust
* fn phi(b : bool) {
* let mut x = 1; // defines x_0
* println!("{}", x); // reads x_0 (read1)
* println!("{}", x + 1); // reads x_0 (read2)
*
* if b {
* x = 2; // defines x_1
* println!("{}", x); // reads x_1 (read1)
* println!("{}", x + 1); // reads x_1 (read2)
* } else {
* x = 3; // defines x_2
* println!("{}", x); // reads x_2 (read1)
* println!("{}", x + 1); // reads x_2 (read2)
* }
* println!("{}", x);
* }
* ```
*/
final predicate hasAdjacentReads(CfgNode read1, CfgNode read2) {
SsaImpl::adjacentReadPair(this, read1, read2)
}
/**
* Gets an SSA definition whose value can flow to this one in one step. This
* includes inputs to phi nodes and the prior definitions of uncertain writes.
*/
private Definition getAPhiInputOrPriorDefinition() {
result = this.(PhiDefinition).getAnInput()
}
/**
* Gets a definition that ultimately defines this SSA definition and is
* not itself a phi node.
*
* Example:
*
* ```rust
* fn phi(b : bool) {
* let mut x = 1; // defines x_0
* println!("{}", x);
* println!("{}", x + 1);
*
* if b {
* x = 2; // defines x_1
* println!("{}", x);
* println!("{}", x + 1);
* } else {
* x = 3; // defines x_2
* println!("{}", x);
* println!("{}", x + 1);
* }
* // defines x_3 = phi(x_1, x_2); ultimate definitions are x_1 and x_2
* println!("{}", x);
* }
* ```
*/
final Definition getAnUltimateDefinition() {
result = this.getAPhiInputOrPriorDefinition*() and
not result instanceof PhiDefinition
}
override string toString() { result = this.getControlFlowNode().toString() }
/** Gets the scope of this SSA definition. */
CfgScope getScope() { result = this.getBasicBlock().getScope() }
}
/**
* An SSA definition that corresponds to a write. Example:
*
* ```rust
* fn m(i : i64) { // writes `i`
* let mut x = i; // writes `x`
* x = 11; // writes `x`
* }
* ```
*/
class WriteDefinition extends Definition, SsaImpl::WriteDefinition {
private CfgNode write;
WriteDefinition() {
exists(BasicBlock bb, int i, Variable v |
this.definesAt(v, bb, i) and
SsaImpl::variableWriteActual(bb, i, v, write)
)
}
/** Gets the underlying write access. */
final CfgNode getWriteAccess() { result = write }
/**
* Holds if this SSA definition assigns `value` to the underlying variable.
*
* This is either a direct assignment, `x = value`, or an assignment via
* simple pattern matching
*
* ```rb
* case value
* in Foo => x then ...
* in y => then ...
* end
* ```
*/
predicate assigns(CfgNode value) {
exists(AssignmentExpr ae, BasicBlock bb, int i |
this.definesAt(_, bb, i) and
ae.getLhs() = bb.getNode(i).getAstNode() and
value.getAstNode() = ae.getRhs()
)
}
final override string toString() { result = write.toString() }
final override Location getLocation() { result = write.getLocation() }
}
/**
* A phi definition. For example, in
*
* ```rust
* if b {
* x = 0
* } else {
* x = 1
* }
* println!("{}", x);
* ```
*
* a phi definition for `x` is inserted just before the call to `println!`.
*/
class PhiDefinition extends Definition, SsaImpl::PhiDefinition {
/**
* Gets an input of this phi definition.
*
* Example:
*
* ```rust
* fn phi(b : bool) {
* let mut x = 1; // defines x_0
* println!("{}", x);
* println!("{}", x + 1);
*
* if b {
* x = 2; // defines x_1
* println!("{}", x);
* println!("{}", x + 1);
* } else {
* x = 3; // defines x_2
* println!("{}", x);
* println!("{}", x + 1);
* }
* // defines x_3 = phi(x_1, x_2); inputs are x_1 and x_2
* println!("{}", x);
* }
* ```
*/
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
/** Holds if `inp` is an input to this phi definition along the edge originating in `bb`. */
predicate hasInputFromBlock(Definition inp, BasicBlock bb) {
inp = SsaImpl::phiHasInputFromBlock(this, bb)
}
private string getSplitString() {
result = this.getBasicBlock().getFirstNode().(CfgImpl::AstCfgNode).getSplitsString()
}
override string toString() {
exists(string prefix |
prefix = "[" + this.getSplitString() + "] "
or
not exists(this.getSplitString()) and
prefix = ""
|
result = prefix + "phi"
)
}
/*
* The location of a phi definition is the same as the location of the first node
* in the basic block in which it is defined.
*
* Strictly speaking, the node is *before* the first node, but such a location
* does not exist in the source program.
*/
final override Location getLocation() {
result = this.getBasicBlock().getFirstNode().getLocation()
}
}
/**
* An SSA definition inserted at the beginning of a scope to represent a
* captured local variable. For example, in
*
* ```rust
* fn capture_immut() {
* let x = 100;
* let mut cap = || {
* println!("{}", x);
* };
* cap();
* }
* ```
*
* an entry definition for `x` is inserted at the start of the CFG for `cap`.
*/
class CapturedEntryDefinition extends Definition, SsaImpl::WriteDefinition {
CapturedEntryDefinition() {
exists(BasicBlock bb, int i, Variable v |
this.definesAt(v, bb, i) and
SsaImpl::capturedEntryWrite(bb, i, v)
)
}
final override string toString() { result = "<captured entry> " + this.getSourceVariable() }
override Location getLocation() { result = this.getBasicBlock().getLocation() }
}
}

View File

@@ -0,0 +1,332 @@
private import rust
private import codeql.rust.controlflow.BasicBlocks as BasicBlocks
private import BasicBlocks
private import codeql.rust.controlflow.ControlFlowGraph as Cfg
private import Cfg
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as ControlFlowGraphImpl
private import codeql.ssa.Ssa as SsaImplCommon
/** Holds if `v` is introduced like `let v : i64;`. */
private predicate isUnitializedLet(IdentPat pat, Variable v) {
pat = v.getPat() and
exists(LetStmt let |
let = v.getLetStmt() and
not let.hasInitializer()
)
}
/** Holds if `write` writes to variable `v`. */
predicate variableWrite(AstNode write, Variable v) {
exists(IdentPat pat |
pat = write and
pat = v.getPat() and
not isUnitializedLet(pat, v)
)
or
exists(VariableAccess access |
access = write and
access.getVariable() = v
|
access instanceof VariableWriteAccess
or
// Although compound assignments, like `x += y`, may in fact not update `x`,
// it makes sense to treat them as such
access = any(CompoundAssignmentExpr cae).getLhs()
)
}
module SsaInput implements SsaImplCommon::InputSig<Location> {
class BasicBlock = BasicBlocks::BasicBlock;
class ControlFlowNode = CfgNode;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock = BasicBlocks::ExitBasicBlock;
/**
* A variable amenable to SSA construction.
*
* All immutable variables are amenable. Mutable variables are restricted
* to those that are not captured by closures, and are not borrowed
* (either explicitly using `& mut`, or (potentially) implicit as borrowed
* receivers in a method call).
*/
class SourceVariable extends Variable {
SourceVariable() {
this.isImmutable()
or
this.isMutable() and
not this.isCaptured() and
forall(VariableAccess va | va = this.getAnAccess() |
va instanceof VariableReadAccess and
// receivers can be borrowed implicitly, cf.
// https://doc.rust-lang.org/reference/expressions/method-call-expr.html
not va = any(MethodCallExpr mce).getReceiver()
or
variableWrite(va, this)
)
}
}
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
(
variableWriteActual(bb, i, v, _)
or
capturedEntryWrite(bb, i, v)
) and
certain = true
}
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(VariableAccess va |
bb.getNode(i).getAstNode() = va and
va = v.getAnAccess()
|
va instanceof VariableReadAccess
or
// Although compound assignments, like `x += y`, may in fact not read `x`,
// it makes sense to treat them as such
va = any(CompoundAssignmentExpr cae).getLhs()
) and
certain = true
or
// For immutable variables, we model a read when they are borrowed (although the
// actual read happens later, if at all). This only affects the SSA liveness
// analysis.
exists(VariableAccess va |
va = any(RefExpr re).getExpr() and
va = bb.getNode(i).getAstNode() and
v = va.getVariable() and
certain = false
)
}
}
import SsaImplCommon::Make<Location, SsaInput> as Impl
class Definition = Impl::Definition;
class WriteDefinition = Impl::WriteDefinition;
class UncertainWriteDefinition = Impl::UncertainWriteDefinition;
class PhiDefinition = Impl::PhiNode;
module Consistency = Impl::Consistency;
module ExposedForTestingOnly {
predicate ssaDefReachesReadExt = Impl::ssaDefReachesReadExt/4;
predicate phiHasInputFromBlockExt = Impl::phiHasInputFromBlockExt/3;
}
pragma[noinline]
private predicate adjacentDefRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SsaInput::SourceVariable v
) {
Impl::adjacentDefRead(def, bb1, i1, bb2, i2) and
v = def.getSourceVariable()
}
pragma[noinline]
private predicate adjacentDefReadExt(
DefinitionExt def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SsaInput::SourceVariable v
) {
Impl::adjacentDefReadExt(def, _, bb1, i1, bb2, i2) and
v = def.getSourceVariable()
}
/** Holds if `v` is read at index `i` in basic block `bb`. */
private predicate variableReadActual(BasicBlock bb, int i, Variable v) {
exists(VariableReadAccess read |
read.getVariable() = v and
read = bb.getNode(i).getAstNode()
)
}
private predicate adjacentDefReachesRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
exists(SsaInput::SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
def.definesAt(v, bb1, i1)
or
SsaInput::variableRead(bb1, i1, v, true)
)
or
exists(BasicBlock bb3, int i3 |
adjacentDefReachesRead(def, bb1, i1, bb3, i3) and
SsaInput::variableRead(bb3, i3, _, false) and
Impl::adjacentDefRead(def, bb3, i3, bb2, i2)
)
}
private predicate adjacentDefReachesReadExt(
DefinitionExt def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
exists(SsaInput::SourceVariable v | adjacentDefReadExt(def, bb1, i1, bb2, i2, v) |
def.definesAt(v, bb1, i1, _)
or
SsaInput::variableRead(bb1, i1, v, true)
)
or
exists(BasicBlock bb3, int i3 |
adjacentDefReachesReadExt(def, bb1, i1, bb3, i3) and
SsaInput::variableRead(bb3, i3, _, false) and
Impl::adjacentDefReadExt(def, _, bb3, i3, bb2, i2)
)
}
/** Same as `adjacentDefRead`, but skips uncertain reads. */
pragma[nomagic]
private predicate adjacentDefSkipUncertainReads(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
SsaInput::variableRead(bb2, i2, _, true)
}
private predicate adjacentDefReachesUncertainReadExt(
DefinitionExt def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
adjacentDefReachesReadExt(def, bb1, i1, bb2, i2) and
SsaInput::variableRead(bb2, i2, _, false)
}
/** Same as `lastRefRedef`, but skips uncertain reads. */
pragma[nomagic]
private predicate lastRefSkipUncertainReadsExt(DefinitionExt def, BasicBlock bb, int i) {
Impl::lastRef(def, bb, i) and
not SsaInput::variableRead(bb, i, def.getSourceVariable(), false)
or
exists(BasicBlock bb0, int i0 |
Impl::lastRef(def, bb0, i0) and
adjacentDefReachesUncertainReadExt(def, bb, i, bb0, i0)
)
}
/** Holds if `bb` contains a captured access to variable `v`. */
pragma[nomagic]
private predicate hasCapturedVariableAccess(BasicBlock bb, Variable v) {
exists(VariableAccess read |
read = bb.getANode().getAstNode() and
read.isCapture() and
read.getVariable() = v
)
}
cached
private module Cached {
/**
* Holds if an entry definition is needed for captured variable `v` at index
* `i` in entry block `bb`.
*/
cached
predicate capturedEntryWrite(EntryBasicBlock bb, int i, Variable v) {
hasCapturedVariableAccess(bb.getASuccessor*(), v) and
i = -1
}
/**
* Holds if `v` is written at index `i` in basic block `bb`, and the corresponding
* AST write access is `write`.
*/
cached
predicate variableWriteActual(BasicBlock bb, int i, Variable v, CfgNode write) {
bb.getNode(i) = write and
variableWrite(write.getAstNode(), v)
}
cached
CfgNode getARead(Definition def) {
exists(Variable v, BasicBlock bb, int i |
Impl::ssaDefReachesRead(v, def, bb, i) and
variableReadActual(bb, i, v) and
result = bb.getNode(i)
)
}
cached
Definition phiHasInputFromBlock(PhiDefinition phi, BasicBlock bb) {
Impl::phiHasInputFromBlock(phi, result, bb)
}
/**
* Holds if the value defined at SSA definition `def` can reach a read at `read`,
* without passing through any other non-pseudo read.
*/
cached
predicate firstRead(Definition def, CfgNode read) {
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
def.definesAt(_, bb1, i1) and
adjacentDefSkipUncertainReads(def, bb1, i1, bb2, i2) and
read = bb2.getNode(i2)
)
}
/**
* Holds if the read at `read2` is a read of the same SSA definition `def`
* as the read at `read1`, and `read2` can be reached from `read1` without
* passing through another non-pseudo read.
*/
cached
predicate adjacentReadPair(Definition def, CfgNode read1, CfgNode read2) {
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
read1 = bb1.getNode(i1) and
variableReadActual(bb1, i1, _) and
adjacentDefSkipUncertainReads(def, bb1, i1, bb2, i2) and
read2 = bb2.getNode(i2)
)
}
/**
* Holds if the read of `def` at `read` may be a last read. That is, `read`
* can either reach another definition of the underlying source variable or
* the end of the CFG scope, without passing through another non-pseudo read.
*/
cached
predicate lastRead(Definition def, CfgNode read) {
exists(BasicBlock bb, int i |
lastRefSkipUncertainReadsExt(def, bb, i) and
variableReadActual(bb, i, _) and
read = bb.getNode(i)
)
}
cached
Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) {
Impl::uncertainWriteDefinitionInput(def, result)
}
}
import Cached
private import codeql.rust.dataflow.Ssa
/**
* An extended static single assignment (SSA) definition.
*
* This is either a normal SSA definition (`Definition`) or a
* phi-read node (`PhiReadNode`).
*
* Only intended for internal use.
*/
class DefinitionExt extends Impl::DefinitionExt {
CfgNode getARead() { result = getARead(this) }
override string toString() { result = this.(Ssa::Definition).toString() }
override Location getLocation() { result = this.(Ssa::Definition).getLocation() }
}
/**
* A phi-read node.
*
* Only intended for internal use.
*/
class PhiReadNode extends DefinitionExt, Impl::PhiReadNode {
override string toString() { result = "SSA phi read(" + this.getSourceVariable() + ")" }
override Location getLocation() { result = Impl::PhiReadNode.super.getLocation() }
}

View File

@@ -74,8 +74,10 @@ import codeql.rust.elements.LoopExpr
import codeql.rust.elements.MacroCall
import codeql.rust.elements.MacroDef
import codeql.rust.elements.MacroExpr
import codeql.rust.elements.MacroItems
import codeql.rust.elements.MacroPat
import codeql.rust.elements.MacroRules
import codeql.rust.elements.MacroStmts
import codeql.rust.elements.MacroType
import codeql.rust.elements.MatchArm
import codeql.rust.elements.MatchArmList

View File

@@ -5,6 +5,7 @@
private import internal.MacroCallImpl
import codeql.rust.elements.AssocItem
import codeql.rust.elements.AstNode
import codeql.rust.elements.Attr
import codeql.rust.elements.ExternItem
import codeql.rust.elements.Item

View File

@@ -0,0 +1,18 @@
// generated by codegen, do not edit
/**
* This module provides the public class `MacroItems`.
*/
private import internal.MacroItemsImpl
import codeql.rust.elements.AstNode
import codeql.rust.elements.Item
/**
* A sequence of items generated by a `MacroCall`. For example:
* ```rust
* mod foo{
* include!("common_definitions.rs");
* }
* ```
*/
final class MacroItems = Impl::MacroItems;

View File

@@ -0,0 +1,19 @@
// generated by codegen, do not edit
/**
* This module provides the public class `MacroStmts`.
*/
private import internal.MacroStmtsImpl
import codeql.rust.elements.AstNode
import codeql.rust.elements.Expr
import codeql.rust.elements.Stmt
/**
* A sequence of statements generated by a `MacroCall`. For example:
* ```rust
* fn main() {
* println!("Hello, world!"); // This macro expands into a list of statements
* }
* ```
*/
final class MacroStmts = Impl::MacroStmts;

View File

@@ -0,0 +1,14 @@
// generated by codegen, remove this comment if you wish to edit this file
/**
* This module defines the hook used internally to tweak the characteristic predicate of
* `MacroItems` synthesized instances.
* INTERNAL: Do not use.
*/
private import codeql.rust.elements.internal.generated.Raw
/**
* The characteristic predicate of `MacroItems` synthesized instances.
* INTERNAL: Do not use.
*/
predicate constructMacroItems(Raw::MacroItems id) { any() }

View File

@@ -0,0 +1,24 @@
// generated by codegen, remove this comment if you wish to edit this file
/**
* This module provides a hand-modifiable wrapper around the generated class `MacroItems`.
*
* INTERNAL: Do not use.
*/
private import codeql.rust.elements.internal.generated.MacroItems
/**
* INTERNAL: This module contains the customizable definition of `MacroItems` and should not
* be referenced directly.
*/
module Impl {
/**
* A sequence of items generated by a `MacroCall`. For example:
* ```rust
* mod foo{
* include!("common_definitions.rs");
* }
* ```
*/
class MacroItems extends Generated::MacroItems { }
}

View File

@@ -0,0 +1,14 @@
// generated by codegen, remove this comment if you wish to edit this file
/**
* This module defines the hook used internally to tweak the characteristic predicate of
* `MacroStmts` synthesized instances.
* INTERNAL: Do not use.
*/
private import codeql.rust.elements.internal.generated.Raw
/**
* The characteristic predicate of `MacroStmts` synthesized instances.
* INTERNAL: Do not use.
*/
predicate constructMacroStmts(Raw::MacroStmts id) { any() }

View File

@@ -0,0 +1,24 @@
// generated by codegen, remove this comment if you wish to edit this file
/**
* This module provides a hand-modifiable wrapper around the generated class `MacroStmts`.
*
* INTERNAL: Do not use.
*/
private import codeql.rust.elements.internal.generated.MacroStmts
/**
* INTERNAL: This module contains the customizable definition of `MacroStmts` and should not
* be referenced directly.
*/
module Impl {
/**
* A sequence of statements generated by a `MacroCall`. For example:
* ```rust
* fn main() {
* println!("Hello, world!"); // This macro expands into a list of statements
* }
* ```
*/
class MacroStmts extends Generated::MacroStmts { }
}

View File

@@ -42,5 +42,11 @@ module Impl {
* Gets the number of arms of this match expression.
*/
int getNumberOfArms() { result = this.getMatchArmList().getNumberOfArms() }
/**
* Gets the last arm of this match expression. Due to exhaustiveness checking,
* this arm is guaranteed to succeed.
*/
MatchArm getLastArm() { result = this.getArm(this.getNumberOfArms() - 1) }
}
}

View File

@@ -1,4 +1,3 @@
// generated by codegen, remove this comment if you wish to edit this file
/**
* This module provides a hand-modifiable wrapper around the generated class `OrPat`.
*
@@ -12,6 +11,7 @@ private import codeql.rust.elements.internal.generated.OrPat
* be referenced directly.
*/
module Impl {
// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
* An or pattern. For example:
* ```rust
@@ -20,5 +20,9 @@ module Impl {
* }
* ```
*/
class OrPat extends Generated::OrPat { }
class OrPat extends Generated::OrPat {
/** Gets the last pattern in this or pattern. */
pragma[nomagic]
Pat getLastPat() { result = this.getPat(this.getNumberOfPats() - 1) }
}
}

View File

@@ -118,16 +118,23 @@ module Impl {
*/
IdentPat getPat() { variableDecl(definingNode, result, name) }
/** Gets the `let` statement that introduces this variable, if any. */
LetStmt getLetStmt() { this.getPat() = result.getPat() }
/** Gets the initial value of this variable, if any. */
Expr getInitializer() {
exists(LetStmt let |
this.getPat() = let.getPat() and
result = let.getInitializer()
)
}
Expr getInitializer() { result = this.getLetStmt().getInitializer() }
/** Holds if this variable is captured. */
predicate isCaptured() { this.getAnAccess().isCapture() }
/** Gets the parameter that introduces this variable, if any. */
Param getParameter() { parameterDeclInScope(result, this, _) }
/** Hold is this variable is mutable. */
predicate isMutable() { this.getPat().isMut() }
/** Hold is this variable is immutable. */
predicate isImmutable() { not this.isMutable() }
}
/** A path expression that may access a local variable. */
@@ -180,6 +187,27 @@ module Impl {
)
}
/**
* Holds if parameter `p` introduces the variable `v` inside variable scope
* `scope`.
*/
private predicate parameterDeclInScope(Param p, Variable v, VariableScope scope) {
exists(Pat pat |
pat = getAVariablePatAncestor(v) and
p.getPat() = pat
|
exists(Function f |
f.getParamList().getAParam() = p and
scope = f.getBody()
)
or
exists(ClosureExpr ce |
ce.getParamList().getAParam() = p and
scope = ce.getBody()
)
)
}
/**
* Holds if `v` is named `name` and is declared inside variable scope
* `scope`, and `v` is bound starting from `(line, column)`.
@@ -188,51 +216,44 @@ module Impl {
Variable v, VariableScope scope, string name, int line, int column
) {
name = v.getName() and
exists(Pat pat | pat = getAVariablePatAncestor(v) |
scope =
any(MatchArmScope arm |
arm.getPat() = pat and
arm.getLocation().hasLocationInfo(_, line, column, _, _)
(
parameterDeclInScope(_, v, scope) and
scope.getLocation().hasLocationInfo(_, line, column, _, _)
or
exists(Pat pat | pat = getAVariablePatAncestor(v) |
scope =
any(MatchArmScope arm |
arm.getPat() = pat and
arm.getLocation().hasLocationInfo(_, line, column, _, _)
)
or
exists(LetStmt let |
let.getPat() = pat and
scope = getEnclosingScope(let) and
// for `let` statements, variables are bound _after_ the statement, i.e.
// not in the RHS
let.getLocation().hasLocationInfo(_, _, _, line, column)
)
or
exists(IfExpr ie, LetExpr let |
let.getPat() = pat and
ie.getCondition() = let and
scope = ie.getThen() and
scope.getLocation().hasLocationInfo(_, line, column, _, _)
)
or
exists(ForExpr fe |
fe.getPat() = pat and
scope = fe.getLoopBody() and
scope.getLocation().hasLocationInfo(_, line, column, _, _)
)
or
exists(WhileExpr we, LetExpr let |
let.getPat() = pat and
we.getCondition() = let and
scope = we.getLoopBody() and
scope.getLocation().hasLocationInfo(_, line, column, _, _)
)
or
exists(Function f |
f.getParamList().getAParam().getPat() = pat and
scope = f.getBody() and
scope.getLocation().hasLocationInfo(_, line, column, _, _)
)
or
exists(LetStmt let |
let.getPat() = pat and
scope = getEnclosingScope(let) and
// for `let` statements, variables are bound _after_ the statement, i.e.
// not in the RHS
let.getLocation().hasLocationInfo(_, _, _, line, column)
)
or
exists(IfExpr ie, LetExpr let |
let.getPat() = pat and
ie.getCondition() = let and
scope = ie.getThen() and
scope.getLocation().hasLocationInfo(_, line, column, _, _)
)
or
exists(ForExpr fe |
fe.getPat() = pat and
scope = fe.getLoopBody() and
scope.getLocation().hasLocationInfo(_, line, column, _, _)
)
or
exists(ClosureExpr ce |
ce.getParamList().getAParam().getPat() = pat and
scope = ce.getBody() and
scope.getLocation().hasLocationInfo(_, line, column, _, _)
)
or
exists(WhileExpr we, LetExpr let |
let.getPat() = pat and
we.getCondition() = let and
scope = we.getLoopBody() and
scope.getLocation().hasLocationInfo(_, line, column, _, _)
)
)
}
@@ -427,7 +448,8 @@ module Impl {
exists(Expr mid |
assignmentExprDescendant(mid) and
getImmediateParent(e) = mid and
not mid.(PrefixExpr).getOperatorName() = "*"
not mid.(PrefixExpr).getOperatorName() = "*" and
not mid instanceof FieldExpr
)
}

View File

@@ -7,6 +7,7 @@
private import codeql.rust.elements.internal.generated.Synth
private import codeql.rust.elements.internal.generated.Raw
import codeql.rust.elements.internal.AssocItemImpl::Impl as AssocItemImpl
import codeql.rust.elements.AstNode
import codeql.rust.elements.Attr
import codeql.rust.elements.internal.ExternItemImpl::Impl as ExternItemImpl
import codeql.rust.elements.internal.ItemImpl::Impl as ItemImpl
@@ -76,5 +77,20 @@ module Generated {
* Holds if `getTokenTree()` exists.
*/
final predicate hasTokenTree() { exists(this.getTokenTree()) }
/**
* Gets the expanded of this macro call, if it exists.
*/
AstNode getExpanded() {
result =
Synth::convertAstNodeFromRaw(Synth::convertMacroCallToRaw(this)
.(Raw::MacroCall)
.getExpanded())
}
/**
* Holds if `getExpanded()` exists.
*/
final predicate hasExpanded() { exists(this.getExpanded()) }
}
}

View File

@@ -0,0 +1,50 @@
// generated by codegen, do not edit
/**
* This module provides the generated definition of `MacroItems`.
* INTERNAL: Do not import directly.
*/
private import codeql.rust.elements.internal.generated.Synth
private import codeql.rust.elements.internal.generated.Raw
import codeql.rust.elements.internal.AstNodeImpl::Impl as AstNodeImpl
import codeql.rust.elements.Item
/**
* INTERNAL: This module contains the fully generated definition of `MacroItems` and should not
* be referenced directly.
*/
module Generated {
/**
* A sequence of items generated by a `MacroCall`. For example:
* ```rust
* mod foo{
* include!("common_definitions.rs");
* }
* ```
* INTERNAL: Do not reference the `Generated::MacroItems` class directly.
* Use the subclass `MacroItems`, where the following predicates are available.
*/
class MacroItems extends Synth::TMacroItems, AstNodeImpl::AstNode {
override string getAPrimaryQlClass() { result = "MacroItems" }
/**
* Gets the `index`th item of this macro items (0-based).
*/
Item getItem(int index) {
result =
Synth::convertItemFromRaw(Synth::convertMacroItemsToRaw(this)
.(Raw::MacroItems)
.getItem(index))
}
/**
* Gets any of the items of this macro items.
*/
final Item getAnItem() { result = this.getItem(_) }
/**
* Gets the number of items of this macro items.
*/
final int getNumberOfItems() { result = count(int i | exists(this.getItem(i))) }
}
}

View File

@@ -0,0 +1,64 @@
// generated by codegen, do not edit
/**
* This module provides the generated definition of `MacroStmts`.
* INTERNAL: Do not import directly.
*/
private import codeql.rust.elements.internal.generated.Synth
private import codeql.rust.elements.internal.generated.Raw
import codeql.rust.elements.internal.AstNodeImpl::Impl as AstNodeImpl
import codeql.rust.elements.Expr
import codeql.rust.elements.Stmt
/**
* INTERNAL: This module contains the fully generated definition of `MacroStmts` and should not
* be referenced directly.
*/
module Generated {
/**
* A sequence of statements generated by a `MacroCall`. For example:
* ```rust
* fn main() {
* println!("Hello, world!"); // This macro expands into a list of statements
* }
* ```
* INTERNAL: Do not reference the `Generated::MacroStmts` class directly.
* Use the subclass `MacroStmts`, where the following predicates are available.
*/
class MacroStmts extends Synth::TMacroStmts, AstNodeImpl::AstNode {
override string getAPrimaryQlClass() { result = "MacroStmts" }
/**
* Gets the expression of this macro statements, if it exists.
*/
Expr getExpr() {
result =
Synth::convertExprFromRaw(Synth::convertMacroStmtsToRaw(this).(Raw::MacroStmts).getExpr())
}
/**
* Holds if `getExpr()` exists.
*/
final predicate hasExpr() { exists(this.getExpr()) }
/**
* Gets the `index`th statement of this macro statements (0-based).
*/
Stmt getStatement(int index) {
result =
Synth::convertStmtFromRaw(Synth::convertMacroStmtsToRaw(this)
.(Raw::MacroStmts)
.getStatement(index))
}
/**
* Gets any of the statements of this macro statements.
*/
final Stmt getAStatement() { result = this.getStatement(_) }
/**
* Gets the number of statements of this macro statements.
*/
final int getNumberOfStatements() { result = count(int i | exists(this.getStatement(i))) }
}
}

View File

@@ -418,6 +418,43 @@ private module Impl {
)
}
private Element getImmediateChildOfMacroItems(MacroItems e, int index, string partialPredicateCall) {
exists(int b, int bAstNode, int n, int nItem |
b = 0 and
bAstNode = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfAstNode(e, i, _)) | i) and
n = bAstNode and
nItem = n + 1 + max(int i | i = -1 or exists(e.getItem(i)) | i) and
(
none()
or
result = getImmediateChildOfAstNode(e, index - b, partialPredicateCall)
or
result = e.getItem(index - n) and
partialPredicateCall = "Item(" + (index - n).toString() + ")"
)
)
}
private Element getImmediateChildOfMacroStmts(MacroStmts e, int index, string partialPredicateCall) {
exists(int b, int bAstNode, int n, int nExpr, int nStatement |
b = 0 and
bAstNode = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfAstNode(e, i, _)) | i) and
n = bAstNode and
nExpr = n + 1 and
nStatement = nExpr + 1 + max(int i | i = -1 or exists(e.getStatement(i)) | i) and
(
none()
or
result = getImmediateChildOfAstNode(e, index - b, partialPredicateCall)
or
index = n and result = e.getExpr() and partialPredicateCall = "Expr()"
or
result = e.getStatement(index - nExpr) and
partialPredicateCall = "Statement(" + (index - nExpr).toString() + ")"
)
)
}
private Element getImmediateChildOfMatchArm(MatchArm e, int index, string partialPredicateCall) {
exists(int b, int bAstNode, int n, int nAttr, int nExpr, int nGuard, int nPat |
b = 0 and
@@ -2999,7 +3036,8 @@ private module Impl {
private Element getImmediateChildOfMacroCall(MacroCall e, int index, string partialPredicateCall) {
exists(
int b, int bAssocItem, int bExternItem, int bItem, int n, int nAttr, int nPath, int nTokenTree
int b, int bAssocItem, int bExternItem, int bItem, int n, int nAttr, int nPath,
int nTokenTree, int nExpanded
|
b = 0 and
bAssocItem = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfAssocItem(e, i, _)) | i) and
@@ -3010,6 +3048,7 @@ private module Impl {
nAttr = n + 1 + max(int i | i = -1 or exists(e.getAttr(i)) | i) and
nPath = nAttr + 1 and
nTokenTree = nPath + 1 and
nExpanded = nTokenTree + 1 and
(
none()
or
@@ -3025,6 +3064,8 @@ private module Impl {
index = nAttr and result = e.getPath() and partialPredicateCall = "Path()"
or
index = nPath and result = e.getTokenTree() and partialPredicateCall = "TokenTree()"
or
index = nTokenTree and result = e.getExpanded() and partialPredicateCall = "Expanded()"
)
)
}
@@ -3448,6 +3489,10 @@ private module Impl {
or
result = getImmediateChildOfLifetime(e, index, partialAccessor)
or
result = getImmediateChildOfMacroItems(e, index, partialAccessor)
or
result = getImmediateChildOfMacroStmts(e, index, partialAccessor)
or
result = getImmediateChildOfMatchArm(e, index, partialAccessor)
or
result = getImmediateChildOfMatchArmList(e, index, partialAccessor)

View File

@@ -345,6 +345,47 @@ module Raw {
string getText() { lifetime_texts(this, result) }
}
/**
* INTERNAL: Do not use.
* A sequence of items generated by a `MacroCall`. For example:
* ```rust
* mod foo{
* include!("common_definitions.rs");
* }
* ```
*/
class MacroItems extends @macro_items, AstNode {
override string toString() { result = "MacroItems" }
/**
* Gets the `index`th item of this macro items (0-based).
*/
Item getItem(int index) { macro_items_items(this, index, result) }
}
/**
* INTERNAL: Do not use.
* A sequence of statements generated by a `MacroCall`. For example:
* ```rust
* fn main() {
* println!("Hello, world!"); // This macro expands into a list of statements
* }
* ```
*/
class MacroStmts extends @macro_stmts, AstNode {
override string toString() { result = "MacroStmts" }
/**
* Gets the expression of this macro statements, if it exists.
*/
Expr getExpr() { macro_stmts_exprs(this, result) }
/**
* Gets the `index`th statement of this macro statements (0-based).
*/
Stmt getStatement(int index) { macro_stmts_statements(this, index, result) }
}
/**
* INTERNAL: Do not use.
* A match arm. For example:
@@ -3430,6 +3471,11 @@ module Raw {
* Gets the token tree of this macro call, if it exists.
*/
TokenTree getTokenTree() { macro_call_token_trees(this, result) }
/**
* Gets the expanded of this macro call, if it exists.
*/
AstNode getExpanded() { macro_call_expandeds(this, result) }
}
/**

View File

@@ -250,6 +250,10 @@ module Synth {
* INTERNAL: Do not use.
*/
TMacroExpr(Raw::MacroExpr id) { constructMacroExpr(id) } or
/**
* INTERNAL: Do not use.
*/
TMacroItems(Raw::MacroItems id) { constructMacroItems(id) } or
/**
* INTERNAL: Do not use.
*/
@@ -258,6 +262,10 @@ module Synth {
* INTERNAL: Do not use.
*/
TMacroRules(Raw::MacroRules id) { constructMacroRules(id) } or
/**
* INTERNAL: Do not use.
*/
TMacroStmts(Raw::MacroStmts id) { constructMacroStmts(id) } or
/**
* INTERNAL: Do not use.
*/
@@ -595,13 +603,13 @@ module Synth {
TAbi or TArgList or TAssocItem or TAssocItemList or TAttr or TCallable or TClosureBinder or
TExpr or TExternItem or TExternItemList or TFieldList or TFormatArgsArg or TGenericArg or
TGenericArgList or TGenericParam or TGenericParamList or TItemList or TLabel or TLetElse or
TLifetime or TMatchArm or TMatchArmList or TMatchGuard or TMeta or TName or TNameRef or
TParam or TParamList or TPat or TPath or TPathSegment or TRecordExprField or
TRecordExprFieldList or TRecordField or TRecordPatField or TRecordPatFieldList or TRename or
TRetType or TReturnTypeSyntax or TSelfParam or TSourceFile or TStmt or TStmtList or
TToken or TTokenTree or TTupleField or TTypeBound or TTypeBoundList or TTypeRef or
TUseTree or TUseTreeList or TVariant or TVariantList or TVisibility or TWhereClause or
TWherePred;
TLifetime or TMacroItems or TMacroStmts or TMatchArm or TMatchArmList or TMatchGuard or
TMeta or TName or TNameRef or TParam or TParamList or TPat or TPath or TPathSegment or
TRecordExprField or TRecordExprFieldList or TRecordField or TRecordPatField or
TRecordPatFieldList or TRename or TRetType or TReturnTypeSyntax or TSelfParam or
TSourceFile or TStmt or TStmtList or TToken or TTokenTree or TTupleField or TTypeBound or
TTypeBoundList or TTypeRef or TUseTree or TUseTreeList or TVariant or TVariantList or
TVisibility or TWhereClause or TWherePred;
/**
* INTERNAL: Do not use.
@@ -1042,6 +1050,12 @@ module Synth {
*/
TMacroExpr convertMacroExprFromRaw(Raw::Element e) { result = TMacroExpr(e) }
/**
* INTERNAL: Do not use.
* Converts a raw element to a synthesized `TMacroItems`, if possible.
*/
TMacroItems convertMacroItemsFromRaw(Raw::Element e) { result = TMacroItems(e) }
/**
* INTERNAL: Do not use.
* Converts a raw element to a synthesized `TMacroPat`, if possible.
@@ -1054,6 +1068,12 @@ module Synth {
*/
TMacroRules convertMacroRulesFromRaw(Raw::Element e) { result = TMacroRules(e) }
/**
* INTERNAL: Do not use.
* Converts a raw element to a synthesized `TMacroStmts`, if possible.
*/
TMacroStmts convertMacroStmtsFromRaw(Raw::Element e) { result = TMacroStmts(e) }
/**
* INTERNAL: Do not use.
* Converts a raw element to a synthesized `TMacroType`, if possible.
@@ -1603,6 +1623,10 @@ module Synth {
or
result = convertLifetimeFromRaw(e)
or
result = convertMacroItemsFromRaw(e)
or
result = convertMacroStmtsFromRaw(e)
or
result = convertMatchArmFromRaw(e)
or
result = convertMatchArmListFromRaw(e)
@@ -2332,6 +2356,12 @@ module Synth {
*/
Raw::Element convertMacroExprToRaw(TMacroExpr e) { e = TMacroExpr(result) }
/**
* INTERNAL: Do not use.
* Converts a synthesized `TMacroItems` to a raw DB element, if possible.
*/
Raw::Element convertMacroItemsToRaw(TMacroItems e) { e = TMacroItems(result) }
/**
* INTERNAL: Do not use.
* Converts a synthesized `TMacroPat` to a raw DB element, if possible.
@@ -2344,6 +2374,12 @@ module Synth {
*/
Raw::Element convertMacroRulesToRaw(TMacroRules e) { e = TMacroRules(result) }
/**
* INTERNAL: Do not use.
* Converts a synthesized `TMacroStmts` to a raw DB element, if possible.
*/
Raw::Element convertMacroStmtsToRaw(TMacroStmts e) { e = TMacroStmts(result) }
/**
* INTERNAL: Do not use.
* Converts a synthesized `TMacroType` to a raw DB element, if possible.
@@ -2893,6 +2929,10 @@ module Synth {
or
result = convertLifetimeToRaw(e)
or
result = convertMacroItemsToRaw(e)
or
result = convertMacroStmtsToRaw(e)
or
result = convertMatchArmToRaw(e)
or
result = convertMatchArmListToRaw(e)

View File

@@ -62,8 +62,10 @@ import codeql.rust.elements.internal.LoopExprConstructor
import codeql.rust.elements.internal.MacroCallConstructor
import codeql.rust.elements.internal.MacroDefConstructor
import codeql.rust.elements.internal.MacroExprConstructor
import codeql.rust.elements.internal.MacroItemsConstructor
import codeql.rust.elements.internal.MacroPatConstructor
import codeql.rust.elements.internal.MacroRulesConstructor
import codeql.rust.elements.internal.MacroStmtsConstructor
import codeql.rust.elements.internal.MacroTypeConstructor
import codeql.rust.elements.internal.MatchArmConstructor
import codeql.rust.elements.internal.MatchArmListConstructor

View File

@@ -154,6 +154,8 @@ locatable_locations(
| @label
| @let_else
| @lifetime
| @macro_items
| @macro_stmts
| @match_arm
| @match_arm_list
| @match_guard
@@ -451,6 +453,34 @@ lifetime_texts(
string text: string ref
);
macro_items(
unique int id: @macro_items
);
#keyset[id, index]
macro_items_items(
int id: @macro_items ref,
int index: int ref,
int item: @item ref
);
macro_stmts(
unique int id: @macro_stmts
);
#keyset[id]
macro_stmts_exprs(
int id: @macro_stmts ref,
int expr: @expr ref
);
#keyset[id, index]
macro_stmts_statements(
int id: @macro_stmts ref,
int index: int ref,
int statement: @stmt ref
);
match_arms(
unique int id: @match_arm
);
@@ -2885,6 +2915,12 @@ macro_call_token_trees(
int token_tree: @token_tree ref
);
#keyset[id]
macro_call_expandeds(
int id: @macro_call ref,
int expanded: @ast_node ref
);
macro_defs(
unique int id: @macro_def
);

View File

@@ -57,8 +57,10 @@ LoopExpr/gen_loop_expr.rs 35deaf35e765db4ae3124a11284266d8f341d1ce7b700030efada0
MacroCall/gen_macro_call.rs 139ef2c69323eea1a901e260d4e2acdd00b26f013b90c9344f48c6503ce29d79 139ef2c69323eea1a901e260d4e2acdd00b26f013b90c9344f48c6503ce29d79
MacroDef/gen_macro_def.rs 17c5387fb464a60b4a4520d22b055ba35ff23e9fe431a18a33808ae02c4bbff5 17c5387fb464a60b4a4520d22b055ba35ff23e9fe431a18a33808ae02c4bbff5
MacroExpr/gen_macro_expr.rs 3c23dc88fcc4bc8f97d9364d2f367671a0a5a63d07e52237d28204b64756dcdb 3c23dc88fcc4bc8f97d9364d2f367671a0a5a63d07e52237d28204b64756dcdb
MacroItems/gen_macro_items.rs 8ef3e16b73635dc97afa3ffa4db2bb21a8f1b435176861a594b0200cc5b9b931 8ef3e16b73635dc97afa3ffa4db2bb21a8f1b435176861a594b0200cc5b9b931
MacroPat/gen_macro_pat.rs b8041370598bd7fb26778d829a15c415c2078d69124f6af634ddeba13a114aa0 b8041370598bd7fb26778d829a15c415c2078d69124f6af634ddeba13a114aa0
MacroRules/gen_macro_rules.rs 7e03b410f4669e422d3b4328f7aafdca2e286e5d951495dd69cee0d44cb793a9 7e03b410f4669e422d3b4328f7aafdca2e286e5d951495dd69cee0d44cb793a9
MacroStmts/gen_macro_stmts.rs 2e45dcf44bf2e8404b49ce9abeee4931572693174b5d96f3fd81eb40ea8e7b4b 2e45dcf44bf2e8404b49ce9abeee4931572693174b5d96f3fd81eb40ea8e7b4b
MacroType/gen_macro_type.rs 84db79c78860512b14f885391fcae999ca7282f2d8a9ab65d30cc413d5bbebd0 84db79c78860512b14f885391fcae999ca7282f2d8a9ab65d30cc413d5bbebd0
MatchArm/gen_match_arm.rs ac75b4836a103e2755bd47a1ee1b74af6eb8349adc4ebedaaa27b3ea3ae41aa5 ac75b4836a103e2755bd47a1ee1b74af6eb8349adc4ebedaaa27b3ea3ae41aa5
MatchArmList/gen_match_arm_list.rs dbf36444d371421a2b8768a188660dd45ed3b823fb1c56b90c1ba77f177d23d6 dbf36444d371421a2b8768a188660dd45ed3b823fb1c56b90c1ba77f177d23d6

View File

@@ -59,8 +59,10 @@
/MacroCall/gen_macro_call.rs linguist-generated
/MacroDef/gen_macro_def.rs linguist-generated
/MacroExpr/gen_macro_expr.rs linguist-generated
/MacroItems/gen_macro_items.rs linguist-generated
/MacroPat/gen_macro_pat.rs linguist-generated
/MacroRules/gen_macro_rules.rs linguist-generated
/MacroStmts/gen_macro_stmts.rs linguist-generated
/MacroType/gen_macro_type.rs linguist-generated
/MatchArm/gen_match_arm.rs linguist-generated
/MatchArmList/gen_match_arm_list.rs linguist-generated

View File

@@ -0,0 +1 @@
| gen_arg_list.rs:5:5:5:11 | ArgList | getNumberOfArgs: | 1 |

View File

@@ -0,0 +1 @@
| gen_arg_list.rs:5:5:5:11 | ArgList | 0 | gen_arg_list.rs:5:5:5:11 | "not yet implemented" |

View File

@@ -1 +1 @@
| gen_macro_call.rs:5:5:5:11 | MacroCall | getNumberOfAttrs: | 0 | hasPath: | yes | hasTokenTree: | yes |
| gen_macro_call.rs:5:5:5:11 | MacroCall | getNumberOfAttrs: | 0 | hasPath: | yes | hasTokenTree: | yes | hasExpanded: | yes |

View File

@@ -2,11 +2,13 @@
import codeql.rust.elements
import TestUtils
from MacroCall x, int getNumberOfAttrs, string hasPath, string hasTokenTree
from MacroCall x, int getNumberOfAttrs, string hasPath, string hasTokenTree, string hasExpanded
where
toBeTested(x) and
not x.isUnknown() and
getNumberOfAttrs = x.getNumberOfAttrs() and
(if x.hasPath() then hasPath = "yes" else hasPath = "no") and
if x.hasTokenTree() then hasTokenTree = "yes" else hasTokenTree = "no"
select x, "getNumberOfAttrs:", getNumberOfAttrs, "hasPath:", hasPath, "hasTokenTree:", hasTokenTree
(if x.hasTokenTree() then hasTokenTree = "yes" else hasTokenTree = "no") and
if x.hasExpanded() then hasExpanded = "yes" else hasExpanded = "no"
select x, "getNumberOfAttrs:", getNumberOfAttrs, "hasPath:", hasPath, "hasTokenTree:", hasTokenTree,
"hasExpanded:", hasExpanded

View File

@@ -0,0 +1 @@
| gen_macro_call.rs:5:5:5:11 | MacroCall | gen_macro_call.rs:5:5:5:11 | MacroStmts |

View File

@@ -0,0 +1,7 @@
// generated by codegen, do not edit
import codeql.rust.elements
import TestUtils
from MacroCall x
where toBeTested(x) and not x.isUnknown()
select x, x.getExpanded()

Some files were not shown because too many files have changed in this diff Show More