Skip to content

Commit 30161b0

Browse files
committed
Codegen: patch customized stubs with QLdoc
1 parent d659709 commit 30161b0

Some content is hidden

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

41 files changed

+292
-30
lines changed

misc/codegen/generators/qlgen.py

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,43 @@ def _get_stub(cls: schema.Class, base_import: str, generated_import_prefix: str)
312312
else:
313313
accessors = []
314314
return ql.Stub(name=cls.name, base_import=base_import, import_prefix=generated_import_prefix,
315-
synth_accessors=accessors, ql_internal="ql_internal" in cls.pragmas)
315+
doc=cls.doc, synth_accessors=accessors,
316+
ql_internal="ql_internal" in cls.pragmas)
317+
318+
319+
def _patch_class_qldocs(cls: str, qldoc: str, stub_file: pathlib.Path):
320+
if not qldoc or not stub_file.exists():
321+
return
322+
qldoc = "\n".join(l.rstrip() for l in qldoc.splitlines())
323+
tmp = stub_file.with_suffix(f'{stub_file.suffix}.bkp')
324+
header = "// the following QLdoc is generated: if you need to edit it, do it in the schema file\n"
325+
with open(stub_file) as input:
326+
qldoc_start = None
327+
qldoc_end = None
328+
class_start = None
329+
for lineno, line in enumerate(input, 1):
330+
if line == header:
331+
qldoc_start = lineno
332+
if line.startswith("/**") and lineno - 1 != qldoc_start:
333+
qldoc_start = lineno
334+
if line.endswith(" */\n"):
335+
qldoc_end = lineno + 1
336+
elif line.startswith(f"class {cls}"):
337+
class_start = lineno
338+
break
339+
assert class_start, stub_file
340+
assert bool(qldoc_start) == bool(qldoc_end), stub_file
341+
if not qldoc_start or qldoc_end != class_start:
342+
qldoc_start = class_start
343+
input.seek(0)
344+
with open(tmp, 'w') as output:
345+
for lineno, line in enumerate(input, 1):
346+
if lineno == qldoc_start:
347+
print(header, end='', file=output)
348+
print(qldoc, file=output)
349+
if lineno < qldoc_start or lineno >= class_start:
350+
print(line, end='', file=output)
351+
tmp.rename(stub_file)
316352

317353

318354
def generate(opts, renderer):
@@ -362,9 +398,13 @@ def generate(opts, renderer):
362398
for c in data.classes.values():
363399
path = _get_path(c)
364400
stub_file = stub_out / path
401+
base_import = get_import(out / path, opts.root_dir)
402+
stub = _get_stub(c, base_import, generated_import_prefix)
365403
if not renderer.is_customized_stub(stub_file):
366-
base_import = get_import(out / path, opts.root_dir)
367-
renderer.render(_get_stub(c, base_import, generated_import_prefix), stub_file)
404+
renderer.render(stub, stub_file)
405+
else:
406+
qldoc = renderer.render_str(stub, template='ql_stub_class_qldoc')
407+
_patch_class_qldocs(c.name, qldoc, stub_file)
368408

369409
# for example path/to/elements -> path/to/elements.qll
370410
renderer.render(ql.ImportList([i for name, i in imports.items() if not classes[name].ql_internal]),

misc/codegen/lib/ql.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,16 @@ class Stub:
167167
import_prefix: str
168168
synth_accessors: List[SynthUnderlyingAccessor] = field(default_factory=list)
169169
ql_internal: bool = False
170+
doc: List[str] = field(default_factory=list)
170171

171172
@property
172173
def has_synth_accessors(self) -> bool:
173174
return bool(self.synth_accessors)
174175

176+
@property
177+
def has_doc(self) -> bool:
178+
return bool(self.doc) or self.ql_internal
179+
175180

176181
@dataclass
177182
class DbClasses:

misc/codegen/test/test_qlgen.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ def test_class_with_doc(generate_classes):
414414
assert generate_classes([
415415
schema.Class("A", doc=doc),
416416
]) == {
417-
"A.qll": (a_ql_stub(name="A"), a_ql_class(name="A", final=True, doc=doc)),
417+
"A.qll": (a_ql_stub(name="A", doc=doc), a_ql_class(name="A", final=True, doc=doc)),
418418
}
419419

420420

swift/ql/.generated.list

Lines changed: 25 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

swift/ql/lib/codeql/swift/elements/AvailabilityInfo.qll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
private import codeql.swift.generated.AvailabilityInfo
22

3+
// the following QLdoc is generated: if you need to edit it, do it in the schema file
4+
/**
5+
* An availability condition of an `if`, `while`, or `guard` statements.
6+
*
7+
* Examples:
8+
* ```
9+
* if #available(iOS 12, *) {
10+
* // Runs on iOS 12 and above
11+
* } else {
12+
* // Runs only anything below iOS 12
13+
* }
14+
* if #unavailable(macOS 10.14, *) {
15+
* // Runs only on macOS 10 and below
16+
* }
17+
* ```
18+
*/
319
class AvailabilityInfo extends Generated::AvailabilityInfo {
420
override string toString() {
521
result = "#available" and not this.isUnavailable()

swift/ql/lib/codeql/swift/elements/AvailabilitySpec.qll

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

swift/ql/lib/codeql/swift/elements/ErrorElement.qll

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

swift/ql/lib/codeql/swift/elements/KeyPathComponent.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
private import codeql.swift.generated.KeyPathComponent
22
private import swift
33

4+
// the following QLdoc is generated: if you need to edit it, do it in the schema file
5+
/**
6+
* A component of a `KeyPathExpr`.
7+
*/
48
class KeyPathComponent extends Generated::KeyPathComponent {
59
/**
610
* Property access like `.bar` in `\Foo.bar`.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
private import codeql.swift.generated.OtherAvailabilitySpec
22

3+
// the following QLdoc is generated: if you need to edit it, do it in the schema file
4+
/**
5+
* A wildcard availability spec `*`
6+
*/
37
class OtherAvailabilitySpec extends Generated::OtherAvailabilitySpec {
48
override string toString() { result = "*" }
59
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
private import codeql.swift.generated.PlatformVersionAvailabilitySpec
22

3+
// the following QLdoc is generated: if you need to edit it, do it in the schema file
4+
/**
5+
* An availability spec based on platform and version, for example `macOS 12` or `watchOS 14`
6+
*/
37
class PlatformVersionAvailabilitySpec extends Generated::PlatformVersionAvailabilitySpec {
48
override string toString() { result = this.getPlatform() + " " + this.getVersion() }
59
}

0 commit comments

Comments
 (0)