Skip to content

Commit 3199a69

Browse files
authored
Merge pull request github#8854 from redsun82/swift-ql-gen
Swift: QL generation script
2 parents 60eb341 + 643471f commit 3199a69

File tree

579 files changed

+4254
-59
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

579 files changed

+4254
-59
lines changed

.github/workflows/check-qldoc.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ jobs:
3030
shell: bash
3131
run: |
3232
EXIT_CODE=0
33-
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -o '^[a-z]*/ql/lib' || true; } | sort -u)"
33+
# TODO: remove the swift exception from the regex when we fix generated QLdoc
34+
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -Po '^(?!swift)[a-z]*/ql/lib' || true; } | sort -u)"
3435
for pack_dir in ${changed_lib_packs}; do
3536
lang="${pack_dir%/ql/lib}"
3637
gh codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-current.txt" --dir="${pack_dir}"

.github/workflows/swift-codegen.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: "Swift: Check code generation"
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "swift/**"
7+
- .github/workflows/swift-codegen.yml
8+
branches:
9+
- main
10+
11+
jobs:
12+
codegen:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v2
16+
- uses: actions/setup-python@v3
17+
with:
18+
python-version: '~3.7'
19+
cache: 'pip'
20+
- uses: ./.github/actions/fetch-codeql
21+
- uses: bazelbuild/setup-bazelisk@v2
22+
- name: Check code generation
23+
run: |
24+
pip install -r swift/codegen/requirements.txt
25+
bazel run //swift/codegen
26+
git add swift
27+
git diff --exit-code --stat HEAD

.github/workflows/swift-qltest.yml

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,7 @@ jobs:
2828
steps:
2929
- uses: actions/checkout@v2
3030
- uses: ./.github/actions/fetch-codeql
31-
- name: Install bazelisk - Linux
32-
if: runner.os == 'Linux'
33-
run: |
34-
sudo apt-get update
35-
sudo apt-get install -y wget
36-
wget https://github.com/bazelbuild/bazelisk/releases/download/v1.11.0/bazelisk-linux-amd64
37-
mv bazelisk-linux-amd64 /usr/local/bin/bazel
38-
chmod +x /usr/local/bin/bazel
39-
- name: Install bazelisk - macOS
40-
if: runner.os == 'MacOS'
41-
run: |
42-
brew install bazelisk
31+
- uses: bazelbuild/setup-bazelisk@v2
4332
- name: Build Swift extractor
4433
run: |
4534
bazel run //swift:create-extractor-pack
@@ -48,4 +37,3 @@ jobs:
4837
codeql test run --threads=0 --ram 5000 --search-path "${{ github.workspace }}/swift/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition ql/test
4938
env:
5039
GITHUB_TOKEN: ${{ github.token }}
51-

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ repos:
3636

3737
- id: swift-codegen
3838
name: Run Swift checked in code generation
39-
files: ^swift/(codegen/|.*/generated/|ql/lib/swift\.dbscheme$)
39+
files: ^swift/(codegen/|.*/generated/|ql/lib/(swift\.dbscheme$|codeql/swift/elements))
4040
language: system
4141
entry: bazel run //swift/codegen
4242
pass_filenames: false

swift/codegen/codegen.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from lib import generator
55
import dbschemegen
6+
import qlgen
67

78
if __name__ == "__main__":
8-
generator.run(dbschemegen.generate)
9+
generator.run(dbschemegen.generate, qlgen.generate)

swift/codegen/lib/generator.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,5 @@ def run(*generators, tags=None):
2323
`generators` should be callables taking as input an option namespace and a `render.Renderer` instance
2424
"""
2525
opts = _parse(tags)
26-
renderer = render.Renderer(dryrun=opts.check)
2726
for g in generators:
28-
g(opts, renderer)
29-
sys.exit(1 if opts.check and renderer.done_something else 0)
27+
g(opts, render.Renderer())

swift/codegen/lib/options.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99

1010

1111
def _init_options():
12-
Option("--check", "-c", action="store_true")
1312
Option("--verbose", "-v", action="store_true")
1413
Option("--schema", tags=["schema"], type=pathlib.Path, default=paths.swift_dir / "codegen/schema.yml")
1514
Option("--dbscheme", tags=["dbscheme"], type=pathlib.Path, default=paths.swift_dir / "ql/lib/swift.dbscheme")
15+
Option("--ql-output", tags=["ql"], type=pathlib.Path, default=paths.swift_dir / "ql/lib/codeql/swift/generated")
16+
Option("--ql-stub-output", tags=["ql"], type=pathlib.Path, default=paths.swift_dir / "ql/lib/codeql/swift/elements")
17+
Option("--codeql-binary", tags=["ql"], default="codeql")
1618

1719

1820
_options = collections.defaultdict(list)

swift/codegen/lib/render.py

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
https://mustache.github.io/
66
"""
77

