Swift: add structured C++ generated classes

This adds `cppgen`, creating structured C++ classes mirroring QL classes
out of `schema.yml`.

An example of generated code at the time of this commit can be found
[in this gist][1].

[1]: https://gist.github.com/redsun82/57304ddb487a8aa40eaa0caa695048fa

Closes https://github.com/github/codeql-c-team/issues/863
This commit is contained in:
Paolo Tranquilli
2022-05-04 18:13:54 +02:00
parent 10c5c8e71f
commit d5d1eb717d
21 changed files with 445 additions and 60 deletions

View File

@@ -1,3 +1,4 @@
import re
from dataclasses import dataclass, field
from typing import List, ClassVar
@@ -14,13 +15,35 @@ cpp_keywords = {"alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", "
"typeid", "typename", "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while",
"xor", "xor_eq"}
_field_overrides = [
(re.compile(r"(start|end)_(line|column)|index|num_.*"), {"type": "unsigned"}),
(re.compile(r"(.*)_"), lambda m: {"name": m[1]}),
]
def get_field_override(field: str):
for r, o in _field_overrides:
m = r.fullmatch(field)
if m:
return o(m) if callable(o) else o
return {}
@dataclass
class Field:
name: str
type: str
is_optional: bool = False
is_repeated: bool = False
trap_name: str = None
first: bool = False
def __post_init__(self):
if self.is_optional:
self.type = f"std::optional<{self.type}>"
elif self.is_repeated:
self.type = f"std::vector<{self.type}>"
@property
def cpp_name(self):
if self.name in cpp_keywords:
@@ -36,6 +59,12 @@ class Field:
else:
return lambda x: x
@property
def is_single(self):
return not (self.is_optional or self.is_repeated)
@dataclass
class Trap:
@@ -74,13 +103,48 @@ class Tag:
@dataclass
class TrapList:
template: ClassVar = 'cpp_traps'
template: ClassVar = 'trap_traps'
traps: List[Trap] = field(default_factory=list)
@dataclass
class TagList:
template: ClassVar = 'cpp_tags'
template: ClassVar = 'trap_tags'
tags: List[Tag] = field(default_factory=list)
@dataclass
class ClassBase:
ref: 'Class'
first: bool = False
@dataclass
class Class:
name: str
bases: List[ClassBase] = field(default_factory=list)
final: bool = False
fields: List[Field] = field(default_factory=list)
trap_name: str = None
def __post_init__(self):
self.bases = [ClassBase(c) for c in sorted(self.bases, key=lambda cls: cls.name)]
if self.bases:
self.bases[0].first = True
@property
def has_bases(self):
return bool(self.bases)
@property
def single_fields(self):
return [f for f in self.fields if f.is_single]
@dataclass
class ClassList:
template: ClassVar = "cpp_classes"
classes: List[Class]