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)
|
properties: List[Property] = field(default_factory=list)
|
||||||
group: str = ""
|
group: str = ""
|
||||||
pragmas: List[str] | Dict[str, object] = field(default_factory=dict)
|
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)
|
doc: List[str] = field(default_factory=list)
|
||||||
hideable: bool = False
|
hideable: bool = False
|
||||||
test_with: Optional[str] = None
|
test_with: Optional[str] = None
|
||||||
@@ -114,13 +112,21 @@ class Class:
|
|||||||
_check_type(d, known)
|
_check_type(d, known)
|
||||||
for p in self.properties:
|
for p in self.properties:
|
||||||
_check_type(p.type, known)
|
_check_type(p.type, known)
|
||||||
if self.synth is not None:
|
if "synth" in self.pragmas:
|
||||||
_check_type(self.synth.from_class, known)
|
synth = self.pragmas["synth"]
|
||||||
if self.synth.on_arguments is not None:
|
_check_type(synth.from_class, known)
|
||||||
for t in self.synth.on_arguments.values():
|
if synth.on_arguments is not None:
|
||||||
|
for t in synth.on_arguments.values():
|
||||||
_check_type(t, known)
|
_check_type(t, known)
|
||||||
_check_type(self.test_with, 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
|
@dataclass
|
||||||
class Schema:
|
class Schema:
|
||||||
|
|||||||
@@ -67,9 +67,9 @@ class _Namespace:
|
|||||||
""" simple namespacing mechanism """
|
""" simple namespacing mechanism """
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
def add(self, pragma: "_PragmaBase"):
|
def add(self, pragma: "_PragmaBase", key: str | None = None):
|
||||||
self.__dict__[pragma.pragma] = pragma
|
self.__dict__[pragma.pragma] = pragma
|
||||||
pragma.pragma = f"{self.name}_{pragma.pragma}"
|
pragma.pragma = key or f"{self.name}_{pragma.pragma}"
|
||||||
|
|
||||||
|
|
||||||
@_dataclass
|
@_dataclass
|
||||||
@@ -142,7 +142,7 @@ class _ParametrizedClassPragma(_PragmaBase):
|
|||||||
"""
|
"""
|
||||||
_pragma_class: _ClassVar[type] = _ClassPragma
|
_pragma_class: _ClassVar[type] = _ClassPragma
|
||||||
|
|
||||||
function: _Callable[[...], object] = None
|
function: _Callable[..., object] = None
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
self.__signature__ = _inspect.signature(self.function).replace(return_annotation=self._pragma_class)
|
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)
|
return _annotate(group=name)
|
||||||
|
|
||||||
|
|
||||||
synth.from_class = lambda ref: _annotate(synth=_schema.SynthInfo(
|
synth.add(_ParametrizedClassPragma("from_class", lambda ref: _schema.SynthInfo(
|
||||||
from_class=_schema.get_type_name(ref)))
|
from_class=_schema.get_type_name(ref))), key="synth")
|
||||||
synth.on_arguments = lambda **kwargs: _annotate(
|
synth.add(_ParametrizedClassPragma("on_arguments", lambda **kwargs:
|
||||||
synth=_schema.SynthInfo(on_arguments={k: _schema.get_type_name(t) for k, t in kwargs.items()}))
|
_schema.SynthInfo(on_arguments={k: _schema.get_type_name(t) for k, t in kwargs.items()})), key="synth")
|
||||||
|
|
||||||
|
|
||||||
class _PropertyModifierList(_schema.PropertyModifier):
|
class _PropertyModifierList(_schema.PropertyModifier):
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ def _get_class(cls: type) -> schema.Class:
|
|||||||
test_with=_get_name(getattr(cls, "_test_with", None)),
|
test_with=_get_name(getattr(cls, "_test_with", None)),
|
||||||
# in the following we don't use `getattr` to avoid inheriting
|
# in the following we don't use `getattr` to avoid inheriting
|
||||||
pragmas=cls.__dict__.get("_pragmas", {}),
|
pragmas=cls.__dict__.get("_pragmas", {}),
|
||||||
synth=cls.__dict__.get("_synth", None),
|
|
||||||
properties=[
|
properties=[
|
||||||
a | _PropertyNamer(n)
|
a | _PropertyNamer(n)
|
||||||
for n, a in cls.__dict__.get("__annotations__", {}).items()
|
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)
|
fill_is_synth(root)
|
||||||
|
|
||||||
for name, cls in classes.items():
|
for name, cls in classes.items():
|
||||||
if cls.synth is None and is_synth[name]:
|
if is_synth[name]:
|
||||||
cls.synth = True
|
cls.mark_synth()
|
||||||
|
|
||||||
|
|
||||||
def _fill_hideable_information(classes: typing.Dict[str, schema.Class]):
|
def _fill_hideable_information(classes: typing.Dict[str, schema.Class]):
|
||||||
|
|||||||
@@ -185,15 +185,15 @@ def test_synth_classes_ignored(generate):
|
|||||||
assert generate([
|
assert generate([
|
||||||
schema.Class(
|
schema.Class(
|
||||||
name="W",
|
name="W",
|
||||||
synth=schema.SynthInfo(),
|
pragmas={"synth": schema.SynthInfo()},
|
||||||
),
|
),
|
||||||
schema.Class(
|
schema.Class(
|
||||||
name="X",
|
name="X",
|
||||||
synth=schema.SynthInfo(from_class="A"),
|
pragmas={"synth": schema.SynthInfo(from_class="A")},
|
||||||
),
|
),
|
||||||
schema.Class(
|
schema.Class(
|
||||||
name="Y",
|
name="Y",
|
||||||
synth=schema.SynthInfo(on_arguments={"a": "A", "b": "int"}),
|
pragmas={"synth": schema.SynthInfo(on_arguments={"a": "A", "b": "int"})},
|
||||||
),
|
),
|
||||||
schema.Class(
|
schema.Class(
|
||||||
name="Z",
|
name="Z",
|
||||||
|
|||||||
@@ -536,9 +536,9 @@ def test_null_class(generate):
|
|||||||
|
|
||||||
def test_synth_classes_ignored(generate):
|
def test_synth_classes_ignored(generate):
|
||||||
assert generate([
|
assert generate([
|
||||||
schema.Class(name="A", synth=schema.SynthInfo()),
|
schema.Class(name="A", pragmas={"synth": schema.SynthInfo()}),
|
||||||
schema.Class(name="B", synth=schema.SynthInfo(from_class="A")),
|
schema.Class(name="B", pragmas={"synth": schema.SynthInfo(from_class="A")}),
|
||||||
schema.Class(name="C", synth=schema.SynthInfo(on_arguments={"x": "A"})),
|
schema.Class(name="C", pragmas={"synth": schema.SynthInfo(on_arguments={"x": "A"})}),
|
||||||
]) == dbscheme.Scheme(
|
]) == dbscheme.Scheme(
|
||||||
src=schema_file.name,
|
src=schema_file.name,
|
||||||
includes=[],
|
includes=[],
|
||||||
@@ -549,7 +549,7 @@ def test_synth_classes_ignored(generate):
|
|||||||
def test_synth_derived_classes_ignored(generate):
|
def test_synth_derived_classes_ignored(generate):
|
||||||
assert generate([
|
assert generate([
|
||||||
schema.Class(name="A", derived={"B", "C"}),
|
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"]),
|
schema.Class(name="C", bases=["A"]),
|
||||||
]) == dbscheme.Scheme(
|
]) == dbscheme.Scheme(
|
||||||
src=schema_file.name,
|
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):
|
def test_stub_on_class_with_synth_from_class(generate_classes):
|
||||||
assert 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")]),
|
properties=[schema.SingleProperty("foo", "bar")]),
|
||||||
]) == {
|
]) == {
|
||||||
"MyObject.qll": (a_ql_class_public(name="MyObject"), a_ql_stub(name="MyObject", synth_accessors=[
|
"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):
|
def test_stub_on_class_with_synth_on_arguments(generate_classes):
|
||||||
assert 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")]),
|
properties=[schema.SingleProperty("foo", "bar")]),
|
||||||
]) == {
|
]) == {
|
||||||
"MyObject.qll": (a_ql_class_public(name="MyObject"), a_ql_stub(name="MyObject", synth_accessors=[
|
"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
|
pass
|
||||||
|
|
||||||
assert data.classes == {
|
assert data.classes == {
|
||||||
'A': schema.Class('A', derived={'B'}, synth=True),
|
'A': schema.Class('A', derived={'B'}, pragmas={"synth": True}),
|
||||||
'B': schema.Class('B', bases=['A'], synth=schema.SynthInfo(from_class="A")),
|
'B': schema.Class('B', bases=['A'], pragmas={"synth": schema.SynthInfo(from_class="A")}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -371,7 +371,7 @@ def test_synth_from_class_ref():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
assert data.classes == {
|
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']),
|
'B': schema.Class('B', bases=['A']),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,8 +396,8 @@ def test_synth_class_on():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
assert data.classes == {
|
assert data.classes == {
|
||||||
'A': schema.Class('A', derived={'B'}, synth=True),
|
'A': schema.Class('A', derived={'B'}, pragmas={"synth": True}),
|
||||||
'B': schema.Class('B', bases=['A'], synth=schema.SynthInfo(on_arguments={'a': 'A', 'i': 'int'})),
|
'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
|
pass
|
||||||
|
|
||||||
assert data.classes == {
|
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']),
|
'B': schema.Class('B', bases=['A']),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,10 +454,10 @@ def test_synth_class_hierarchy():
|
|||||||
|
|
||||||
assert data.classes == {
|
assert data.classes == {
|
||||||
'Root': schema.Class('Root', derived={'Base', 'C'}),
|
'Root': schema.Class('Root', derived={'Base', 'C'}),
|
||||||
'Base': schema.Class('Base', bases=['Root'], derived={'Intermediate', 'B'}, synth=True),
|
'Base': schema.Class('Base', bases=['Root'], derived={'Intermediate', 'B'}, pragmas={"synth": True}),
|
||||||
'Intermediate': schema.Class('Intermediate', bases=['Base'], derived={'A'}, synth=True),
|
'Intermediate': schema.Class('Intermediate', bases=['Base'], derived={'A'}, pragmas={"synth": True}),
|
||||||
'A': schema.Class('A', bases=['Intermediate'], synth=schema.SynthInfo(on_arguments={'a': 'Base', 'i': 'int'})),
|
'A': schema.Class('A', bases=['Intermediate'], pragmas={"synth": schema.SynthInfo(on_arguments={'a': 'Base', 'i': 'int'})}),
|
||||||
'B': schema.Class('B', bases=['Base'], synth=schema.SynthInfo(from_class='Base')),
|
'B': schema.Class('B', bases=['Base'], pragmas={"synth": schema.SynthInfo(from_class='Base')}),
|
||||||
'C': schema.Class('C', bases=['Root']),
|
'C': schema.Class('C', bases=['Root']),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user