mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Codegen: move class synth decorators to pragmas
This commit is contained in:
@@ -93,8 +93,6 @@ class Class:
|
||||
properties: List[Property] = field(default_factory=list)
|
||||
group: str = ""
|
||||
pragmas: List[str] | Dict[str, object] = field(default_factory=dict)
|
||||
synth: Optional[Union[SynthInfo, bool]] = None
|
||||
"""^^^ filled with `True` for non-final classes with only synthesized final descendants """
|
||||
doc: List[str] = field(default_factory=list)
|
||||
hideable: bool = False
|
||||
test_with: Optional[str] = None
|
||||
@@ -114,13 +112,21 @@ class Class:
|
||||
_check_type(d, known)
|
||||
for p in self.properties:
|
||||
_check_type(p.type, known)
|
||||
if self.synth is not None:
|
||||
_check_type(self.synth.from_class, known)
|
||||
if self.synth.on_arguments is not None:
|
||||
for t in self.synth.on_arguments.values():
|
||||
if "synth" in self.pragmas:
|
||||
synth = self.pragmas["synth"]
|
||||
_check_type(synth.from_class, known)
|
||||
if synth.on_arguments is not None:
|
||||
for t in synth.on_arguments.values():
|
||||
_check_type(t, known)
|
||||
_check_type(self.test_with, known)
|
||||
|
||||
@property
|
||||
def synth(self) -> SynthInfo | bool | None:
|
||||
return self.pragmas.get("synth")
|
||||
|
||||
def mark_synth(self):
|
||||
self.pragmas.setdefault("synth", True)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Schema:
|
||||
|
||||
@@ -67,9 +67,9 @@ class _Namespace:
|
||||
""" simple namespacing mechanism """
|
||||
name: str
|
||||
|
||||
def add(self, pragma: "_PragmaBase"):
|
||||
def add(self, pragma: "_PragmaBase", key: str | None = None):
|
||||
self.__dict__[pragma.pragma] = pragma
|
||||
pragma.pragma = f"{self.name}_{pragma.pragma}"
|
||||
pragma.pragma = key or f"{self.name}_{pragma.pragma}"
|
||||
|
||||
|
||||
@_dataclass
|
||||
@@ -142,7 +142,7 @@ class _ParametrizedClassPragma(_PragmaBase):
|
||||
"""
|
||||
_pragma_class: _ClassVar[type] = _ClassPragma
|
||||
|
||||
function: _Callable[[...], object] = None
|
||||
function: _Callable[..., object] = None
|
||||
|
||||
def __post_init__(self):
|
||||
self.__signature__ = _inspect.signature(self.function).replace(return_annotation=self._pragma_class)
|
||||
@@ -248,10 +248,10 @@ def group(name: str = "") -> _ClassDecorator:
|
||||
return _annotate(group=name)
|
||||
|
||||
|
||||
synth.from_class = lambda ref: _annotate(synth=_schema.SynthInfo(
|
||||
from_class=_schema.get_type_name(ref)))
|
||||
synth.on_arguments = lambda **kwargs: _annotate(
|
||||
synth=_schema.SynthInfo(on_arguments={k: _schema.get_type_name(t) for k, t in kwargs.items()}))
|
||||
synth.add(_ParametrizedClassPragma("from_class", lambda ref: _schema.SynthInfo(
|
||||
from_class=_schema.get_type_name(ref))), key="synth")
|
||||
synth.add(_ParametrizedClassPragma("on_arguments", lambda **kwargs:
|
||||
_schema.SynthInfo(on_arguments={k: _schema.get_type_name(t) for k, t in kwargs.items()})), key="synth")
|
||||
|
||||
|
||||
class _PropertyModifierList(_schema.PropertyModifier):
|
||||
|
||||
@@ -50,7 +50,6 @@ def _get_class(cls: type) -> schema.Class:
|
||||
test_with=_get_name(getattr(cls, "_test_with", None)),
|
||||
# in the following we don't use `getattr` to avoid inheriting
|
||||
pragmas=cls.__dict__.get("_pragmas", {}),
|
||||
synth=cls.__dict__.get("_synth", None),
|
||||
properties=[
|
||||
a | _PropertyNamer(n)
|
||||
for n, a in cls.__dict__.get("__annotations__", {}).items()
|
||||
@@ -100,8 +99,8 @@ def _fill_synth_information(classes: typing.Dict[str, schema.Class]):
|
||||
fill_is_synth(root)
|
||||
|
||||
for name, cls in classes.items():
|
||||
if cls.synth is None and is_synth[name]:
|
||||
cls.synth = True
|
||||
if is_synth[name]:
|
||||
cls.mark_synth()
|
||||
|
||||
|
||||
def _fill_hideable_information(classes: typing.Dict[str, schema.Class]):
|
||||
|
||||
@@ -185,15 +185,15 @@ def test_synth_classes_ignored(generate):
|
||||
assert generate([
|
||||
schema.Class(
|
||||
name="W",
|
||||
synth=schema.SynthInfo(),
|
||||
pragmas={"synth": schema.SynthInfo()},
|
||||
),
|
||||
schema.Class(
|
||||
name="X",
|
||||
synth=schema.SynthInfo(from_class="A"),
|
||||
pragmas={"synth": schema.SynthInfo(from_class="A")},
|
||||
),
|
||||
schema.Class(
|
||||
name="Y",
|
||||
synth=schema.SynthInfo(on_arguments={"a": "A", "b": "int"}),
|
||||
pragmas={"synth": schema.SynthInfo(on_arguments={"a": "A", "b": "int"})},
|
||||
),
|
||||
schema.Class(
|
||||
name="Z",
|
||||
|
||||
@@ -536,9 +536,9 @@ def test_null_class(generate):
|
||||
|
||||
def test_synth_classes_ignored(generate):
|
||||
assert generate([
|
||||
schema.Class(name="A", synth=schema.SynthInfo()),
|
||||
schema.Class(name="B", synth=schema.SynthInfo(from_class="A")),
|
||||
schema.Class(name="C", synth=schema.SynthInfo(on_arguments={"x": "A"})),
|
||||
schema.Class(name="A", pragmas={"synth": schema.SynthInfo()}),
|
||||
schema.Class(name="B", pragmas={"synth": schema.SynthInfo(from_class="A")}),
|
||||
schema.Class(name="C", pragmas={"synth": schema.SynthInfo(on_arguments={"x": "A"})}),
|
||||
]) == dbscheme.Scheme(
|
||||
src=schema_file.name,
|
||||
includes=[],
|
||||
@@ -549,7 +549,7 @@ def test_synth_classes_ignored(generate):
|
||||
def test_synth_derived_classes_ignored(generate):
|
||||
assert generate([
|
||||
schema.Class(name="A", derived={"B", "C"}),
|
||||
schema.Class(name="B", bases=["A"], synth=schema.SynthInfo()),
|
||||
schema.Class(name="B", bases=["A"], pragmas={"synth": schema.SynthInfo()}),
|
||||
schema.Class(name="C", bases=["A"]),
|
||||
]) == dbscheme.Scheme(
|
||||
src=schema_file.name,
|
||||
|
||||
@@ -937,7 +937,7 @@ def test_property_on_class_with_default_doc_name(generate_classes):
|
||||
|
||||
def test_stub_on_class_with_synth_from_class(generate_classes):
|
||||
assert generate_classes([
|
||||
schema.Class("MyObject", synth=schema.SynthInfo(from_class="A"),
|
||||
schema.Class("MyObject", pragmas={"synth": schema.SynthInfo(from_class="A")},
|
||||
properties=[schema.SingleProperty("foo", "bar")]),
|
||||
]) == {
|
||||
"MyObject.qll": (a_ql_class_public(name="MyObject"), a_ql_stub(name="MyObject", synth_accessors=[
|
||||
@@ -952,7 +952,7 @@ def test_stub_on_class_with_synth_from_class(generate_classes):
|
||||
|
||||
def test_stub_on_class_with_synth_on_arguments(generate_classes):
|
||||
assert generate_classes([
|
||||
schema.Class("MyObject", synth=schema.SynthInfo(on_arguments={"base": "A", "index": "int", "label": "string"}),
|
||||
schema.Class("MyObject", pragmas={"synth": schema.SynthInfo(on_arguments={"base": "A", "index": "int", "label": "string"})},
|
||||
properties=[schema.SingleProperty("foo", "bar")]),
|
||||
]) == {
|
||||
"MyObject.qll": (a_ql_class_public(name="MyObject"), a_ql_stub(name="MyObject", synth_accessors=[
|
||||
|
||||
@@ -355,8 +355,8 @@ def test_synth_from_class():
|
||||
pass
|
||||
|
||||
assert data.classes == {
|
||||
'A': schema.Class('A', derived={'B'}, synth=True),
|
||||
'B': schema.Class('B', bases=['A'], synth=schema.SynthInfo(from_class="A")),
|
||||
'A': schema.Class('A', derived={'B'}, pragmas={"synth": True}),
|
||||
'B': schema.Class('B', bases=['A'], pragmas={"synth": schema.SynthInfo(from_class="A")}),
|
||||
}
|
||||
|
||||
|
||||
@@ -371,7 +371,7 @@ def test_synth_from_class_ref():
|
||||
pass
|
||||
|
||||
assert data.classes == {
|
||||
'A': schema.Class('A', derived={'B'}, synth=schema.SynthInfo(from_class="B")),
|
||||
'A': schema.Class('A', derived={'B'}, pragmas={"synth": schema.SynthInfo(from_class="B")}),
|
||||
'B': schema.Class('B', bases=['A']),
|
||||
}
|
||||
|
||||
@@ -396,8 +396,8 @@ def test_synth_class_on():
|
||||
pass
|
||||
|
||||
assert data.classes == {
|
||||
'A': schema.Class('A', derived={'B'}, synth=True),
|
||||
'B': schema.Class('B', bases=['A'], synth=schema.SynthInfo(on_arguments={'a': 'A', 'i': 'int'})),
|
||||
'A': schema.Class('A', derived={'B'}, pragmas={"synth": True}),
|
||||
'B': schema.Class('B', bases=['A'], pragmas={"synth": schema.SynthInfo(on_arguments={'a': 'A', 'i': 'int'})}),
|
||||
}
|
||||
|
||||
|
||||
@@ -415,7 +415,7 @@ def test_synth_class_on_ref():
|
||||
pass
|
||||
|
||||
assert data.classes == {
|
||||
'A': schema.Class('A', derived={'B'}, synth=schema.SynthInfo(on_arguments={'b': 'B', 'i': 'int'})),
|
||||
'A': schema.Class('A', derived={'B'}, pragmas={"synth": schema.SynthInfo(on_arguments={'b': 'B', 'i': 'int'})}),
|
||||
'B': schema.Class('B', bases=['A']),
|
||||
}
|
||||
|
||||
@@ -454,10 +454,10 @@ def test_synth_class_hierarchy():
|
||||
|
||||
assert data.classes == {
|
||||
'Root': schema.Class('Root', derived={'Base', 'C'}),
|
||||
'Base': schema.Class('Base', bases=['Root'], derived={'Intermediate', 'B'}, synth=True),
|
||||
'Intermediate': schema.Class('Intermediate', bases=['Base'], derived={'A'}, synth=True),
|
||||
'A': schema.Class('A', bases=['Intermediate'], synth=schema.SynthInfo(on_arguments={'a': 'Base', 'i': 'int'})),
|
||||
'B': schema.Class('B', bases=['Base'], synth=schema.SynthInfo(from_class='Base')),
|
||||
'Base': schema.Class('Base', bases=['Root'], derived={'Intermediate', 'B'}, pragmas={"synth": True}),
|
||||
'Intermediate': schema.Class('Intermediate', bases=['Base'], derived={'A'}, pragmas={"synth": True}),
|
||||
'A': schema.Class('A', bases=['Intermediate'], pragmas={"synth": schema.SynthInfo(on_arguments={'a': 'Base', 'i': 'int'})}),
|
||||
'B': schema.Class('B', bases=['Base'], pragmas={"synth": schema.SynthInfo(from_class='Base')}),
|
||||
'C': schema.Class('C', bases=['Root']),
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user