Skip to content

Commit 281985b

Browse files
author
Dave Bartolomeo
committed
C++: Sync Opcode.qll QLDoc with Instruction.qll QLDoc
For every concrete `Opcode`, there is a corresponding `Instruction` class. Rather than duplicate all of the QLDoc by hand, I wrote a quick Python script to copy the QLDoc from `Instruction.qll` to `Opcode.qll`. I don't expect that we will need to do this often, so I'm not hooking it up to a PR check or anything like that, but I did commit the script itself in case we need it again.
1 parent 023e1dc commit 281985b

File tree

3 files changed

+629
-0
lines changed

3 files changed

+629
-0
lines changed

config/opcode-qldoc.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/env python3
2+
3+
import os
4+
import re
5+
path = os.path
6+
7+
start_qldoc_re = re.compile(r'^\s*/\*\*') # Start of a QLDoc comment
8+
end_qldoc_re = re.compile(r'\*/\s*$') # End of a QLDoc comment
9+
blank_qldoc_line_re = re.compile(r'^\s*\*\s*$') # A line in a QLDoc comment with only the '*'
10+
instruction_class_re = re.compile(r'^class (?P<name>[A-aa-z0-9]+)Instruction\s') # Declaration of an `Instruction` class
11+
opcode_class_re = re.compile(r'^\s*class (?P<name>[A-aa-z0-9]+)\s') # Declaration of an `Opcode` class
12+
13+
script_dir = path.realpath(path.dirname(__file__))
14+
instruction_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll'))
15+
opcode_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll'))
16+
17+
# Scan `Instruction.qll`, keeping track of the QLDoc comment attached to each declaration of a class
18+
# whose name ends with `Instruction`.
19+
instruction_comments = {}
20+
in_qldoc = False
21+
saw_blank_line_in_qldoc = False
22+
qldoc_lines = []
23+
with open(instruction_path, 'r', encoding='utf-8') as instr:
24+
for line in instr:
25+
if in_qldoc:
26+
if end_qldoc_re.search(line):
27+
qldoc_lines.append(line)
28+
in_qldoc = False
29+
elif blank_qldoc_line_re.search(line):
30+
# We're going to skip any lines after the first blank line, to avoid duplicating all
31+
# of the verbose description.
32+
saw_blank_line_in_qldoc = True
33+
elif not saw_blank_line_in_qldoc:
34+
qldoc_lines.append(line)
35+
else:
36+
if start_qldoc_re.search(line):
37+
# Starting a new QLDoc comment.
38+
saw_blank_line_in_qldoc = False
39+
qldoc_lines.append(line)
40+
if not end_qldoc_re.search(line):
41+
in_qldoc = True
42+
else:
43+
instruction_match = instruction_class_re.search(line)
44+
if instruction_match:
45+
# Found the declaration of an `Instruction` class. Record the QLDoc comments.
46+
instruction_comments[instruction_match.group('name')] = qldoc_lines
47+
qldoc_lines = []
48+
49+
# Scan `Opcode.qll`. Whenever we see the declaration of an `Opcode` class for which we have a
50+
# corresponding `Instruction` class, we'll attach a copy of the `Instruction`'s QLDoc comment.
51+
in_qldoc = False
52+
qldoc_lines = []
53+
output_lines = []
54+
with open(opcode_path, 'r', encoding='utf-8') as opcode:
55+
for line in opcode:
56+
if in_qldoc:
57+
qldoc_lines.append(line)
58+
if end_qldoc_re.search(line):
59+
in_qldoc = False
60+
else:
61+
if start_qldoc_re.search(line):
62+
qldoc_lines.append(line)
63+
if not end_qldoc_re.search(line):
64+
in_qldoc = True
65+
else:
66+
opcode_match = opcode_class_re.search(line)
67+
if opcode_match:
68+
# Found an `Opcode` that matches a known `Instruction`. Replace the QLDoc with
69+
# a copy of the one from the `Instruction`.
70+
name = opcode_match.group('name')
71+
if instruction_comments.get(name):
72+
# Indent by two additional spaces, since opcodes are declared in the
73+
# `Opcode` module.
74+
# Rename `instruction` to `operation`.
75+
qldoc_lines = [(' ' + qldoc_line.replace(' An instruction ', ' An operation '))
76+
for qldoc_line in instruction_comments[name]]
77+
output_lines.extend(qldoc_lines)
78+
qldoc_lines = []
79+
output_lines.append(line)
80+
81+
# Write out the updated `Opcode.qll`
82+
with open(opcode_path, 'w', encoding='utf-8') as opcode:
83+
opcode.writelines(output_lines)

0 commit comments

Comments
 (0)