Merge branch 'main' into redsun82/cargo-upgrade

This commit is contained in:
Paolo Tranquilli
2025-07-03 10:16:18 +02:00
37 changed files with 639 additions and 333 deletions

View File

@@ -1,35 +0,0 @@
name: "Go: Run Tests - Other OS"
on:
pull_request:
paths:
- "go/**"
- "!go/documentation/**"
- "!go/ql/**" # don't run other-os if only ql/ files changed
- .github/workflows/go-tests-other-os.yml
- .github/actions/**
- codeql-workspace.yml
- MODULE.bazel
- .bazelrc
- misc/bazel/**
permissions:
contents: read
jobs:
test-mac:
name: Test MacOS
runs-on: macos-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Run tests
uses: ./go/actions/test
test-win:
name: Test Windows
runs-on: windows-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Run tests
uses: ./go/actions/test

View File

@@ -1,22 +0,0 @@
name: "Go: Run RTJO Tests"
on:
pull_request:
types:
- labeled
permissions:
contents: read
jobs:
test-linux:
if: "github.repository_owner == 'github' && github.event.label.name == 'Run: RTJO Language Tests'"
name: RTJO Test Linux (Ubuntu)
runs-on: ubuntu-latest-xl
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Run tests
uses: ./go/actions/test
with:
run-code-checks: true
dynamic-join-order-mode: all

View File

@@ -1,20 +1,9 @@
name: "Go: Run Tests"
on:
push:
paths:
- "go/**"
- "!go/documentation/**"
- "shared/**"
- .github/workflows/go-tests.yml
- .github/actions/**
- codeql-workspace.yml
branches:
- main
- "rc/*"
pull_request:
paths:
- "go/**"
- "!go/documentation/**"
- "!go/documentation/**"
- "shared/**"
- .github/workflows/go-tests.yml
- .github/actions/**

View File

@@ -32,4 +32,8 @@ extensions:
- ["", "", False, "CommandLineToArgvA", "", "", "Argument[*0]", "ReturnValue[**]", "taint", "manual"]
- ["", "", False, "CommandLineToArgvW", "", "", "Argument[*0]", "ReturnValue[**]", "taint", "manual"]
# fileapi.h
- ["", "", False, "ReadFileEx", "", "", "Argument[*3].Field[@hEvent]", "Argument[4].Parameter[*2].Field[@hEvent]", "value", "manual"]
- ["", "", False, "ReadFileEx", "", "", "Argument[*3].Field[@hEvent]", "Argument[4].Parameter[*2].Field[@hEvent]", "value", "manual"]
# processthreadsapi.h
- ["", "", False, "CreateThread", "", "", "Argument[@3]", "Argument[2].Parameter[@0]", "value", "manual"]
- ["", "", False, "CreateRemoteThread", "", "", "Argument[@4]", "Argument[3].Parameter[@0]", "value", "manual"]
- ["", "", False, "CreateRemoteThreadEx", "", "", "Argument[@4]", "Argument[3].Parameter[@0]", "value", "manual"]

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added flow models for the Win32 API functions `CreateThread`, `CreateRemoteThread`, and `CreateRemoteThreadEx`.

View File

@@ -17,13 +17,16 @@ models
| 16 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual |
| 17 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual |
| 18 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual |
| 19 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual |
| 20 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated |
| 21 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual |
| 22 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual |
| 23 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual |
| 19 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual |
| 20 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual |
| 21 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual |
| 22 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual |
| 23 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated |
| 24 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual |
| 25 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual |
| 26 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual |
edges
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:23 |
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:26 |
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:17 |
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:17 Sink:MaD:2 |
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction |
@@ -32,10 +35,10 @@ edges
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:23 |
| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:21 |
| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:20 |
| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:22 |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:26 |
| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:24 |
| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:23 |
| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:25 |
| test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | |
| test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | |
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:16 |
@@ -47,15 +50,15 @@ edges
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | |
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 |
| test.cpp:17:24:17:24 | x | test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | provenance | |
| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:21 |
| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:24 |
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | |
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 |
| test.cpp:21:27:21:27 | x | test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | provenance | |
| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:20 |
| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:23 |
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | |
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 |
| test.cpp:25:35:25:35 | x | test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | provenance | |
| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:22 |
| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:25 |
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | |
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 |
| test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | |
@@ -73,8 +76,8 @@ edges
| windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | windows.cpp:41:10:41:13 | * ... | provenance | Src:MaD:5 |
| windows.cpp:90:6:90:15 | [summary param] *3 in ReadFileEx [*hEvent] | windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[*hEvent] in ReadFileEx | provenance | |
| windows.cpp:90:6:90:15 | [summary param] *3 in ReadFileEx [hEvent] | windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[hEvent] in ReadFileEx | provenance | |
| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[*hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[*hEvent] in ReadFileEx | provenance | MaD:19 |
| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[hEvent] in ReadFileEx | provenance | MaD:19 |
| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[*hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[*hEvent] in ReadFileEx | provenance | MaD:22 |
| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[hEvent] in ReadFileEx | provenance | MaD:22 |
| windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2] in ReadFileEx [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | |
| windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2] in ReadFileEx [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | |
| windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[*hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2] in ReadFileEx [*hEvent] | provenance | |
@@ -122,6 +125,29 @@ edges
| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | provenance | Src:MaD:12 |
| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | windows.cpp:333:20:333:52 | *pMapView | provenance | |
| windows.cpp:333:20:333:52 | *pMapView | windows.cpp:335:10:335:16 | * ... | provenance | |
| windows.cpp:349:8:349:19 | [summary param] *3 in CreateThread [x] | windows.cpp:349:8:349:19 | [summary] to write: Argument[2].Parameter[*0] in CreateThread [x] | provenance | MaD:21 |
| windows.cpp:349:8:349:19 | [summary] to write: Argument[2].Parameter[*0] in CreateThread [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | |
| windows.cpp:357:8:357:25 | [summary param] *4 in CreateRemoteThread [x] | windows.cpp:357:8:357:25 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThread [x] | provenance | MaD:19 |
| windows.cpp:357:8:357:25 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThread [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | |
| windows.cpp:387:8:387:27 | [summary param] *4 in CreateRemoteThreadEx [x] | windows.cpp:387:8:387:27 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThreadEx [x] | provenance | MaD:20 |
| windows.cpp:387:8:387:27 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThreadEx [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | |
| windows.cpp:403:26:403:36 | *lpParameter [x] | windows.cpp:405:10:405:25 | *lpParameter [x] | provenance | |
| windows.cpp:405:10:405:25 | *lpParameter [x] | windows.cpp:406:8:406:8 | *s [x] | provenance | |
| windows.cpp:406:8:406:8 | *s [x] | windows.cpp:406:8:406:11 | x | provenance | |
| windows.cpp:410:26:410:36 | *lpParameter [x] | windows.cpp:412:10:412:25 | *lpParameter [x] | provenance | |
| windows.cpp:412:10:412:25 | *lpParameter [x] | windows.cpp:413:8:413:8 | *s [x] | provenance | |
| windows.cpp:413:8:413:8 | *s [x] | windows.cpp:413:8:413:11 | x | provenance | |
| windows.cpp:417:26:417:36 | *lpParameter [x] | windows.cpp:419:10:419:25 | *lpParameter [x] | provenance | |
| windows.cpp:419:10:419:25 | *lpParameter [x] | windows.cpp:420:8:420:8 | *s [x] | provenance | |
| windows.cpp:420:8:420:8 | *s [x] | windows.cpp:420:8:420:11 | x | provenance | |
| windows.cpp:431:3:431:3 | *s [post update] [x] | windows.cpp:439:7:439:8 | *& ... [x] | provenance | |
| windows.cpp:431:3:431:3 | *s [post update] [x] | windows.cpp:451:7:451:8 | *& ... [x] | provenance | |
| windows.cpp:431:3:431:3 | *s [post update] [x] | windows.cpp:464:7:464:8 | *& ... [x] | provenance | |
| windows.cpp:431:3:431:16 | ... = ... | windows.cpp:431:3:431:3 | *s [post update] [x] | provenance | |
| windows.cpp:431:9:431:14 | call to source | windows.cpp:431:3:431:16 | ... = ... | provenance | |
| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:349:8:349:19 | [summary param] *3 in CreateThread [x] | provenance | |
| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:357:8:357:25 | [summary param] *4 in CreateRemoteThread [x] | provenance | |
| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:387:8:387:27 | [summary param] *4 in CreateRemoteThreadEx [x] | provenance | |
nodes
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | semmle.label | [summary param] *0 in buffer |
| asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | semmle.label | [summary] to write: ReturnValue in buffer |
@@ -238,6 +264,30 @@ nodes
| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | semmle.label | *call to MapViewOfFileNuma2 |
| windows.cpp:333:20:333:52 | *pMapView | semmle.label | *pMapView |
| windows.cpp:335:10:335:16 | * ... | semmle.label | * ... |
| windows.cpp:349:8:349:19 | [summary param] *3 in CreateThread [x] | semmle.label | [summary param] *3 in CreateThread [x] |
| windows.cpp:349:8:349:19 | [summary] to write: Argument[2].Parameter[*0] in CreateThread [x] | semmle.label | [summary] to write: Argument[2].Parameter[*0] in CreateThread [x] |
| windows.cpp:357:8:357:25 | [summary param] *4 in CreateRemoteThread [x] | semmle.label | [summary param] *4 in CreateRemoteThread [x] |
| windows.cpp:357:8:357:25 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThread [x] | semmle.label | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThread [x] |
| windows.cpp:387:8:387:27 | [summary param] *4 in CreateRemoteThreadEx [x] | semmle.label | [summary param] *4 in CreateRemoteThreadEx [x] |
| windows.cpp:387:8:387:27 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThreadEx [x] | semmle.label | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThreadEx [x] |
| windows.cpp:403:26:403:36 | *lpParameter [x] | semmle.label | *lpParameter [x] |
| windows.cpp:405:10:405:25 | *lpParameter [x] | semmle.label | *lpParameter [x] |
| windows.cpp:406:8:406:8 | *s [x] | semmle.label | *s [x] |
| windows.cpp:406:8:406:11 | x | semmle.label | x |
| windows.cpp:410:26:410:36 | *lpParameter [x] | semmle.label | *lpParameter [x] |
| windows.cpp:412:10:412:25 | *lpParameter [x] | semmle.label | *lpParameter [x] |
| windows.cpp:413:8:413:8 | *s [x] | semmle.label | *s [x] |
| windows.cpp:413:8:413:11 | x | semmle.label | x |
| windows.cpp:417:26:417:36 | *lpParameter [x] | semmle.label | *lpParameter [x] |
| windows.cpp:419:10:419:25 | *lpParameter [x] | semmle.label | *lpParameter [x] |
| windows.cpp:420:8:420:8 | *s [x] | semmle.label | *s [x] |
| windows.cpp:420:8:420:11 | x | semmle.label | x |
| windows.cpp:431:3:431:3 | *s [post update] [x] | semmle.label | *s [post update] [x] |
| windows.cpp:431:3:431:16 | ... = ... | semmle.label | ... = ... |
| windows.cpp:431:9:431:14 | call to source | semmle.label | call to source |
| windows.cpp:439:7:439:8 | *& ... [x] | semmle.label | *& ... [x] |
| windows.cpp:451:7:451:8 | *& ... [x] | semmle.label | *& ... [x] |
| windows.cpp:464:7:464:8 | *& ... [x] | semmle.label | *& ... [x] |
subpaths
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | asio_streams.cpp:100:44:100:62 | call to buffer |
| test.cpp:17:24:17:24 | x | test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual |

View File

@@ -4638,7 +4638,13 @@
| Dubious signature "(z_streamp,int *)" in summary model. |
| Dubious signature "(z_streamp,unsigned int *,int *)" in summary model. |
| Dubious signature "(z_streamp,unsigned int)" in summary model. |
| Unrecognized input specification "Argument[***3]" in summary model. |
| Unrecognized input specification "Argument[***4]" in summary model. |
| Unrecognized input specification "Argument[****3]" in summary model. |
| Unrecognized input specification "Argument[****4]" in summary model. |
| Unrecognized input specification "Field[****hEvent]" in summary model. |
| Unrecognized input specification "Field[***hEvent]" in summary model. |
| Unrecognized output specification "Field[****hEvent]" in summary model. |
| Unrecognized output specification "Field[***hEvent]" in summary model. |
| Unrecognized output specification "Parameter[***0]" in summary model. |
| Unrecognized output specification "Parameter[****0]" in summary model. |

View File

@@ -335,3 +335,135 @@ void mapViewOfFile(HANDLE hMapFile) {
sink(*buffer); // $ ir
}
}
typedef struct _SECURITY_ATTRIBUTES
{
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
typedef DWORD (*LPTHREAD_START_ROUTINE)(
LPVOID lpThreadParameter);
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId);
HANDLE CreateRemoteThread(
HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
typedef ULONG_PTR DWORD_PTR;
typedef struct _PROC_THREAD_ATTRIBUTE_ENTRY
{
DWORD_PTR Attribute;
SIZE_T cbSize;
PVOID lpValue;
} PROC_THREAD_ATTRIBUTE_ENTRY, *LPPROC_THREAD_ATTRIBUTE_ENTRY;
// This structure contains a list of attributes that have been added using UpdateProcThreadAttribute
typedef struct _PROC_THREAD_ATTRIBUTE_LIST
{
DWORD dwFlags;
ULONG Size;
ULONG Count;
ULONG Reserved;
PULONG Unknown;
PROC_THREAD_ATTRIBUTE_ENTRY Entries[1];
} PROC_THREAD_ATTRIBUTE_LIST, *LPPROC_THREAD_ATTRIBUTE_LIST;
HANDLE CreateRemoteThreadEx(
HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
LPDWORD lpThreadId
);
struct S
{
int x;
};
DWORD ThreadProc1(LPVOID lpParameter)
{
S *s = (S *)lpParameter;
sink(s->x); // $ ir
return 0;
}
DWORD ThreadProc2(LPVOID lpParameter)
{
S *s = (S *)lpParameter;
sink(s->x); // $ ir
return 0;
}
DWORD ThreadProc3(LPVOID lpParameter)
{
S *s = (S *)lpParameter;
sink(s->x); // $ ir
return 0;
}
int source();
void test_create_thread()
{
SECURITY_ATTRIBUTES sa;
S s;
s.x = source();
{
DWORD threadId;
HANDLE threadHandle = CreateThread(
&sa,
0,
ThreadProc1,
&s,
0,
&threadId);
}
{
DWORD threadId;
HANDLE threadHandle = CreateRemoteThread(
nullptr,
&sa,
0,
ThreadProc2,
&s,
0,
&threadId);
}
{
DWORD threadId;
PROC_THREAD_ATTRIBUTE_LIST attrList;
HANDLE threadHandle = CreateRemoteThreadEx(
nullptr,
&sa,
0,
ThreadProc3,
&s,
0,
&attrList,
&threadId);
}
}

View File

@@ -9,10 +9,6 @@ inputs:
description: Whether to run formatting, code and qhelp generation checks
required: false
default: false
dynamic-join-order-mode:
description: Value of the --dynamic-join-order-mode flag to pass to the codeql test command
required: false
default: "none"
runs:
using: composite
steps:
@@ -67,15 +63,3 @@ runs:
with:
name: qhelp-markdown
path: go/qhelp-out/**/*.md
- name: Cache compilation cache
id: query-cache
uses: ./.github/actions/cache-query-compilation
with:
key: go-qltest
- name: Test
shell: bash
run: |
cd go
make test cache="${{ steps.query-cache.outputs.cache-dir }}" rtjo=${{ inputs.dynamic-join-order-mode }}