8-
import hashlib
98
import logging
109
import pathlib
1110

@@ -16,29 +15,13 @@
1615
log = logging.getLogger(__name__)
1716

1817

19-
def _md5(data):
20-
return hashlib.md5(data).digest()
21-
22-
2318
class Renderer:
2419
""" Template renderer using mustache templates in the `templates` directory """
2520

26-
def __init__(self, dryrun=False):
27-
""" Construct the renderer, which will not write anything if `dryrun` is `True` """
21+
def __init__(self):
2822
self.r = pystache.Renderer(search_dirs=str(paths.lib_dir / "templates"), escape=lambda u: u)
2923
self.generator = paths.exe_file.relative_to(paths.swift_dir)
30-
self.dryrun = dryrun
3124
self.written = set()
32-
self.skipped = set()
33-
self.erased = set()
34-
35-
@property
36-
def done_something(self):
37-
return bool(self.written or self.erased)
38-
39-
@property
40-
def rendered(self):
41-
return self.written | self.skipped
4225

4326
def render(self, data, output: pathlib.Path):
4427
""" Render `data` to `output`.
@@ -50,27 +33,14 @@ def render(self, data, output: pathlib.Path):
5033
mnemonic = type(data).__name__
5134
output.parent.mkdir(parents=True, exist_ok=True)
5235
data = self.r.render_name(data.template, data, generator=self.generator)
53-
if output.is_file():
54-
with open(output, "rb") as file:
55-
if _md5(data.encode()) == _md5(file.read()):
56-
log.debug(f"skipped {output.name}")
57-
self.skipped.add(output)
58-
return
59-
if self.dryrun:
60-
log.error(f"would have generated {mnemonic} {output.name}")
61-
else:
62-
with open(output, "w") as out:
63-
out.write(data)
64-
log.info(f"generated {mnemonic} {output.name}")
36+
with open(output, "w") as out:
37+
out.write(data)
38+
log.debug(f"generated {mnemonic} {output.name}")
6539
self.written.add(output)
6640

6741
def cleanup(self, existing):
6842
""" Remove files in `existing` for which no `render` has been called """
69-
for f in existing - self.written - self.skipped:
43+
for f in existing - self.written:
7044
if f.is_file():
71-
if self.dryrun:
72-
log.error(f"would have removed {f.name}")
73-
else:
74-
f.unlink()
75-
log.info(f"removed {f.name}")
76-
self.erased.add(f)
45+
f.unlink()
46+
log.info(f"removed {f.name}")
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// generated by {{generator}}
2+
{{#imports}}
3+
import {{.}}
4+
{{/imports}}
5+
6+
class {{name}}Base extends {{db_id}}{{#bases}}, {{.}}{{/bases}} {
7+
{{#root}}
8+
string toString() { none() } // overridden by subclasses
9+
10+
{{name}}Base getResolveStep() { none() } // overridden by subclasses
11+
12+
{{name}}Base resolve() {
13+
not exists(getResolveStep()) and result = this
14+
or
15+
result = getResolveStep().resolve()
16+
}
17+
{{/root}}
18+
{{#final}}
19+
override string toString() { result = "{{name}}" }
20+
{{/final}}
21+
{{#properties}}
22+
23+
{{#type_is_class}}
24+
{{type}} get{{singular}}({{#params}}{{^first}}, {{/first}}{{type}} {{param}}{{/params}}) {
25+
exists({{type}} {{local_var}} |
26+
{{tablename}}({{#tableparams}}{{^first}}, {{/first}}{{param}}{{/tableparams}})
27+
and
28+
result = {{local_var}}.resolve())
29+
}
30+
{{/type_is_class}}
31+
{{^type_is_class}}
32+
{{type}} get{{singular}}({{#params}}{{^first}}, {{/first}}{{type}} {{param}}{{/params}}) {
33+
{{tablename}}({{#tableparams}}{{^first}}, {{/first}}{{param}}{{/tableparams}})
34+
}
35+
{{/type_is_class}}
36+
{{#indefinite_article}}
37+
38+
{{type}} get{{.}}{{singular}}() {
39+
result = get{{singular}}({{#params}}{{^first}}, {{/first}}_{{/params}})
40+
}
41+
42+
int getNumberOf{{plural}}() {
43+
result = count(get{{.}}{{singular}}())
44+
}
45+
{{/indefinite_article}}
46+
{{/properties}}
47+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// generated by {{generator}}
2+
{{#imports}}
3+
import {{.}}
4+
{{/imports}}

0 commit comments

Comments
 (0)