View File

@@ -0,0 +1,50 @@
#[derive(Eq, PartialEq)]
pub enum FieldType {
String,
Predicate,
Optional(String),
Body(String),
List(String),
}
pub struct FieldInfo {
pub name: String,
pub ty: FieldType,
}
impl FieldInfo {
pub fn optional(name: &str, ty: &str) -> FieldInfo {
FieldInfo {
name: name.to_string(),
ty: FieldType::Optional(ty.to_string()),
}
}
pub fn body(name: &str, ty: &str) -> FieldInfo {
FieldInfo {
name: name.to_string(),
ty: FieldType::Body(ty.to_string()),
}
}
pub fn string(name: &str) -> FieldInfo {
FieldInfo {
name: name.to_string(),
ty: FieldType::String,
}
}
pub fn predicate(name: &str) -> FieldInfo {
FieldInfo {
name: name.to_string(),
ty: FieldType::Predicate,
}
}
pub fn list(name: &str, ty: &str) -> FieldInfo {
FieldInfo {
name: name.to_string(),
ty: FieldType::List(ty.to_string()),
}
}
}

View File

@@ -2,7 +2,10 @@ use std::{fs, path::PathBuf};
pub mod codegen;
mod flags;
mod field_info;
use crate::codegen::grammar::ast_src::{AstEnumSrc, Cardinality};
use crate::field_info::{FieldInfo, FieldType};
use codegen::grammar::ast_src::{AstNodeSrc, AstSrc, Field};
use itertools::Itertools;
use serde::Serialize;
@@ -10,11 +13,6 @@ use std::collections::{BTreeMap, BTreeSet};
use std::env;
use ungrammar::Grammar;
fn project_root() -> PathBuf {
let dir = env::var("CARGO_MANIFEST_DIR").unwrap().to_owned();
PathBuf::from(dir).parent().unwrap().to_owned()
}
fn class_name(type_name: &str) -> String {
match type_name {
"BinExpr" => "BinaryExpr".to_owned(),
@@ -78,6 +76,128 @@ fn has_special_emission(type_name: &str) -> bool {
)
}
fn should_enum_be_skipped(name: &str) -> bool {
name == "VariantDef" // remove the VariantDef enum, there is no use for it at the moment
}
fn should_node_be_skipped(name: &str) -> bool {
name == "TypeAnchor" // we flatten TypeAnchor into PathSegment in the extractor
}
fn should_node_be_skipped_in_extractor(name: &str) -> bool {
name == "Adt" // no fields have `Adt` type, so we don't need extraction for it
}
fn should_field_be_skipped(node_name: &str, field_name: &str) -> bool {
matches!(
(node_name, field_name),
("ArrayExpr", "expr") // The ArrayExpr type also has an 'exprs' field
| ("PathSegment", "type_anchor") // we flatten TypeAnchor into PathSegment in the extractor
| ("Param", "pat") | ("MacroCall", "token_tree") // handled manually to use `body`
)
}
fn get_additional_fields(node_name: &str) -> Vec<FieldInfo> {
match node_name {
"Name" | "NameRef" | "Lifetime" => vec![FieldInfo::string("text")],
"Abi" => vec![FieldInfo::string("abi_string")],
"Literal" => vec![FieldInfo::string("text_value")],
"PrefixExpr" => vec![FieldInfo::string("operator_name")],
"BinExpr" => vec![
FieldInfo::optional("lhs", "Expr"),
FieldInfo::optional("rhs", "Expr"),
FieldInfo::string("operator_name"),
],
"IfExpr" => vec![
FieldInfo::optional("then_branch", "BlockExpr"),
FieldInfo::optional("else_branch", "ElseBranch"),
FieldInfo::optional("condition", "Expr"),
],
"RangeExpr" => vec![
FieldInfo::optional("start", "Expr"),
FieldInfo::optional("end", "Expr"),
FieldInfo::string("operator_name"),
],
"RangePat" => vec![
FieldInfo::optional("start", "Pat"),
FieldInfo::optional("end", "Pat"),
FieldInfo::string("operator_name"),
],
"IndexExpr" => vec![
FieldInfo::optional("index", "Expr"),
FieldInfo::optional("base", "Expr"),
],
"Impl" => vec![
FieldInfo::optional("trait_", "Type"),
FieldInfo::optional("self_ty", "Type"),
],
"ForExpr" => vec![FieldInfo::optional("iterable", "Expr")],
"WhileExpr" => vec![FieldInfo::optional("condition", "Expr")],
"MatchGuard" => vec![FieldInfo::optional("condition", "Expr")],
"MacroDef" => vec![
FieldInfo::body("args", "TokenTree"),
FieldInfo::body("body", "TokenTree"),
],
"MacroCall" => vec![FieldInfo::body("token_tree", "TokenTree")],
"FormatArgsExpr" => vec![FieldInfo::list("args", "FormatArgsArg")],
"ArgList" => vec![FieldInfo::list("args", "Expr")],
"Fn" => vec![FieldInfo::body("body", "BlockExpr")],
"Const" => vec![FieldInfo::body("body", "Expr")],
"Static" => vec![FieldInfo::body("body", "Expr")],
"Param" => vec![FieldInfo::body("pat", "Pat")],
"ClosureExpr" => vec![FieldInfo::optional("body", "Expr")],
"ArrayExpr" => vec![FieldInfo::predicate("is_semicolon")],
"SelfParam" => vec![FieldInfo::predicate("is_amp")],
"UseTree" => vec![FieldInfo::predicate("is_star")],
_ => vec![],
}
}
fn get_trait_fields(trait_name: &str) -> Vec<FieldInfo> {
match trait_name {
"HasAttrs" => vec![FieldInfo::list("attrs", "Attr")],
"HasName" => vec![FieldInfo::optional("name", "Name")],
"HasVisibility" => vec![FieldInfo::optional("visibility", "Visibility")],
"HasGenericParams" => vec![
FieldInfo::optional("generic_param_list", "GenericParamList"),
FieldInfo::optional("where_clause", "WhereClause"),
],
"HasGenericArgs" => vec![FieldInfo::optional("generic_arg_list", "GenericArgList")],
"HasTypeBounds" => vec![FieldInfo::optional("type_bound_list", "TypeBoundList")],
"HasModuleItem" => vec![FieldInfo::list("items", "Item")],
"HasLoopBody" =>
vec![FieldInfo::optional("label", "Label"),
FieldInfo::optional("loop_body", "BlockExpr")],
"HasArgList" => vec![FieldInfo::optional("arg_list", "ArgList")],
"HasDocComments" => vec![],
_ => panic!("Unknown trait {}", trait_name),
}
}
fn should_predicate_be_extracted(name: &str) -> bool {
matches!(
name,
"async"
| "auto"
| "const"
| "default"
| "gen"
| "move"
| "mut"
| "raw"
| "ref"
| "static"
| "try"
| "unsafe"
)
}
fn project_root() -> PathBuf {
let dir = env::var("CARGO_MANIFEST_DIR").unwrap().to_owned();
PathBuf::from(dir).parent().unwrap().to_owned()
}
fn to_lower_snake_case(s: &str) -> String {
let mut buf = String::with_capacity(s.len());
let mut prev = false;
@@ -192,121 +312,11 @@ fn write_schema(
Ok(fix_blank_lines(&res))
}
#[derive(Eq, PartialEq)]
enum FieldType {
String,
Predicate,
Optional(String),
Body(String),
List(String),
}
struct FieldInfo {
name: String,
ty: FieldType,
}
impl FieldInfo {
pub fn optional(name: &str, ty: &str) -> FieldInfo {
FieldInfo {
name: name.to_string(),
ty: FieldType::Optional(ty.to_string()),
}
}
pub fn body(name: &str, ty: &str) -> FieldInfo {
FieldInfo {
name: name.to_string(),
ty: FieldType::Body(ty.to_string()),
}
}
pub fn string(name: &str) -> FieldInfo {
FieldInfo {
name: name.to_string(),
ty: FieldType::String,
}
}
pub fn predicate(name: &str) -> FieldInfo {
FieldInfo {
name: name.to_string(),
ty: FieldType::Predicate,
}
}
pub fn list(name: &str, ty: &str) -> FieldInfo {
FieldInfo {
name: name.to_string(),
ty: FieldType::List(ty.to_string()),
}
}
}
fn get_additional_fields(node: &AstNodeSrc) -> Vec<FieldInfo> {
match node.name.as_str() {
"Name" | "NameRef" | "Lifetime" => vec![FieldInfo::string("text")],
"Abi" => vec![FieldInfo::string("abi_string")],
"Literal" => vec![FieldInfo::string("text_value")],
"PrefixExpr" => vec![FieldInfo::string("operator_name")],
"BinExpr" => vec![
FieldInfo::optional("lhs", "Expr"),
FieldInfo::optional("rhs", "Expr"),
FieldInfo::string("operator_name"),
],
"IfExpr" => vec![
FieldInfo::optional("then_branch", "BlockExpr"),
FieldInfo::optional("else_branch", "ElseBranch"),
FieldInfo::optional("condition", "Expr"),
],
"RangeExpr" => vec![
FieldInfo::optional("start", "Expr"),
FieldInfo::optional("end", "Expr"),
FieldInfo::string("operator_name"),
],
"RangePat" => vec![
FieldInfo::optional("start", "Pat"),
FieldInfo::optional("end", "Pat"),
FieldInfo::string("operator_name"),
],
"IndexExpr" => vec![
FieldInfo::optional("index", "Expr"),
FieldInfo::optional("base", "Expr"),
],
"Impl" => vec![
FieldInfo::optional("trait_", "Type"),
FieldInfo::optional("self_ty", "Type"),
],
"ForExpr" => vec![FieldInfo::optional("iterable", "Expr")],
"WhileExpr" => vec![FieldInfo::optional("condition", "Expr")],
"MatchGuard" => vec![FieldInfo::optional("condition", "Expr")],
"MacroDef" => vec![
FieldInfo::body("args", "TokenTree"),
FieldInfo::body("body", "TokenTree"),
],
"MacroCall" => vec![FieldInfo::body("token_tree", "TokenTree")],
"FormatArgsExpr" => vec![FieldInfo::list("args", "FormatArgsArg")],
"ArgList" => vec![FieldInfo::list("args", "Expr")],
"Fn" => vec![FieldInfo::body("body", "BlockExpr")],
"Const" => vec![FieldInfo::body("body", "Expr")],
"Static" => vec![FieldInfo::body("body", "Expr")],
"Param" => vec![FieldInfo::body("pat", "Pat")],
"ClosureExpr" => vec![FieldInfo::optional("body", "Expr")],
"ArrayExpr" => vec![FieldInfo::predicate("is_semicolon")],
"SelfParam" => vec![FieldInfo::predicate("is_amp")],
"UseTree" => vec![FieldInfo::predicate("is_star")],
_ => vec![],
}
}
fn get_fields(node: &AstNodeSrc) -> Vec<FieldInfo> {
let mut result = Vec::new();
let predicates = [
"async", "auto", "const", "default", "gen", "move", "mut", "raw", "ref", "static", "try",
"unsafe",
];
for field in &node.fields {
if let Field::Token(name) = field {
if predicates.contains(&name.as_str()) {
if should_predicate_be_extracted(&name) {
result.push(FieldInfo {
name: format!("is_{name}"),
ty: FieldType::Predicate,
@@ -315,17 +325,11 @@ fn get_fields(node: &AstNodeSrc) -> Vec<FieldInfo> {
}
}
result.extend(get_additional_fields(node));
result.extend(get_additional_fields(&node.name));
for field in &node.fields {
let name = field.method_name();
match (node.name.as_str(), name.as_str()) {
("ArrayExpr", "expr") // The ArrayExpr type also has an 'exprs' field
| ("PathSegment", "type_anchor") // we flatten TypeAnchor into PathSegment in the extractor
| ("Param", "pat") | ("MacroCall", "token_tree") // handled manually to use `body`
=> continue,
_ => {}
}
if should_field_be_skipped(&node.name, &name) { continue; }
let ty = match field {
Field::Token(_) => continue,
Field::Node {
@@ -338,31 +342,7 @@ fn get_fields(node: &AstNodeSrc) -> Vec<FieldInfo> {
result.push(FieldInfo { name, ty });
}
for trait_ in &node.traits {
match trait_.as_str() {
"HasAttrs" => result.push(FieldInfo::list("attrs", "Attr")),
"HasName" => result.push(FieldInfo::optional("name", "Name")),
"HasVisibility" => result.push(FieldInfo::optional("visibility", "Visibility")),
"HasGenericParams" => {
result.push(FieldInfo::optional(
"generic_param_list",
"GenericParamList",
));
result.push(FieldInfo::optional("where_clause", "WhereClause"))
}
"HasGenericArgs" => {
result.push(FieldInfo::optional("generic_arg_list", "GenericArgList"))
}
"HasTypeBounds" => result.push(FieldInfo::optional("type_bound_list", "TypeBoundList")),
"HasModuleItem" => result.push(FieldInfo::list("items", "Item")),
"HasLoopBody" => {
result.push(FieldInfo::optional("label", "Label"));
result.push(FieldInfo::optional("loop_body", "BlockExpr"))
}
"HasArgList" => result.push(FieldInfo::optional("arg_list", "ArgList")),
"HasDocComments" => {}
_ => panic!("Unknown trait {}", trait_),
};
result.extend(get_trait_fields(&trait_));
}
result.sort_by(|x, y| x.name.cmp(&y.name));
result
@@ -412,12 +392,8 @@ struct ExtractorInfo {
nodes: Vec<ExtractorNodeInfo>,
}
fn enum_to_extractor_info(node: &AstEnumSrc) -> Option<ExtractorEnumInfo> {
if node.name == "Adt" {
// no fields have `Adt` type, so we don't need extraction for it
return None;
}
Some(ExtractorEnumInfo {
fn enum_to_extractor_info(node: &AstEnumSrc) -> ExtractorEnumInfo {
ExtractorEnumInfo {
name: class_name(&node.name),
snake_case_name: to_lower_snake_case(&node.name),
ast_name: node.name.clone(),
@@ -435,7 +411,7 @@ fn enum_to_extractor_info(node: &AstEnumSrc) -> Option<ExtractorEnumInfo> {
})
.collect(),
has_special_emission: has_special_emission(&node.name),
})
}
}
fn field_info_to_extractor_info(name: &str, field: &FieldInfo) -> ExtractorNodeFieldInfo {
@@ -498,7 +474,8 @@ fn write_extractor(grammar: &AstSrc, mustache_ctx: &mustache::Context) -> mustac
enums: grammar
.enums
.iter()
.filter_map(enum_to_extractor_info)
.filter(|e| !should_node_be_skipped_in_extractor(&e.name))
.map(enum_to_extractor_info)
.collect(),
nodes: grammar.nodes.iter().map(node_to_extractor_info).collect(),
};
@@ -514,11 +491,8 @@ fn main() -> anyhow::Result<()> {
.parse()
.expect("Failed to parse grammar");
let mut grammar = codegen::grammar::lower(&grammar);
// remove the VariantDef enum, there is no use for it at the moment
grammar.enums.retain(|e| e.name != "VariantDef");
// we flatten TypeAnchor into PathSegment in the extractor
grammar.nodes.retain(|x| x.name != "TypeAnchor");
grammar.enums.retain(|e| !should_enum_be_skipped(&e.name));
grammar.nodes.retain(|x| !should_node_be_skipped(&x.name));
let mut super_types: BTreeMap<String, BTreeSet<String>> = BTreeMap::new();
for node in &grammar.enums {

View File

@@ -71,6 +71,7 @@ pub struct Config {
pub proc_macro_server: Option<PathBuf>,
pub skip_path_resolution: bool,
pub extract_dependencies_as_source: bool,
pub force_library_mode: bool, // for testing purposes
}
impl Config {

View File

@@ -293,6 +293,11 @@ fn main() -> anyhow::Result<()> {
} else {
(SourceKind::Library, ResolvePaths::No)
};
let (source_mode, source_resolve_paths) = if cfg.force_library_mode {
(library_mode, library_resolve_paths)
} else {
(SourceKind::Source, resolve_paths)
};
let mut processed_files: HashSet<PathBuf, RandomState> =
HashSet::from_iter(files.iter().cloned());
for (manifest, files) in map.values().filter(|(_, files)| !files.is_empty()) {
@@ -311,12 +316,10 @@ fn main() -> anyhow::Result<()> {
file,
&semantics,
vfs,
resolve_paths,
SourceKind::Source,
source_resolve_paths,
source_mode,
),
Err(reason) => {
extractor.extract_without_semantics(file, SourceKind::Source, &reason)
}
Err(reason) => extractor.extract_without_semantics(file, source_mode, &reason),
};
}
for (file_id, file) in vfs.iter() {

View File

@@ -19,7 +19,7 @@ fn dump_lib() -> anyhow::Result<()> {
.iter()
.map(|p| p.file_stem().expect("results of glob must have a name"))
.filter(|&p| !["main", "lib", "proc_macro"].map(OsStr::new).contains(&p))
.map(|p| format!("mod {};", p.to_string_lossy()))
.map(|p| format!("pub mod {};", p.to_string_lossy()))
.join("\n");
fs::write("lib.rs", lib).context("writing lib.rs")
}

View File

@@ -24,33 +24,31 @@ use ra_ap_syntax::{
impl Emission<ast::Item> for Translator<'_> {
fn pre_emit(&mut self, node: &ast::Item) -> Option<Label<generated::Item>> {
self.prepare_item_expansion(node).map(Into::into)
self.item_pre_emit(node).map(Into::into)
}
fn post_emit(&mut self, node: &ast::Item, label: Label<generated::Item>) {
self.emit_item_expansion(node, label);
self.item_post_emit(node, label);
}
}
impl Emission<ast::AssocItem> for Translator<'_> {
fn pre_emit(&mut self, node: &ast::AssocItem) -> Option<Label<generated::AssocItem>> {
self.prepare_item_expansion(&node.clone().into())
.map(Into::into)
self.item_pre_emit(&node.clone().into()).map(Into::into)
}
fn post_emit(&mut self, node: &ast::AssocItem, label: Label<generated::AssocItem>) {
self.emit_item_expansion(&node.clone().into(), label.into());
self.item_post_emit(&node.clone().into(), label.into());
}
}
impl Emission<ast::ExternItem> for Translator<'_> {
fn pre_emit(&mut self, node: &ast::ExternItem) -> Option<Label<generated::ExternItem>> {
self.prepare_item_expansion(&node.clone().into())
.map(Into::into)
self.item_pre_emit(&node.clone().into()).map(Into::into)
}
fn post_emit(&mut self, node: &ast::ExternItem, label: Label<generated::ExternItem>) {
self.emit_item_expansion(&node.clone().into(), label.into());
self.item_post_emit(&node.clone().into(), label.into());
}
}
@@ -849,35 +847,6 @@ impl<'a> Translator<'a> {
})
}
pub(crate) fn prepare_item_expansion(
&mut self,
node: &ast::Item,
) -> Option<Label<generated::MacroCall>> {
if self.source_kind == SourceKind::Library {
// if the item expands via an attribute macro, we want to only emit the expansion
if let Some(expanded) = self.emit_attribute_macro_expansion(node) {
// we wrap it in a dummy MacroCall to get a single Item label that can replace
// the original Item
let label = self.trap.emit(generated::MacroCall {
id: TrapId::Star,
attrs: vec![],
path: None,
token_tree: None,
});
generated::MacroCall::emit_macro_call_expansion(
label,
expanded.into(),
&mut self.trap.writer,
);
return Some(label);
}
}
if self.is_attribute_macro_target(node) {
self.macro_context_depth += 1;
}
None
}
fn process_item_macro_expansion(
&mut self,
node: &impl ast::AstNode,
@@ -915,10 +884,6 @@ impl<'a> Translator<'a> {
&mut self,
node: &ast::Item,
) -> Option<Label<generated::MacroItems>> {
if !self.is_attribute_macro_target(node) {
return None;
}
self.macro_context_depth -= 1;
if self.macro_context_depth > 0 {
// only expand the outermost attribute macro
return None;
@@ -927,7 +892,49 @@ impl<'a> Translator<'a> {
self.process_item_macro_expansion(node, expansion.map(|x| x.value))
}
pub(crate) fn emit_item_expansion(&mut self, node: &ast::Item, label: Label<generated::Item>) {
pub(crate) fn item_pre_emit(
&mut self,
node: &ast::Item,
) -> Option<Label<generated::MacroCall>> {
if !self.is_attribute_macro_target(node) {
return None;
}
if self.source_kind == SourceKind::Library {
// if the item expands via an attribute macro, we want to only emit the expansion
if let Some(expanded) = self.emit_attribute_macro_expansion(node) {
// we wrap it in a dummy MacroCall to get a single Item label that can replace
// the original Item
let label = self.trap.emit(generated::MacroCall {
id: TrapId::Star,
attrs: vec![],
path: None,
token_tree: None,
});
generated::Item::emit_attribute_macro_expansion(
label.into(),
expanded,
&mut self.trap.writer,
);
self.emit_location(label, node);
return Some(label);
}
}
self.macro_context_depth += 1;
None
}
pub(crate) fn item_post_emit(&mut self, node: &ast::Item, label: Label<generated::Item>) {
if !self.is_attribute_macro_target(node) {
return;
}
// see `item_pre_emit`:
// if self.is_attribute_macro_target(node), then we either exited early with `Some(label)`
// and are not here, or we did self.macro_context_depth += 1
assert!(
self.macro_context_depth > 0,
"macro_context_depth should be > 0 for an attribute macro target"
);
self.macro_context_depth -= 1;
if let Some(expanded) = self.emit_attribute_macro_expansion(node) {
generated::Item::emit_attribute_macro_expansion(label, expanded, &mut self.trap.writer);
}

View File

@@ -32,7 +32,9 @@ module Impl {
* ```
*/
class MacroCall extends Generated::MacroCall {
override string toStringImpl() { result = this.getPath().toAbbreviatedString() + "!..." }
override string toStringImpl() {
if this.hasPath() then result = this.getPath().toAbbreviatedString() + "!..." else result = ""
}
/** Gets an AST node whose location is inside the token tree belonging to this macro call. */
pragma[nomagic]

View File

@@ -6,7 +6,7 @@ predicate toBeTested(Element e) {
(
not e instanceof Locatable
or
e.(Locatable).fromSource()
exists(e.(Locatable).getFile().getRelativePath())
)
}

View File

@@ -2,8 +2,8 @@ canonicalPath
| anonymous.rs:3:1:32:1 | fn canonicals | test::anonymous::canonicals |
| anonymous.rs:34:1:36:1 | fn other | test::anonymous::other |
| {EXTERNAL LOCATION} | fn trim | <core::str>::trim |
| lib.rs:1:1:1:14 | mod anonymous | test::anonymous |
| lib.rs:2:1:2:12 | mod regular | test::regular |
| lib.rs:1:1:1:18 | mod anonymous | test::anonymous |
| lib.rs:2:1:2:16 | mod regular | test::regular |
| regular.rs:1:1:2:18 | struct Struct | test::regular::Struct |
| regular.rs:2:12:2:17 | fn eq | <test::regular::Struct as core::cmp::PartialEq>::eq |
| regular.rs:2:12:2:17 | impl ...::Eq for Struct::<...> { ... } | <test::regular::Struct as core::cmp::Eq> |
@@ -42,8 +42,8 @@ canonicalPaths
| anonymous.rs:26:5:31:5 | fn usage | None | None |
| anonymous.rs:34:1:36:1 | fn other | repo::test | crate::anonymous::other |
| anonymous.rs:35:5:35:23 | struct OtherStruct | None | None |
| lib.rs:1:1:1:14 | mod anonymous | repo::test | crate::anonymous |
| lib.rs:2:1:2:12 | mod regular | repo::test | crate::regular |
| lib.rs:1:1:1:18 | mod anonymous | repo::test | crate::anonymous |
| lib.rs:2:1:2:16 | mod regular | repo::test | crate::regular |
| regular.rs:1:1:2:18 | struct Struct | repo::test | crate::regular::Struct |
| regular.rs:2:12:2:17 | fn eq | repo::test | <crate::regular::Struct as crate::cmp::PartialEq>::eq |
| regular.rs:2:12:2:17 | impl ...::Eq for Struct::<...> { ... } | None | None |

View File

@@ -2,8 +2,8 @@ canonicalPath
| anonymous.rs:6:1:35:1 | fn canonicals | test::anonymous::canonicals |
| anonymous.rs:37:1:39:1 | fn other | test::anonymous::other |
| {EXTERNAL LOCATION} | fn trim | <core::str>::trim |
| lib.rs:1:1:1:14 | mod anonymous | test::anonymous |
| lib.rs:2:1:2:12 | mod regular | test::regular |
| lib.rs:1:1:1:18 | mod anonymous | test::anonymous |
| lib.rs:2:1:2:16 | mod regular | test::regular |
| regular.rs:4:1:5:18 | struct Struct | test::regular::Struct |
| regular.rs:5:12:5:17 | fn eq | <test::regular::Struct as core::cmp::PartialEq>::eq |
| regular.rs:5:12:5:17 | impl ...::Eq for Struct::<...> { ... } | <test::regular::Struct as core::cmp::Eq> |
@@ -42,8 +42,8 @@ canonicalPaths
| anonymous.rs:29:5:34:5 | fn usage | None | None |
| anonymous.rs:37:1:39:1 | fn other | None | None |
| anonymous.rs:38:5:38:23 | struct OtherStruct | None | None |
| lib.rs:1:1:1:14 | mod anonymous | None | None |
| lib.rs:2:1:2:12 | mod regular | None | None |
| lib.rs:1:1:1:18 | mod anonymous | None | None |
| lib.rs:2:1:2:16 | mod regular | None | None |
| regular.rs:4:1:5:18 | struct Struct | None | None |
| regular.rs:5:12:5:17 | fn eq | None | None |
| regular.rs:5:12:5:17 | impl ...::Eq for Struct::<...> { ... } | None | None |

View File

@@ -1,15 +1,15 @@
instances
| gen_module.rs:3:1:4:8 | mod foo |
| gen_module.rs:5:1:7:1 | mod bar |
| lib.rs:1:1:1:15 | mod gen_module |
| lib.rs:1:1:1:19 | mod gen_module |
getExtendedCanonicalPath
| gen_module.rs:3:1:4:8 | mod foo | crate::gen_module::foo |
| gen_module.rs:5:1:7:1 | mod bar | crate::gen_module::bar |
| lib.rs:1:1:1:15 | mod gen_module | crate::gen_module |
| lib.rs:1:1:1:19 | mod gen_module | crate::gen_module |
getCrateOrigin
| gen_module.rs:3:1:4:8 | mod foo | repo::test |
| gen_module.rs:5:1:7:1 | mod bar | repo::test |
| lib.rs:1:1:1:15 | mod gen_module | repo::test |
| lib.rs:1:1:1:19 | mod gen_module | repo::test |
getAttributeMacroExpansion
getAttr
getItemList
@@ -17,5 +17,6 @@ getItemList
getName
| gen_module.rs:3:1:4:8 | mod foo | gen_module.rs:4:5:4:7 | foo |
| gen_module.rs:5:1:7:1 | mod bar | gen_module.rs:5:5:5:7 | bar |
| lib.rs:1:1:1:15 | mod gen_module | lib.rs:1:5:1:14 | gen_module |
| lib.rs:1:1:1:19 | mod gen_module | lib.rs:1:9:1:18 | gen_module |
getVisibility
| lib.rs:1:1:1:19 | mod gen_module | lib.rs:1:1:1:3 | Visibility |

View File

@@ -1,8 +1,8 @@
instances
| gen_name.rs:3:4:3:12 | test_name |
| gen_name.rs:7:9:7:11 | foo |
| lib.rs:1:5:1:12 | gen_name |
| lib.rs:1:9:1:16 | gen_name |
getText
| gen_name.rs:3:4:3:12 | test_name | test_name |
| gen_name.rs:7:9:7:11 | foo | foo |
| lib.rs:1:5:1:12 | gen_name | gen_name |
| lib.rs:1:9:1:16 | gen_name | gen_name |

View File

@@ -1,7 +1,7 @@
instances
| gen_source_file.rs:1:1:9:2 | SourceFile |
| lib.rs:1:1:1:20 | SourceFile |
| lib.rs:1:1:1:24 | SourceFile |
getAttr
getItem
| gen_source_file.rs:1:1:9:2 | SourceFile | 0 | gen_source_file.rs:3:1:9:1 | fn test_source_file |
| lib.rs:1:1:1:20 | SourceFile | 0 | lib.rs:1:1:1:20 | mod gen_source_file |
| lib.rs:1:1:1:24 | SourceFile | 0 | lib.rs:1:1:1:24 | mod gen_source_file |

View File

@@ -1,3 +1,4 @@
instances
| gen_visibility.rs:7:7:7:9 | Visibility |
| lib.rs:1:1:1:3 | Visibility |
getPath

View File

@@ -146,8 +146,10 @@ lib.rs:
# 1| [SourceFile] SourceFile
# 1| getItem(0): [Module] mod call
# 1| getName(): [Name] call
# 1| getVisibility(): [Visibility] Visibility
# 2| getItem(1): [Module] mod macro_expansion
# 2| getName(): [Name] macro_expansion
# 2| getVisibility(): [Visibility] Visibility
macro_expansion.rs:
# 1| [SourceFile] SourceFile
# 1| getItem(0): [Use] use proc_macro::{...}

View File

@@ -0,0 +1,53 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "proc_macro"
version = "0.0.1"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "test"
version = "0.0.1"
dependencies = [
"proc_macro",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"

View File

@@ -0,0 +1,63 @@
lib.rs:
# 1| [SourceFile] SourceFile
# 1| getItem(0): [Module] mod macro_in_library
# 1| getName(): [Name] macro_in_library
# 1| getVisibility(): [Visibility] Visibility
macro_in_library.rs:
# 1| [SourceFile] SourceFile
# 1| getItem(0): [MacroCall]
# 2| getAttributeMacroExpansion(): [MacroItems] MacroItems
# 2| getItem(0): [Function] fn foo
# 2| getParamList(): [ParamList] ParamList
# 2| getName(): [Name] foo
# 2| getVisibility(): [Visibility] Visibility
# 2| getItem(1): [Function] fn foo_new
# 2| getParamList(): [ParamList] ParamList
# 2| getName(): [Name] foo_new
# 2| getVisibility(): [Visibility] Visibility
# 4| getItem(1): [Function] fn bar
# 4| getParamList(): [ParamList] ParamList
# 4| getName(): [Name] bar
# 4| getVisibility(): [Visibility] Visibility
proc_macro.rs:
# 1| [SourceFile] SourceFile
# 1| getItem(0): [Use] use ...::TokenStream
# 1| getUseTree(): [UseTree] ...::TokenStream
# 1| getPath(): [Path] ...::TokenStream
# 1| getQualifier(): [Path] proc_macro
# 1| getSegment(): [PathSegment] proc_macro
# 1| getIdentifier(): [NameRef] proc_macro
# 1| getSegment(): [PathSegment] TokenStream
# 1| getIdentifier(): [NameRef] TokenStream
# 2| getItem(1): [Use] use ...::quote
# 2| getUseTree(): [UseTree] ...::quote
# 2| getPath(): [Path] ...::quote
# 2| getQualifier(): [Path] quote
# 2| getSegment(): [PathSegment] quote
# 2| getIdentifier(): [NameRef] quote
# 2| getSegment(): [PathSegment] quote
# 2| getIdentifier(): [NameRef] quote
# 4| getItem(2): [Function] fn add_one
# 5| getParamList(): [ParamList] ParamList
# 5| getParam(0): [Param] : TokenStream
# 5| getTypeRepr(): [PathTypeRepr] TokenStream
# 5| getPath(): [Path] TokenStream
# 5| getSegment(): [PathSegment] TokenStream
# 5| getIdentifier(): [NameRef] TokenStream
# 5| getParam(1): [Param] : TokenStream
# 5| getTypeRepr(): [PathTypeRepr] TokenStream
# 5| getPath(): [Path] TokenStream
# 5| getSegment(): [PathSegment] TokenStream
# 5| getIdentifier(): [NameRef] TokenStream
# 4| getAttr(0): [Attr] Attr
# 4| getMeta(): [Meta] Meta
# 4| getPath(): [Path] proc_macro_attribute
# 4| getSegment(): [PathSegment] proc_macro_attribute
# 4| getIdentifier(): [NameRef] proc_macro_attribute
# 5| getName(): [Name] add_one
# 5| getRetType(): [RetTypeRepr] RetTypeRepr
# 5| getTypeRepr(): [PathTypeRepr] TokenStream
# 5| getPath(): [Path] TokenStream
# 5| getSegment(): [PathSegment] TokenStream
# 5| getIdentifier(): [NameRef] TokenStream
# 5| getVisibility(): [Visibility] Visibility

View File

@@ -0,0 +1 @@
utils/PrintAst.ql

View File

@@ -0,0 +1,6 @@
#[proc_macro::add_one]
pub fn foo() {}
pub fn bar() {
foo_new();
}

View File

@@ -0,0 +1 @@
force_library_mode: true

View File

@@ -0,0 +1,14 @@
use proc_macro::TokenStream;
use quote::quote;
#[proc_macro_attribute]
pub fn add_one(_attr: TokenStream, item: TokenStream) -> TokenStream {
let ast = syn::parse_macro_input!(item as syn::ItemFn);
let mut new_ast = ast.clone();
new_ast.sig.ident = syn::Ident::new(&format!("{}_new", ast.sig.ident), ast.sig.ident.span());
quote! {
#ast
#new_ast
}.into()
}

View File

@@ -0,0 +1,4 @@
macro_items
| macro_in_library.rs:2:1:2:14 | MacroItems | 0 | macro_in_library.rs:2:1:2:14 | fn foo |
| macro_in_library.rs:2:1:2:14 | MacroItems | 1 | macro_in_library.rs:2:1:2:14 | fn foo_new |
warnings

View File

@@ -0,0 +1,10 @@
import rust
import codeql.rust.Diagnostics
query predicate macro_items(MacroItems c, int index, Item expanded) {
exists(c.getFile().getRelativePath()) and
not c.getLocation().getFile().getAbsolutePath().matches("%proc_macro.rs") and
expanded = c.getItem(index)
}
query predicate warnings(ExtractionWarning w) { any() }

View File

@@ -1,6 +1,7 @@
| lib.rs:1:1:1:21 | SourceFile |
| lib.rs:1:1:1:21 | mod utf8_identifiers |
| lib.rs:1:5:1:20 | utf8_identifiers |
| lib.rs:1:1:1:3 | Visibility |
| lib.rs:1:1:1:25 | SourceFile |
| lib.rs:1:1:1:25 | mod utf8_identifiers |
| lib.rs:1:9:1:24 | utf8_identifiers |
| utf8_identifiers.rs:1:1:4:6 | fn foo |
| utf8_identifiers.rs:1:1:12:2 | SourceFile |
| utf8_identifiers.rs:1:4:1:6 | foo |

View File

@@ -1,5 +1,5 @@
mod
| lib.rs:1:1:1:7 | mod my |
| lib.rs:1:1:1:11 | mod my |
| main.rs:1:1:1:7 | mod my |
| main.rs:7:1:7:8 | mod my2 |
| main.rs:13:1:37:1 | mod m1 |