Merge pull request #19063 from github/redsun82/codegen-rename-dbscheme

Codegen: add `ql.db_table_name` property pragma
This commit is contained in:
Paolo Tranquilli
2025-03-31 12:01:35 +02:00
committed by GitHub
37 changed files with 347 additions and 140 deletions

View File

@@ -37,5 +37,6 @@ build --java_language_version=17
build --tool_java_language_version=17 build --tool_java_language_version=17
build --tool_java_runtime_version=remotejdk_17 build --tool_java_runtime_version=remotejdk_17
build --java_runtime_version=remotejdk_17 build --java_runtime_version=remotejdk_17
build --@rules_python//python/config_settings:python_version=3.12
try-import %workspace%/local.bazelrc try-import %workspace%/local.bazelrc

View File

@@ -8,3 +8,5 @@ common --registry=https://bcr.bazel.build
# its implementation packages without providing any code itself. # its implementation packages without providing any code itself.
# We either can depend on internal implementation details, or turn of strict deps. # We either can depend on internal implementation details, or turn of strict deps.
common --@rules_dotnet//dotnet/settings:strict_deps=false common --@rules_dotnet//dotnet/settings:strict_deps=false
build --@rules_python//python/config_settings:python_version=3.12

View File

@@ -155,7 +155,7 @@ use_repo(csharp_main_extension, "paket.main")
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
pip.parse( pip.parse(
hub_name = "codegen_deps", hub_name = "codegen_deps",
python_version = "3.11", python_version = "3.12",
requirements_lock = "//misc/codegen:requirements_lock.txt", requirements_lock = "//misc/codegen:requirements_lock.txt",
) )
use_repo(pip, "codegen_deps") use_repo(pip, "codegen_deps")

View File

@@ -1 +1 @@
3.11 3.12

View File

@@ -37,12 +37,19 @@ def _get_type(t: str, add_or_none_except: typing.Optional[str] = None) -> str:
return t return t
def _get_trap_name(cls: schema.Class, p: schema.Property) -> str | None:
if p.is_single:
return None
overridden_trap_name = p.pragmas.get("ql_db_table_name")
if overridden_trap_name:
return inflection.camelize(overridden_trap_name)
trap_name = inflection.camelize(f"{cls.name}_{p.name}")
if p.is_predicate:
return trap_name
return inflection.pluralize(trap_name)
def _get_field(cls: schema.Class, p: schema.Property, add_or_none_except: typing.Optional[str] = None) -> cpp.Field: def _get_field(cls: schema.Class, p: schema.Property, add_or_none_except: typing.Optional[str] = None) -> cpp.Field:
trap_name = None
if not p.is_single:
trap_name = inflection.camelize(f"{cls.name}_{p.name}")
if not p.is_predicate:
trap_name = inflection.pluralize(trap_name)
args = dict( args = dict(
field_name=p.name + ("_" if p.name in cpp.cpp_keywords else ""), field_name=p.name + ("_" if p.name in cpp.cpp_keywords else ""),
base_type=_get_type(p.type, add_or_none_except), base_type=_get_type(p.type, add_or_none_except),
@@ -50,7 +57,7 @@ def _get_field(cls: schema.Class, p: schema.Property, add_or_none_except: typing
is_repeated=p.is_repeated, is_repeated=p.is_repeated,
is_predicate=p.is_predicate, is_predicate=p.is_predicate,
is_unordered=p.is_unordered, is_unordered=p.is_unordered,
trap_name=trap_name, trap_name=_get_trap_name(cls, p),
) )
args.update(cpp.get_field_override(p.name)) args.update(cpp.get_field_override(p.name))
return cpp.Field(**args) return cpp.Field(**args)

View File

@@ -24,6 +24,10 @@ from misc.codegen.lib.dbscheme import *
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class Error(Exception):
pass
def dbtype(typename: str, add_or_none_except: typing.Optional[str] = None) -> str: def dbtype(typename: str, add_or_none_except: typing.Optional[str] = None) -> str:
""" translate a type to a dbscheme counterpart, using `@lower_underscore` format for classes. """ translate a type to a dbscheme counterpart, using `@lower_underscore` format for classes.
For class types, appends an underscore followed by `null` if provided For class types, appends an underscore followed by `null` if provided
@@ -65,11 +69,12 @@ def cls_to_dbscheme(cls: schema.Class, lookup: typing.Dict[str, schema.Class], a
) )
# use property-specific tables for 1-to-many and 1-to-at-most-1 properties # use property-specific tables for 1-to-many and 1-to-at-most-1 properties
for f in cls.properties: for f in cls.properties:
overridden_table_name = f.pragmas.get("ql_db_table_name")
if f.synth: if f.synth:
continue continue
if f.is_unordered: if f.is_unordered:
yield Table( yield Table(
name=inflection.tableize(f"{cls.name}_{f.name}"), name=overridden_table_name or inflection.tableize(f"{cls.name}_{f.name}"),
columns=[ columns=[
Column("id", type=dbtype(cls.name)), Column("id", type=dbtype(cls.name)),
Column(inflection.singularize(f.name), dbtype(f.type, add_or_none_except)), Column(inflection.singularize(f.name), dbtype(f.type, add_or_none_except)),
@@ -79,7 +84,7 @@ def cls_to_dbscheme(cls: schema.Class, lookup: typing.Dict[str, schema.Class], a
elif f.is_repeated: elif f.is_repeated:
yield Table( yield Table(
keyset=KeySet(["id", "index"]), keyset=KeySet(["id", "index"]),
name=inflection.tableize(f"{cls.name}_{f.name}"), name=overridden_table_name or inflection.tableize(f"{cls.name}_{f.name}"),
columns=[ columns=[
Column("id", type=dbtype(cls.name)), Column("id", type=dbtype(cls.name)),
Column("index", type="int"), Column("index", type="int"),
@@ -90,7 +95,7 @@ def cls_to_dbscheme(cls: schema.Class, lookup: typing.Dict[str, schema.Class], a
elif f.is_optional: elif f.is_optional:
yield Table( yield Table(
keyset=KeySet(["id"]), keyset=KeySet(["id"]),
name=inflection.tableize(f"{cls.name}_{f.name}"), name=overridden_table_name or inflection.tableize(f"{cls.name}_{f.name}"),
columns=[ columns=[
Column("id", type=dbtype(cls.name)), Column("id", type=dbtype(cls.name)),
Column(f.name, dbtype(f.type, add_or_none_except)), Column(f.name, dbtype(f.type, add_or_none_except)),
@@ -100,7 +105,7 @@ def cls_to_dbscheme(cls: schema.Class, lookup: typing.Dict[str, schema.Class], a
elif f.is_predicate: elif f.is_predicate:
yield Table( yield Table(
keyset=KeySet(["id"]), keyset=KeySet(["id"]),
name=inflection.underscore(f"{cls.name}_{f.name}"), name=overridden_table_name or inflection.underscore(f"{cls.name}_{f.name}"),
columns=[ columns=[
Column("id", type=dbtype(cls.name)), Column("id", type=dbtype(cls.name)),
], ],
@@ -108,6 +113,17 @@ def cls_to_dbscheme(cls: schema.Class, lookup: typing.Dict[str, schema.Class], a
) )
def check_name_conflicts(decls: list[Table | Union]):
names = set()
for decl in decls:
match decl:
case Table(name=name):
if name in names:
raise Error(f"Duplicate table name: {
name}, you can use `@ql.db_table_name` on a property to resolve this")
names.add(name)
def get_declarations(data: schema.Schema): def get_declarations(data: schema.Schema):
add_or_none_except = data.root_class.name if data.null else None add_or_none_except = data.root_class.name if data.null else None
declarations = [d for cls in data.classes.values() if not cls.imported for d in cls_to_dbscheme(cls, declarations = [d for cls in data.classes.values() if not cls.imported for d in cls_to_dbscheme(cls,
@@ -120,6 +136,7 @@ def get_declarations(data: schema.Schema):
declarations += [ declarations += [
Union(dbtype(t, data.null), [dbtype(t), dbtype(data.null)]) for t in sorted(property_classes) Union(dbtype(t, data.null), [dbtype(t), dbtype(data.null)]) for t in sorted(property_classes)
] ]
check_name_conflicts(declarations)
return declarations return declarations

View File

@@ -130,6 +130,9 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, lookup: typing.Dic
internal="ql_internal" in prop.pragmas, internal="ql_internal" in prop.pragmas,
) )
ql_name = prop.pragmas.get("ql_name", prop.name) ql_name = prop.pragmas.get("ql_name", prop.name)
db_table_name = prop.pragmas.get("ql_db_table_name")
if db_table_name and prop.is_single:
raise Error(f"`db_table_name` pragma is not supported for single properties, but {cls.name}.{prop.name} has it")
if prop.is_single: if prop.is_single:
args.update( args.update(
singular=inflection.camelize(ql_name), singular=inflection.camelize(ql_name),
@@ -141,7 +144,7 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, lookup: typing.Dic
args.update( args.update(
singular=inflection.singularize(inflection.camelize(ql_name)), singular=inflection.singularize(inflection.camelize(ql_name)),
plural=inflection.pluralize(inflection.camelize(ql_name)), plural=inflection.pluralize(inflection.camelize(ql_name)),
tablename=inflection.tableize(f"{cls.name}_{prop.name}"), tablename=db_table_name or inflection.tableize(f"{cls.name}_{prop.name}"),
tableparams=["this", "index", "result"] if not prop.is_unordered else ["this", "result"], tableparams=["this", "index", "result"] if not prop.is_unordered else ["this", "result"],
doc=_get_doc(cls, prop, plural=False), doc=_get_doc(cls, prop, plural=False),
doc_plural=_get_doc(cls, prop, plural=True), doc_plural=_get_doc(cls, prop, plural=True),
@@ -149,14 +152,14 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, lookup: typing.Dic
elif prop.is_optional: elif prop.is_optional:
args.update( args.update(
singular=inflection.camelize(ql_name), singular=inflection.camelize(ql_name),
tablename=inflection.tableize(f"{cls.name}_{prop.name}"), tablename=db_table_name or inflection.tableize(f"{cls.name}_{prop.name}"),
tableparams=["this", "result"], tableparams=["this", "result"],
doc=_get_doc(cls, prop), doc=_get_doc(cls, prop),
) )
elif prop.is_predicate: elif prop.is_predicate:
args.update( args.update(
singular=inflection.camelize(ql_name, uppercase_first_letter=False), singular=inflection.camelize(ql_name, uppercase_first_letter=False),
tablename=inflection.underscore(f"{cls.name}_{prop.name}"), tablename=db_table_name or inflection.underscore(f"{cls.name}_{prop.name}"),
tableparams=["this"], tableparams=["this"],
doc=_get_doc(cls, prop), doc=_get_doc(cls, prop),
) )

View File

@@ -27,14 +27,20 @@ def _get_type(t: str) -> str:
return t return t
def _get_table_name(cls: schema.Class, p: schema.Property) -> str:
if p.is_single:
return inflection.tableize(cls.name)
overridden_table_name = p.pragmas.get("ql_db_table_name")
if overridden_table_name:
return overridden_table_name
table_name = f"{cls.name}_{p.name}"
if p.is_predicate:
return inflection.underscore(table_name)
else:
return inflection.tableize(table_name)
def _get_field(cls: schema.Class, p: schema.Property) -> rust.Field: def _get_field(cls: schema.Class, p: schema.Property) -> rust.Field:
table_name = inflection.tableize(cls.name)
if not p.is_single:
table_name = f"{cls.name}_{p.name}"
if p.is_predicate:
table_name = inflection.underscore(table_name)
else:
table_name = inflection.tableize(table_name)
args = dict( args = dict(
field_name=rust.avoid_keywords(p.name), field_name=rust.avoid_keywords(p.name),
base_type=_get_type(p.type), base_type=_get_type(p.type),
@@ -42,7 +48,7 @@ def _get_field(cls: schema.Class, p: schema.Property) -> rust.Field:
is_repeated=p.is_repeated, is_repeated=p.is_repeated,
is_predicate=p.is_predicate, is_predicate=p.is_predicate,
is_unordered=p.is_unordered, is_unordered=p.is_unordered,
table_name=table_name, table_name=_get_table_name(cls, p),
) )
args.update(rust.get_field_override(p.name)) args.update(rust.get_field_override(p.name))
return rust.Field(**args) return rust.Field(**args)

View File

@@ -2,8 +2,9 @@ from typing import (
Callable as _Callable, Callable as _Callable,
Dict as _Dict, Dict as _Dict,
Iterable as _Iterable, Iterable as _Iterable,
ClassVar as _ClassVar, Union as _Union,
) )
from copy import deepcopy as _deepcopy
from misc.codegen.lib import schema as _schema from misc.codegen.lib import schema as _schema
import inspect as _inspect import inspect as _inspect
from dataclasses import dataclass as _dataclass from dataclasses import dataclass as _dataclass
@@ -75,7 +76,7 @@ class _Namespace:
""" simple namespacing mechanism """ """ simple namespacing mechanism """
_name: str _name: str
def add(self, pragma: "_PragmaBase", key: str | None = None): def add(self, pragma: _Union["_PragmaBase", "_Parametrized"], key: str | None = None):
self.__dict__[pragma.pragma] = pragma self.__dict__[pragma.pragma] = pragma
pragma.pragma = key or f"{self._name}_{pragma.pragma}" pragma.pragma = key or f"{self._name}_{pragma.pragma}"
@@ -101,6 +102,10 @@ synth = _SynthModifier("synth")
@_dataclass @_dataclass
class _PragmaBase: class _PragmaBase:
pragma: str pragma: str
value: object = None
def _apply(self, pragmas: _Dict[str, object]) -> None:
pragmas[self.pragma] = self.value
@_dataclass @_dataclass
@@ -109,7 +114,6 @@ class _ClassPragma(_PragmaBase):
For schema classes it acts as a python decorator with `@`. For schema classes it acts as a python decorator with `@`.
""" """
inherited: bool = False inherited: bool = False
value: object = None
def __call__(self, cls: type) -> type: def __call__(self, cls: type) -> type:
""" use this pragma as a decorator on classes """ """ use this pragma as a decorator on classes """
@@ -122,15 +126,11 @@ class _ClassPragma(_PragmaBase):
self._apply(cls._pragmas) self._apply(cls._pragmas)
return cls return cls
def _apply(self, pragmas: _Dict[str, object]) -> None:
pragmas[self.pragma] = self.value
@_dataclass @_dataclass
class _Pragma(_ClassPragma, _schema.PropertyModifier): class _PropertyPragma(_PragmaBase, _schema.PropertyModifier):
""" A class or property pragma. """ A property pragma.
For properties, it functions similarly to a `_PropertyModifier` with `|`, adding the pragma. It functions similarly to a `_PropertyModifier` with `|`, adding the pragma.
For schema classes it acts as a python decorator with `@`.
""" """
remove: bool = False remove: bool = False
@@ -138,7 +138,7 @@ class _Pragma(_ClassPragma, _schema.PropertyModifier):
self._apply(prop.pragmas) self._apply(prop.pragmas)
def negate(self) -> _schema.PropertyModifier: def negate(self) -> _schema.PropertyModifier:
return _Pragma(self.pragma, remove=True) return _PropertyPragma(self.pragma, remove=not self.remove)
def _apply(self, pragmas: _Dict[str, object]) -> None: def _apply(self, pragmas: _Dict[str, object]) -> None:
if self.remove: if self.remove:
@@ -148,31 +148,38 @@ class _Pragma(_ClassPragma, _schema.PropertyModifier):
@_dataclass @_dataclass
class _ParametrizedClassPragma(_PragmaBase): class _Pragma(_ClassPragma, _PropertyPragma):
""" A class parametrized pragma. """ A class or property pragma.
Needs to be applied to a parameter to give a class pragma. For properties, it functions similarly to a `_PropertyModifier` with `|`, adding the pragma.
For schema classes it acts as a python decorator with `@`.
""" """
_pragma_class: _ClassVar[type] = _ClassPragma
inherited: bool = False
factory: _Callable[..., object] = None
def __post_init__(self):
self.__signature__ = _inspect.signature(self.factory).replace(return_annotation=self._pragma_class)
def __call__(self, *args, **kwargs) -> _pragma_class:
return self._pragma_class(self.pragma, self.inherited, value=self.factory(*args, **kwargs))
@_dataclass class _Parametrized[P, **Q, T]:
class _ParametrizedPragma(_ParametrizedClassPragma): """ A parametrized pragma.
""" A class or property parametrized pragma.
Needs to be applied to a parameter to give a pragma. Needs to be applied to a parameter to give a pragma.
""" """
_pragma_class: _ClassVar[type] = _Pragma
def __invert__(self) -> _Pragma: def __init__(self, pragma_instance: P, factory: _Callable[Q, T]):
return _Pragma(self.pragma, remove=True) self.pragma_instance = pragma_instance
self.factory = factory
self.__signature__ = _inspect.signature(self.factory).replace(return_annotation=type(self.pragma_instance))
@property
def pragma(self):
return self.pragma_instance.pragma
@pragma.setter
def pragma(self, value):
self.pragma_instance.pragma = value
def __invert__(self) -> "_Parametrized[P, Q, T]":
return _Parametrized(~self.pragma_instance, factory=self.factory)
def __call__(self, *args: Q.args, **kwargs: Q.kwargs) -> T:
ret = _deepcopy(self.pragma_instance)
ret.value = self.factory(*args, **kwargs)
return ret
class _Optionalizer(_schema.PropertyModifier): class _Optionalizer(_schema.PropertyModifier):
@@ -232,30 +239,31 @@ desc = _DescModifier
use_for_null = _ClassPragma("null") use_for_null = _ClassPragma("null")
qltest.add(_Pragma("skip")) qltest.add(_ClassPragma("skip"))
qltest.add(_ClassPragma("collapse_hierarchy")) qltest.add(_ClassPragma("collapse_hierarchy"))
qltest.add(_ClassPragma("uncollapse_hierarchy")) qltest.add(_ClassPragma("uncollapse_hierarchy"))
qltest.add(_ParametrizedClassPragma("test_with", inherited=True, factory=_schema.get_type_name)) qltest.add(_Parametrized(_ClassPragma("test_with", inherited=True), factory=_schema.get_type_name))
ql.add(_ParametrizedClassPragma("default_doc_name", factory=lambda doc: doc)) ql.add(_Parametrized(_ClassPragma("default_doc_name"), factory=lambda doc: doc))
ql.add(_ClassPragma("hideable", inherited=True)) ql.add(_ClassPragma("hideable", inherited=True))
ql.add(_Pragma("internal")) ql.add(_Pragma("internal"))
ql.add(_ParametrizedPragma("name", factory=lambda name: name)) ql.add(_Parametrized(_Pragma("name"), factory=lambda name: name))
ql.add(_Parametrized(_PropertyPragma("db_table_name"), factory=lambda name: name))
cpp.add(_Pragma("skip")) cpp.add(_Pragma("skip"))
rust.add(_Pragma("detach")) rust.add(_PropertyPragma("detach"))
rust.add(_Pragma("skip_doc_test")) rust.add(_Pragma("skip_doc_test"))
rust.add(_ParametrizedClassPragma("doc_test_signature", factory=lambda signature: signature)) rust.add(_Parametrized(_ClassPragma("doc_test_signature"), factory=lambda signature: signature))
group = _ParametrizedClassPragma("group", inherited=True, factory=lambda group: group) group = _Parametrized(_ClassPragma("group", inherited=True), factory=lambda group: group)
synth.add(_ParametrizedClassPragma("from_class", factory=lambda ref: _schema.SynthInfo( synth.add(_Parametrized(_ClassPragma("from_class"), factory=lambda ref: _schema.SynthInfo(
from_class=_schema.get_type_name(ref))), key="synth") from_class=_schema.get_type_name(ref))), key="synth")
synth.add(_ParametrizedClassPragma("on_arguments", factory=lambda **kwargs: synth.add(_Parametrized(_ClassPragma("on_arguments"), factory=lambda **kwargs:
_schema.SynthInfo(on_arguments={k: _schema.get_type_name(t) for k, t in kwargs.items()})), key="synth") _schema.SynthInfo(on_arguments={k: _schema.get_type_name(t) for k, t in kwargs.items()})), key="synth")
@_dataclass(frozen=True) @_dataclass(frozen=True)

View File

@@ -1,5 +1,5 @@
# #
# This file is autogenerated by pip-compile with Python 3.11 # This file is autogenerated by pip-compile with Python 3.12
# by the following command: # by the following command:
# #
# pip-compile --output-file=misc/codegen/requirements_lock.txt misc/codegen/requirements_in.txt # pip-compile --output-file=misc/codegen/requirements_lock.txt misc/codegen/requirements_in.txt
@@ -8,15 +8,15 @@ inflection==0.5.1
# via -r misc/codegen/requirements_in.txt # via -r misc/codegen/requirements_in.txt
iniconfig==2.0.0 iniconfig==2.0.0
# via pytest # via pytest
packaging==23.2 packaging==24.2
# via pytest # via pytest
pluggy==1.4.0 pluggy==1.5.0
# via pytest # via pytest
pystache==0.6.5 pystache==0.6.8
# via -r misc/codegen/requirements_in.txt # via -r misc/codegen/requirements_in.txt
pytest==8.0.0 pytest==8.3.5
# via -r misc/codegen/requirements_in.txt # via -r misc/codegen/requirements_in.txt
pyyaml==6.0.1 pyyaml==6.0.2
# via -r misc/codegen/requirements_in.txt # via -r misc/codegen/requirements_in.txt
toposort==1.10 toposort==1.10
# via -r misc/codegen/requirements_in.txt # via -r misc/codegen/requirements_in.txt

View File

@@ -225,5 +225,25 @@ def test_synth_properties_ignored(generate):
] ]
def test_properties_with_custom_db_table_names(generate):
assert generate([
schema.Class("Obj", properties=[
schema.OptionalProperty("x", "a", pragmas={"ql_db_table_name": "foo"}),
schema.RepeatedProperty("y", "b", pragmas={"ql_db_table_name": "bar"}),
schema.RepeatedOptionalProperty("z", "c", pragmas={"ql_db_table_name": "baz"}),
schema.PredicateProperty("p", pragmas={"ql_db_table_name": "hello"}),
schema.RepeatedUnorderedProperty("q", "d", pragmas={"ql_db_table_name": "world"}),
]),
]) == [
cpp.Class(name="Obj", final=True, trap_name="Objs", fields=[
cpp.Field("x", "a", is_optional=True, trap_name="Foo"),
cpp.Field("y", "b", is_repeated=True, trap_name="Bar"),
cpp.Field("z", "c", is_repeated=True, is_optional=True, trap_name="Baz"),
cpp.Field("p", "bool", is_predicate=True, trap_name="Hello"),
cpp.Field("q", "d", is_repeated=True, is_unordered=True, trap_name="World"),
]),
]
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(pytest.main([__file__] + sys.argv[1:])) sys.exit(pytest.main([__file__] + sys.argv[1:]))

View File

@@ -593,5 +593,78 @@ def test_synth_properties_ignored(generate):
) )
def test_table_conflict(generate):
with pytest.raises(dbschemegen.Error):
generate([
schema.Class("Foo", properties=[
schema.OptionalProperty("bar", "FooBar"),
]),
schema.Class("FooBar"),
])
def test_table_name_overrides(generate):
assert generate([
schema.Class("Obj", properties=[
schema.OptionalProperty("x", "a", pragmas={"ql_db_table_name": "foo"}),
schema.RepeatedProperty("y", "b", pragmas={"ql_db_table_name": "bar"}),
schema.RepeatedOptionalProperty("z", "c", pragmas={"ql_db_table_name": "baz"}),
schema.PredicateProperty("p", pragmas={"ql_db_table_name": "hello"}),
schema.RepeatedUnorderedProperty("q", "d", pragmas={"ql_db_table_name": "world"}),
]),
]) == dbscheme.Scheme(
src=schema_file.name,
includes=[],
declarations=[
dbscheme.Table(
name="objs",
columns=[
dbscheme.Column("id", "@obj", binding=True),
],
),
dbscheme.Table(
name="foo",
keyset=dbscheme.KeySet(["id"]),
columns=[
dbscheme.Column("id", "@obj"),
dbscheme.Column("x", "a"),
],
),
dbscheme.Table(
name="bar",
keyset=dbscheme.KeySet(["id", "index"]),
columns=[
dbscheme.Column("id", "@obj"),
dbscheme.Column("index", "int"),
dbscheme.Column("y", "b"),
],
),
dbscheme.Table(
name="baz",
keyset=dbscheme.KeySet(["id", "index"]),
columns=[
dbscheme.Column("id", "@obj"),
dbscheme.Column("index", "int"),
dbscheme.Column("z", "c"),
],
),
dbscheme.Table(
name="hello",
keyset=dbscheme.KeySet(["id"]),
columns=[
dbscheme.Column("id", "@obj"),
],
),
dbscheme.Table(
name="world",
columns=[
dbscheme.Column("id", "@obj"),
dbscheme.Column("q", "d"),
],
),
],
)
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(pytest.main([__file__] + sys.argv[1:])) sys.exit(pytest.main([__file__] + sys.argv[1:]))

View File

@@ -1013,5 +1013,38 @@ def test_hideable_property(generate_classes):
} }
def test_property_with_custom_db_table_name(generate_classes):
assert generate_classes([
schema.Class("Obj", properties=[
schema.OptionalProperty("x", "a", pragmas={"ql_db_table_name": "foo"}),
schema.RepeatedProperty("y", "b", pragmas={"ql_db_table_name": "bar"}),
schema.RepeatedOptionalProperty("z", "c", pragmas={"ql_db_table_name": "baz"}),
schema.PredicateProperty("p", pragmas={"ql_db_table_name": "hello"}),
schema.RepeatedUnorderedProperty("q", "d", pragmas={"ql_db_table_name": "world"}),
]),
]) == {
"Obj.qll": (a_ql_class_public(name="Obj"),
a_ql_stub(name="Obj"),
a_ql_class(name="Obj", final=True, properties=[
ql.Property(singular="X", type="a", tablename="foo",
tableparams=["this", "result"],
is_optional=True, doc="x of this obj"),
ql.Property(singular="Y", plural="Ys", type="b", tablename="bar",
tableparams=["this", "index", "result"],
doc="y of this obj", doc_plural="ys of this obj"),
ql.Property(singular="Z", plural="Zs", type="c", tablename="baz",
tableparams=["this", "index", "result"],
is_optional=True, doc="z of this obj", doc_plural="zs of this obj"),
ql.Property(singular="p", type="predicate", tablename="hello",
tableparams=["this"], is_predicate=True,
doc="this obj p"),
ql.Property(singular="Q", plural="Qs", type="d", tablename="world",
tableparams=["this", "result"], is_unordered=True,
doc="q of this obj", doc_plural="qs of this obj"),
],
imports=[stub_import_prefix + "Obj"])),
}
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(pytest.main([__file__] + sys.argv[1:])) sys.exit(pytest.main([__file__] + sys.argv[1:]))

View File

@@ -272,10 +272,10 @@ def test_builtin_predicate_and_set_children_not_allowed(spec):
_class_pragmas = [ _class_pragmas = [
(defs.qltest.collapse_hierarchy, "qltest_collapse_hierarchy"), (defs.qltest.collapse_hierarchy, "qltest_collapse_hierarchy"),
(defs.qltest.uncollapse_hierarchy, "qltest_uncollapse_hierarchy"), (defs.qltest.uncollapse_hierarchy, "qltest_uncollapse_hierarchy"),
(defs.qltest.skip, "qltest_skip"),
] ]
_property_pragmas = [ _property_pragmas = [
(defs.qltest.skip, "qltest_skip"),
(defs.cpp.skip, "cpp_skip"), (defs.cpp.skip, "cpp_skip"),
(defs.ql.internal, "ql_internal"), (defs.ql.internal, "ql_internal"),
] ]
@@ -646,6 +646,17 @@ def test_class_default_doc_name():
} }
def test_db_table_name():
@load
class data:
class A:
x: optional[int] | defs.ql.db_table_name("foo")
assert data.classes == {
'A': schema.Class('A', properties=[schema.OptionalProperty("x", "int", pragmas={"ql_db_table_name": "foo"})]),
}
def test_null_class(): def test_null_class():
@load @load
class data: class data:
@@ -838,7 +849,7 @@ def test_annotate_fields_negations():
@load @load
class data: class data:
class Root: class Root:
x: defs.int | defs.ql.internal | defs.qltest.skip x: defs.int | defs.ql.internal
y: defs.optional["Root"] | defs.child | defs.desc("foo\nbar\n") y: defs.optional["Root"] | defs.child | defs.desc("foo\nbar\n")
z: defs.string | defs.synth | defs.doc("foo") z: defs.string | defs.synth | defs.doc("foo")
@@ -850,7 +861,7 @@ def test_annotate_fields_negations():
assert data.classes == { assert data.classes == {
"Root": schema.Class("Root", properties=[ "Root": schema.Class("Root", properties=[
schema.SingleProperty("x", "int", pragmas=["qltest_skip"]), schema.SingleProperty("x", "int"),
schema.OptionalProperty("y", "Root"), schema.OptionalProperty("y", "Root"),
schema.SingleProperty("z", "string"), schema.SingleProperty("z", "string"),
]), ]),

View File

@@ -36,7 +36,6 @@ fn property_name(type_name: &str, field_name: &str) -> String {
("CallExpr", "expr") => "function", ("CallExpr", "expr") => "function",
("LetExpr", "expr") => "scrutinee", ("LetExpr", "expr") => "scrutinee",
("MatchExpr", "expr") => "scrutinee", ("MatchExpr", "expr") => "scrutinee",
("Path", "segment") => "part",
(_, "then_branch") => "then", (_, "then_branch") => "then",
(_, "else_branch") => "else_", (_, "else_branch") => "else_",
("ArrayType", "ty") => "element_type_repr", ("ArrayType", "ty") => "element_type_repr",

View File

@@ -1004,7 +1004,7 @@ fn make_qualified_path(
id: trap::TrapId::Star, id: trap::TrapId::Star,
text: Some(name), text: Some(name),
})); }));
let part = Some(trap.emit(generated::PathSegment { let segment = Some(trap.emit(generated::PathSegment {
id: trap::TrapId::Star, id: trap::TrapId::Star,
generic_arg_list: None, generic_arg_list: None,
name_ref, name_ref,
@@ -1015,7 +1015,7 @@ fn make_qualified_path(
trap.emit(generated::Path { trap.emit(generated::Path {
id: trap::TrapId::Star, id: trap::TrapId::Star,
qualifier, qualifier,
part, segment,
}) })
} }
path.into_iter() path.into_iter()

View File

@@ -1,2 +1,2 @@
mod.rs 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7 mod.rs 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7
top.rs fcff2f1d468e6bc5384e5c0d7f3249773fa3ef38db054c0ec555c43d143117da fcff2f1d468e6bc5384e5c0d7f3249773fa3ef38db054c0ec555c43d143117da top.rs 49e4f3abb137d6eed5a7c5202b3a31c9cafa1f565ee63dd5960e971950fafaa1 49e4f3abb137d6eed5a7c5202b3a31c9cafa1f565ee63dd5960e971950fafaa1

View File

@@ -2027,7 +2027,7 @@ impl From<trap::Label<Pat>> for trap::Label<Element> {
pub struct Path { pub struct Path {
pub id: trap::TrapId<Path>, pub id: trap::TrapId<Path>,
pub qualifier: Option<trap::Label<Path>>, pub qualifier: Option<trap::Label<Path>>,
pub part: Option<trap::Label<PathSegment>>, pub segment: Option<trap::Label<PathSegment>>,
} }
impl trap::TrapEntry for Path { impl trap::TrapEntry for Path {
@@ -2040,8 +2040,8 @@ impl trap::TrapEntry for Path {
if let Some(v) = self.qualifier { if let Some(v) = self.qualifier {
out.add_tuple("path_qualifiers", vec![id.into(), v.into()]); out.add_tuple("path_qualifiers", vec![id.into(), v.into()]);
} }
if let Some(v) = self.part { if let Some(v) = self.segment {
out.add_tuple("path_parts", vec![id.into(), v.into()]); out.add_tuple("path_segments_", vec![id.into(), v.into()]);
} }
} }
} }

View File

@@ -1659,11 +1659,11 @@ impl Translator<'_> {
pub(crate) fn emit_path(&mut self, node: ast::Path) -> Option<Label<generated::Path>> { pub(crate) fn emit_path(&mut self, node: ast::Path) -> Option<Label<generated::Path>> {
let qualifier = node.qualifier().and_then(|x| self.emit_path(x)); let qualifier = node.qualifier().and_then(|x| self.emit_path(x));
let part = node.segment().and_then(|x| self.emit_path_segment(x)); let segment = node.segment().and_then(|x| self.emit_path_segment(x));
let label = self.trap.emit(generated::Path { let label = self.trap.emit(generated::Path {
id: TrapId::Star, id: TrapId::Star,
qualifier, qualifier,
part, segment,
}); });
self.emit_location(label, &node); self.emit_location(label, &node);
emit_detached!(Path, self, node, label); emit_detached!(Path, self, node, label);

View File

@@ -579,10 +579,10 @@ lib/codeql/rust/elements/internal/generated/ParamList.qll c808c9d84dd7800573832b
lib/codeql/rust/elements/internal/generated/ParenExpr.qll bc0731505bfe88516205ec360582a4222d2681d11342c93e15258590ddee82f2 d4bd6e0c80cf1d63746c88d4bcb3a01d4c75732e5da09e3ebd9437ced227fb60 lib/codeql/rust/elements/internal/generated/ParenExpr.qll bc0731505bfe88516205ec360582a4222d2681d11342c93e15258590ddee82f2 d4bd6e0c80cf1d63746c88d4bcb3a01d4c75732e5da09e3ebd9437ced227fb60
lib/codeql/rust/elements/internal/generated/ParenPat.qll 4f168ef5d5bb87a903251cc31b2e44a759b099ec69c90af31783fbb15778c940 0e34f94a45a13396fd57d94c245dc64d1adde2ab0e22b56946f7e94c04e297fc lib/codeql/rust/elements/internal/generated/ParenPat.qll 4f168ef5d5bb87a903251cc31b2e44a759b099ec69c90af31783fbb15778c940 0e34f94a45a13396fd57d94c245dc64d1adde2ab0e22b56946f7e94c04e297fc
lib/codeql/rust/elements/internal/generated/ParenTypeRepr.qll 40ab5c592e7699c621787793743e33988de71ff42ca27599f5ab3ddb70e3f7d8 12c0a6eed2202ee3e892f61da3b3ce77ac3190854cdf3097e8d2be98aa3cb91d lib/codeql/rust/elements/internal/generated/ParenTypeRepr.qll 40ab5c592e7699c621787793743e33988de71ff42ca27599f5ab3ddb70e3f7d8 12c0a6eed2202ee3e892f61da3b3ce77ac3190854cdf3097e8d2be98aa3cb91d
lib/codeql/rust/elements/internal/generated/ParentChild.qll 052cfc8ff7ecdcc941006d07c0381c5255174cf104d15621308e143e4d5401f6 51ffa60668c98ff888b84a06f73b6540d487105ba888de1afd70067df4416509 lib/codeql/rust/elements/internal/generated/ParentChild.qll d5cda732625e48dabe494d264d2b26df2d2e043ca0503052b551ee2cb1518ab7 9ff0d4634f7be4afada224f9eb3607041ea3461b389401a9f2998099037edffe
lib/codeql/rust/elements/internal/generated/ParenthesizedArgList.qll c5fa328ea60d3a3333d7c7bb3480969c1873166c7ac8ebb9d0afad7a8099d1a8 2dbbb6200d96f7db7dea4a55bdeab8d67b14d39a43e0bd54ada019f7e466f163 lib/codeql/rust/elements/internal/generated/ParenthesizedArgList.qll c5fa328ea60d3a3333d7c7bb3480969c1873166c7ac8ebb9d0afad7a8099d1a8 2dbbb6200d96f7db7dea4a55bdeab8d67b14d39a43e0bd54ada019f7e466f163
lib/codeql/rust/elements/internal/generated/Pat.qll 3605ac062be2f294ee73336e9669027b8b655f4ad55660e1eab35266275154ee 7f9400db2884d336dd1d21df2a8093759c2a110be9bf6482ce8e80ae0fd74ed4 lib/codeql/rust/elements/internal/generated/Pat.qll 3605ac062be2f294ee73336e9669027b8b655f4ad55660e1eab35266275154ee 7f9400db2884d336dd1d21df2a8093759c2a110be9bf6482ce8e80ae0fd74ed4
lib/codeql/rust/elements/internal/generated/Path.qll 8e47e91aff3f8c60f1ee8cb3887b8e4936c38e4665d052f2c92a939a969aac29 2c28beb89cabd7c7c91a5bc65c874f414cb96bbefde37b25811b61089a8a0053 lib/codeql/rust/elements/internal/generated/Path.qll 9b12afb46fc5a9ad3a811b05472621bbecccb900c47504feb7f29d96b28421ca bcacbffc36fb3e0c9b26523b5963af0ffa9fd6b19f00a2a31bdb2316071546bd
lib/codeql/rust/elements/internal/generated/PathAstNode.qll e6d4d5bffd3c623baaaee46bc183eb31ce88795535f164f6a9b9b4d98bbd6101 168db515404933479ba6b150c72e012d28592cbc32366aefcb1bf9599dbcd183 lib/codeql/rust/elements/internal/generated/PathAstNode.qll e6d4d5bffd3c623baaaee46bc183eb31ce88795535f164f6a9b9b4d98bbd6101 168db515404933479ba6b150c72e012d28592cbc32366aefcb1bf9599dbcd183
lib/codeql/rust/elements/internal/generated/PathExpr.qll 34ebad4d062ce8b7e517f2ab09d52745fb8455203f4a936df7284ad296638387 ba66781cdbdeb89c27a4bfb2be0f27f85fb34978d699b4e343446fb0d7ad2aa6 lib/codeql/rust/elements/internal/generated/PathExpr.qll 34ebad4d062ce8b7e517f2ab09d52745fb8455203f4a936df7284ad296638387 ba66781cdbdeb89c27a4bfb2be0f27f85fb34978d699b4e343446fb0d7ad2aa6
lib/codeql/rust/elements/internal/generated/PathExprBase.qll d8218e201b8557fa6d9ca2c30b764e5ad9a04a2e4fb695cc7219bbd7636a6ac2 4ef178426d7095a156f4f8c459b4d16f63abc64336cb50a6cf883a5f7ee09113 lib/codeql/rust/elements/internal/generated/PathExprBase.qll d8218e201b8557fa6d9ca2c30b764e5ad9a04a2e4fb695cc7219bbd7636a6ac2 4ef178426d7095a156f4f8c459b4d16f63abc64336cb50a6cf883a5f7ee09113
@@ -594,7 +594,7 @@ lib/codeql/rust/elements/internal/generated/PtrTypeRepr.qll 51d1e9e683fc79dddbff
lib/codeql/rust/elements/internal/generated/PureSynthConstructors.qll e5b8e69519012bbaae29dcb82d53f7f7ecce368c0358ec27ef6180b228a0057f e5b8e69519012bbaae29dcb82d53f7f7ecce368c0358ec27ef6180b228a0057f lib/codeql/rust/elements/internal/generated/PureSynthConstructors.qll e5b8e69519012bbaae29dcb82d53f7f7ecce368c0358ec27ef6180b228a0057f e5b8e69519012bbaae29dcb82d53f7f7ecce368c0358ec27ef6180b228a0057f
lib/codeql/rust/elements/internal/generated/RangeExpr.qll 23cca03bf43535f33b22a38894f70d669787be4e4f5b8fe5c8f7b964d30e9027 18624cef6c6b679eeace2a98737e472432e0ead354cca02192b4d45330f047c9 lib/codeql/rust/elements/internal/generated/RangeExpr.qll 23cca03bf43535f33b22a38894f70d669787be4e4f5b8fe5c8f7b964d30e9027 18624cef6c6b679eeace2a98737e472432e0ead354cca02192b4d45330f047c9
lib/codeql/rust/elements/internal/generated/RangePat.qll 80826a6a6868a803aa2372e31c52a03e1811a3f1f2abdb469f91ca0bfdd9ecb6 34ee1e208c1690cba505dff2c588837c0cd91e185e2a87d1fe673191962276a9 lib/codeql/rust/elements/internal/generated/RangePat.qll 80826a6a6868a803aa2372e31c52a03e1811a3f1f2abdb469f91ca0bfdd9ecb6 34ee1e208c1690cba505dff2c588837c0cd91e185e2a87d1fe673191962276a9
lib/codeql/rust/elements/internal/generated/Raw.qll ba65a01002b1eb2dd26a637c5475c06e91f11f1093d820787e5df4226aaa137f 0d8cabba6fa915461b3cce7e065f4f77339798f008c3fc3ab143667321729e67 lib/codeql/rust/elements/internal/generated/Raw.qll 48bb632ea749504184ba9ed85f364806657a6de953eff9492d5c1c509c75b9b0 b5f8a05c79cbb36f95d830994946e58862583f3e16df80c947e8318aa8f17beb
lib/codeql/rust/elements/internal/generated/RecordFieldList.qll 4a23b0d75a90671197246dbbb4e62706c180074abb8ebe60a96df11c47a917a2 09be127977651a24010b090d9681714d83ebd461098f9cf0e0d1973cafb1c782 lib/codeql/rust/elements/internal/generated/RecordFieldList.qll 4a23b0d75a90671197246dbbb4e62706c180074abb8ebe60a96df11c47a917a2 09be127977651a24010b090d9681714d83ebd461098f9cf0e0d1973cafb1c782
lib/codeql/rust/elements/internal/generated/RefExpr.qll 7d995884e3dc1c25fc719f5d7253179344d63650e217e9ff6530285fe7a57f64 f2c3c12551deea4964b66553fb9b6423ee16fec53bd63db4796191aa60dc6c66 lib/codeql/rust/elements/internal/generated/RefExpr.qll 7d995884e3dc1c25fc719f5d7253179344d63650e217e9ff6530285fe7a57f64 f2c3c12551deea4964b66553fb9b6423ee16fec53bd63db4796191aa60dc6c66
lib/codeql/rust/elements/internal/generated/RefPat.qll 456ede39837463ee22a630ec7ab6c8630d3664a8ea206fcc6e4f199e92fa564c 5622062765f32930465ba6b170e986706f159f6070f48adee3c20e24e8df4e05 lib/codeql/rust/elements/internal/generated/RefPat.qll 456ede39837463ee22a630ec7ab6c8630d3664a8ea206fcc6e4f199e92fa564c 5622062765f32930465ba6b170e986706f159f6070f48adee3c20e24e8df4e05
@@ -986,7 +986,7 @@ test/extractor-tests/generated/ParenPat/ParenPat_getPat.ql 96f3db0ec4e71fd870619
test/extractor-tests/generated/ParenTypeRepr/ParenTypeRepr.ql a96bb8b51d8c0c466afc1c076834fa16edf7e67fffe2f641799850dee43099a2 0e6c375e621b7a7756d39e8edd78b671e53d1aac757ac54a26747fe5259c5394 test/extractor-tests/generated/ParenTypeRepr/ParenTypeRepr.ql a96bb8b51d8c0c466afc1c076834fa16edf7e67fffe2f641799850dee43099a2 0e6c375e621b7a7756d39e8edd78b671e53d1aac757ac54a26747fe5259c5394
test/extractor-tests/generated/ParenTypeRepr/ParenTypeRepr_getTypeRepr.ql 64fe4ea708bc489ba64ed845f63cfbcd57c1179c57d95be309db37eac2f5eb71 0f4cbbfdf39d89830b5249cabf26d834fc2310b8a9579c19383c90cb4333afb7 test/extractor-tests/generated/ParenTypeRepr/ParenTypeRepr_getTypeRepr.ql 64fe4ea708bc489ba64ed845f63cfbcd57c1179c57d95be309db37eac2f5eb71 0f4cbbfdf39d89830b5249cabf26d834fc2310b8a9579c19383c90cb4333afb7
test/extractor-tests/generated/ParenthesizedArgList/MISSING_SOURCE.txt b6cf5771fdbbe981aeb3f443ec7a40517b6e99ffc9817fd8872c2e344240dae1 b6cf5771fdbbe981aeb3f443ec7a40517b6e99ffc9817fd8872c2e344240dae1 test/extractor-tests/generated/ParenthesizedArgList/MISSING_SOURCE.txt b6cf5771fdbbe981aeb3f443ec7a40517b6e99ffc9817fd8872c2e344240dae1 b6cf5771fdbbe981aeb3f443ec7a40517b6e99ffc9817fd8872c2e344240dae1
test/extractor-tests/generated/Path/Path.ql 2bdcd99b3b5ffc83ac47d8cc27a4561d616bcf06844f0c452c699cd10ee640ca 5a7d7ffb8b0c04d6a8cbb2a953761df8561b796c4372bef1bd55c359b2f19911 test/extractor-tests/generated/Path/Path.ql 2b02325ab1739bf41bc5f50d56b1e9cc72fca4093b03f2bda193699121e64448 c4d44402696ce10175ad8286dbd78277fbb81e7e1b886c0c27d5b88a7509052e
test/extractor-tests/generated/Path/PathExpr.ql 5039fe730998a561f51813a0716e18c7c1d36b6da89936e4cfbdb4ef0e895560 cd3ddf8ab93cd573381807f59cded7fb3206f1dbdff582490be6f23bed2d6f29 test/extractor-tests/generated/Path/PathExpr.ql 5039fe730998a561f51813a0716e18c7c1d36b6da89936e4cfbdb4ef0e895560 cd3ddf8ab93cd573381807f59cded7fb3206f1dbdff582490be6f23bed2d6f29
test/extractor-tests/generated/Path/PathExpr_getAttr.ql 2ccac48cd91d86670c1d2742de20344135d424e6f0e3dafcc059555046f92d92 9b7b5f5f9e3674fad9b3a5bcd3cabc0dff32a95640da0fce6f4d0eb931f1757d test/extractor-tests/generated/Path/PathExpr_getAttr.ql 2ccac48cd91d86670c1d2742de20344135d424e6f0e3dafcc059555046f92d92 9b7b5f5f9e3674fad9b3a5bcd3cabc0dff32a95640da0fce6f4d0eb931f1757d
test/extractor-tests/generated/Path/PathExpr_getPath.ql e7894071313a74166bdd31d7cd974037fcd5a7f0e92d5eec42833266196eb858 46a06e8a1207e7a0fa175cd4b61068e5fd6c43b5575b88986409f0ac2be64c51 test/extractor-tests/generated/Path/PathExpr_getPath.ql e7894071313a74166bdd31d7cd974037fcd5a7f0e92d5eec42833266196eb858 46a06e8a1207e7a0fa175cd4b61068e5fd6c43b5575b88986409f0ac2be64c51
@@ -1006,8 +1006,8 @@ test/extractor-tests/generated/Path/PathSegment_getTraitTypeRepr.ql d7ea6ee3f6b7
test/extractor-tests/generated/Path/PathSegment_getTypeRepr.ql d9d8ff43a55671616bd5b98ff2c03690ec2661817d19a61edcc4b37d23e312d0 b4dc0ae4d7f03c98c23312b358d214565b34c7a028ba8983826c6bf5c1177eeb test/extractor-tests/generated/Path/PathSegment_getTypeRepr.ql d9d8ff43a55671616bd5b98ff2c03690ec2661817d19a61edcc4b37d23e312d0 b4dc0ae4d7f03c98c23312b358d214565b34c7a028ba8983826c6bf5c1177eeb
test/extractor-tests/generated/Path/PathTypeRepr.ql c2e069acc5111088a7287d98b4bd4bf44bd79c5a786b275f7448ebafc3613500 6e016750e5fef92a98bc5cc60bfd40d85fbb5eb2d251b4d69ffe600813f81df0 test/extractor-tests/generated/Path/PathTypeRepr.ql c2e069acc5111088a7287d98b4bd4bf44bd79c5a786b275f7448ebafc3613500 6e016750e5fef92a98bc5cc60bfd40d85fbb5eb2d251b4d69ffe600813f81df0
test/extractor-tests/generated/Path/PathTypeRepr_getPath.ql 49e96ea2aa482e3b80cb0e2d944055f8298f7fc55b36cea7468586c94bacf686 29b3c2140ac1bc6e0e6160140e292e2b84e13145c1553480e2a582cd7f7bd3fd test/extractor-tests/generated/Path/PathTypeRepr_getPath.ql 49e96ea2aa482e3b80cb0e2d944055f8298f7fc55b36cea7468586c94bacf686 29b3c2140ac1bc6e0e6160140e292e2b84e13145c1553480e2a582cd7f7bd3fd
test/extractor-tests/generated/Path/Path_getPart.ql 8aa45a0b58203ef1177166efbe1c2851faf4b4c9a453c83137f0c9298badcdbf b82d490d9b3a8237487cd5da8b3b6fc4aa477977b332a5c6539b3cd4e6d5b45b
test/extractor-tests/generated/Path/Path_getQualifier.ql 9af95e22cdf3a65da6a41d93136aef4523db5ce81d38f6ed4bc613f1c68784d0 3102d9241a417a92c97a53ac56a7a8683463f1adc7a593cda1382c0d25b3f261 test/extractor-tests/generated/Path/Path_getQualifier.ql 9af95e22cdf3a65da6a41d93136aef4523db5ce81d38f6ed4bc613f1c68784d0 3102d9241a417a92c97a53ac56a7a8683463f1adc7a593cda1382c0d25b3f261
test/extractor-tests/generated/Path/Path_getSegment.ql 475f344ee24a14468745d50922fdfd63f5d817f14cc041a184c2f8ec144a01dd 4f663c5c2b1e0cb8b9a8a0b2d8b5d81f12a3bf333c71ecbb43d9258f7dfe4ec7
test/extractor-tests/generated/PrefixExpr/PrefixExpr.ql 44fb7174365c6deecdc22c720d84617c6e060c05d49c41c90433451588f8aa6f 871fab471c82fede3c36edc003f9decee5bb7844c016951d28be78d0c91487e5 test/extractor-tests/generated/PrefixExpr/PrefixExpr.ql 44fb7174365c6deecdc22c720d84617c6e060c05d49c41c90433451588f8aa6f 871fab471c82fede3c36edc003f9decee5bb7844c016951d28be78d0c91487e5
test/extractor-tests/generated/PrefixExpr/PrefixExpr_getAttr.ql fdad6ad5199435ded1e4a9ea6b246e76b904cd73a36aaa4780e84eef91741c5b 75d63940046e62c1efa1151b0cac45b5ec0bab5e39aec2e11d43f6c385e37984 test/extractor-tests/generated/PrefixExpr/PrefixExpr_getAttr.ql fdad6ad5199435ded1e4a9ea6b246e76b904cd73a36aaa4780e84eef91741c5b 75d63940046e62c1efa1151b0cac45b5ec0bab5e39aec2e11d43f6c385e37984
test/extractor-tests/generated/PrefixExpr/PrefixExpr_getExpr.ql 2d1d97f6277794871fbb032ea87ac30b1aa902a74cd874720156162057ea202e b1b9880fce07d66df7ec87f12189c37adf9f233a1d0b38a1b09808d052a95642 test/extractor-tests/generated/PrefixExpr/PrefixExpr_getExpr.ql 2d1d97f6277794871fbb032ea87ac30b1aa902a74cd874720156162057ea202e b1b9880fce07d66df7ec87f12189c37adf9f233a1d0b38a1b09808d052a95642

2
rust/ql/.gitattributes generated vendored
View File

@@ -1008,8 +1008,8 @@
/test/extractor-tests/generated/Path/PathSegment_getTypeRepr.ql linguist-generated /test/extractor-tests/generated/Path/PathSegment_getTypeRepr.ql linguist-generated
/test/extractor-tests/generated/Path/PathTypeRepr.ql linguist-generated /test/extractor-tests/generated/Path/PathTypeRepr.ql linguist-generated
/test/extractor-tests/generated/Path/PathTypeRepr_getPath.ql linguist-generated /test/extractor-tests/generated/Path/PathTypeRepr_getPath.ql linguist-generated
/test/extractor-tests/generated/Path/Path_getPart.ql linguist-generated
/test/extractor-tests/generated/Path/Path_getQualifier.ql linguist-generated /test/extractor-tests/generated/Path/Path_getQualifier.ql linguist-generated
/test/extractor-tests/generated/Path/Path_getSegment.ql linguist-generated
/test/extractor-tests/generated/PrefixExpr/PrefixExpr.ql linguist-generated /test/extractor-tests/generated/PrefixExpr/PrefixExpr.ql linguist-generated
/test/extractor-tests/generated/PrefixExpr/PrefixExpr_getAttr.ql linguist-generated /test/extractor-tests/generated/PrefixExpr/PrefixExpr_getAttr.ql linguist-generated
/test/extractor-tests/generated/PrefixExpr/PrefixExpr_getExpr.ql linguist-generated /test/extractor-tests/generated/PrefixExpr/PrefixExpr_getExpr.ql linguist-generated

View File

@@ -32,14 +32,14 @@ module Impl {
result = "...::" result = "...::"
or or
index = 1 and index = 1 and
result = this.getPart().toAbbreviatedString() result = this.getSegment().toAbbreviatedString()
} }
/** /**
* Gets the text of this path, if it exists. * Gets the text of this path, if it exists.
*/ */
pragma[nomagic] pragma[nomagic]
string getText() { result = this.getPart().getNameRef().getText() } string getText() { result = this.getSegment().getNameRef().getText() }
} }
/** A simple identifier path. */ /** A simple identifier path. */
@@ -49,7 +49,7 @@ module Impl {
IdentPath() { IdentPath() {
not this.hasQualifier() and not this.hasQualifier() and
exists(PathSegment ps | exists(PathSegment ps |
ps = this.getPart() and ps = this.getSegment() and
not ps.hasGenericArgList() and not ps.hasGenericArgList() and
not ps.hasParenthesizedArgList() and not ps.hasParenthesizedArgList() and
not ps.hasTypeRepr() and not ps.hasTypeRepr() and

View File

@@ -809,12 +809,12 @@ private module Impl {
} }
private Element getImmediateChildOfPath(Path e, int index, string partialPredicateCall) { private Element getImmediateChildOfPath(Path e, int index, string partialPredicateCall) {
exists(int b, int bAstNode, int n, int nQualifier, int nPart | exists(int b, int bAstNode, int n, int nQualifier, int nSegment |
b = 0 and b = 0 and
bAstNode = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfAstNode(e, i, _)) | i) and bAstNode = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfAstNode(e, i, _)) | i) and
n = bAstNode and n = bAstNode and
nQualifier = n + 1 and nQualifier = n + 1 and
nPart = nQualifier + 1 and nSegment = nQualifier + 1 and
( (
none() none()
or or
@@ -822,7 +822,7 @@ private module Impl {
or or
index = n and result = e.getQualifier() and partialPredicateCall = "Qualifier()" index = n and result = e.getQualifier() and partialPredicateCall = "Qualifier()"
or or
index = nQualifier and result = e.getPart() and partialPredicateCall = "Part()" index = nQualifier and result = e.getSegment() and partialPredicateCall = "Segment()"
) )
) )
} }

View File

@@ -42,15 +42,16 @@ module Generated {
final predicate hasQualifier() { exists(this.getQualifier()) } final predicate hasQualifier() { exists(this.getQualifier()) }
/** /**
* Gets the part of this path, if it exists. * Gets the last segment of this path, if it exists.
*/ */
PathSegment getPart() { PathSegment getSegment() {
result = Synth::convertPathSegmentFromRaw(Synth::convertPathToRaw(this).(Raw::Path).getPart()) result =
Synth::convertPathSegmentFromRaw(Synth::convertPathToRaw(this).(Raw::Path).getSegment())
} }
/** /**
* Holds if `getPart()` exists. * Holds if `getSegment()` exists.
*/ */
final predicate hasPart() { exists(this.getPart()) } final predicate hasSegment() { exists(this.getSegment()) }
} }
} }

View File

@@ -721,9 +721,9 @@ module Raw {
Path getQualifier() { path_qualifiers(this, result) } Path getQualifier() { path_qualifiers(this, result) }
/** /**
* Gets the part of this path, if it exists. * Gets the last segment of this path, if it exists.
*/ */
PathSegment getPart() { path_parts(this, result) } PathSegment getSegment() { path_segments_(this, result) }
} }
/** /**

View File

@@ -31,14 +31,14 @@ class StreamCipherInit extends Cryptography::CryptographicOperation::Range {
rawAlgorithmName = rawAlgorithmName =
p.getPath() p.getPath()
.getQualifier() .getQualifier()
.getPart() .getSegment()
.getGenericArgList() .getGenericArgList()
.getGenericArg(0) .getGenericArg(0)
.(TypeArg) .(TypeArg)
.getTypeRepr() .getTypeRepr()
.(PathTypeRepr) .(PathTypeRepr)
.getPath() .getPath()
.getPart() .getSegment()
.getNameRef() .getNameRef()
.getText() .getText()
) and ) and

View File

@@ -378,7 +378,7 @@ class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
pragma[nomagic] pragma[nomagic]
private TypeRepr getASelfTyArg() { private TypeRepr getASelfTyArg() {
result = result =
this.getSelfPath().getPart().getGenericArgList().getAGenericArg().(TypeArg).getTypeRepr() this.getSelfPath().getSegment().getGenericArgList().getAGenericArg().(TypeArg).getTypeRepr()
} }
/** /**

View File

@@ -240,7 +240,7 @@ private Type inferImplicitSelfType(SelfParam self, TypePath path) {
*/ */
private TypeMention getExplicitTypeArgMention(Path path, TypeParam tp) { private TypeMention getExplicitTypeArgMention(Path path, TypeParam tp) {
exists(int i | exists(int i |
result = path.getPart().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and result = path.getSegment().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and
tp = resolvePath(path).getTypeParam(pragma[only_bind_into](i)) tp = resolvePath(path).getTypeParam(pragma[only_bind_into](i))
) )
or or

View File

@@ -78,7 +78,7 @@ class TypeReprMention extends TypeMention, TypeRepr {
class PathMention extends TypeMention, Path { class PathMention extends TypeMention, Path {
override TypeMention getTypeArgument(int i) { override TypeMention getTypeArgument(int i) {
result = this.getPart().getGenericArgList().getTypeArg(i) result = this.getSegment().getGenericArgList().getTypeArg(i)
or or
// `Self` paths inside traits and `impl` blocks have implicit type arguments // `Self` paths inside traits and `impl` blocks have implicit type arguments
// that are the type parameters of the trait or impl. For example, in // that are the type parameters of the trait or impl. For example, in
@@ -93,7 +93,7 @@ class PathMention extends TypeMention, Path {
// //
// the `Self` return type is shorthand for `Foo<T>`. // the `Self` return type is shorthand for `Foo<T>`.
exists(ImplOrTraitItemNode node | this = node.getASelfPath() | exists(ImplOrTraitItemNode node | this = node.getASelfPath() |
result = node.(ImplItemNode).getSelfPath().getPart().getGenericArgList().getTypeArg(i) result = node.(ImplItemNode).getSelfPath().getSegment().getGenericArgList().getTypeArg(i)
or or
result = node.(Trait).getGenericParamList().getTypeParam(i) result = node.(Trait).getGenericParamList().getTypeParam(i)
) )
@@ -140,7 +140,7 @@ private predicate isImplSelfTypeParam(
) { ) {
exists(PathMention path | exists(PathMention path |
selfPath = impl.getSelfPath() and selfPath = impl.getSelfPath() and
path = selfPath.getPart().getGenericArgList().getTypeArg(i).(PathTypeRepr).getPath() and path = selfPath.getSegment().getGenericArgList().getTypeArg(i).(PathTypeRepr).getPath() and
tp = path.resolveType() tp = path.resolveType()
) )
} }

View File

@@ -63,7 +63,7 @@ private class RegexInjectionDefaultBarrier extends RegexInjectionBarrier {
.getFunction() .getFunction()
.(PathExpr) .(PathExpr)
.getPath() .getPath()
.getPart() .getSegment()
.getNameRef() .getNameRef()
.getText() = "escape" .getText() = "escape"
} }

View File

@@ -772,9 +772,9 @@ path_qualifiers(
); );
#keyset[id] #keyset[id]
path_parts( path_segments_(
int id: @path ref, int id: @path ref,
int part: @path_segment ref int segment: @path_segment ref
); );
path_segments( path_segments(

View File

@@ -1,25 +1,25 @@
| gen_path.rs:5:9:5:18 | some_crate | hasQualifier: | no | hasPart: | yes | | gen_path.rs:5:9:5:18 | some_crate | hasQualifier: | no | hasSegment: | yes |
| gen_path.rs:5:9:5:31 | ...::some_module | hasQualifier: | yes | hasPart: | yes | | gen_path.rs:5:9:5:31 | ...::some_module | hasQualifier: | yes | hasSegment: | yes |
| gen_path.rs:5:9:5:42 | ...::some_item | hasQualifier: | yes | hasPart: | yes | | gen_path.rs:5:9:5:42 | ...::some_item | hasQualifier: | yes | hasSegment: | yes |
| gen_path.rs:6:5:6:7 | foo | hasQualifier: | no | hasPart: | yes | | gen_path.rs:6:5:6:7 | foo | hasQualifier: | no | hasSegment: | yes |
| gen_path.rs:6:5:6:12 | ...::bar | hasQualifier: | yes | hasPart: | yes | | gen_path.rs:6:5:6:12 | ...::bar | hasQualifier: | yes | hasSegment: | yes |
| gen_path_expr.rs:5:13:5:20 | variable | hasQualifier: | no | hasPart: | yes | | gen_path_expr.rs:5:13:5:20 | variable | hasQualifier: | no | hasSegment: | yes |
| gen_path_expr.rs:6:13:6:15 | foo | hasQualifier: | no | hasPart: | yes | | gen_path_expr.rs:6:13:6:15 | foo | hasQualifier: | no | hasSegment: | yes |
| gen_path_expr.rs:6:13:6:20 | ...::bar | hasQualifier: | yes | hasPart: | yes | | gen_path_expr.rs:6:13:6:20 | ...::bar | hasQualifier: | yes | hasSegment: | yes |
| gen_path_expr.rs:7:13:7:15 | <...> | hasQualifier: | no | hasPart: | yes | | gen_path_expr.rs:7:13:7:15 | <...> | hasQualifier: | no | hasSegment: | yes |
| gen_path_expr.rs:7:13:7:20 | ...::foo | hasQualifier: | yes | hasPart: | yes | | gen_path_expr.rs:7:13:7:20 | ...::foo | hasQualifier: | yes | hasSegment: | yes |
| gen_path_expr.rs:7:14:7:14 | T | hasQualifier: | no | hasPart: | yes | | gen_path_expr.rs:7:14:7:14 | T | hasQualifier: | no | hasSegment: | yes |
| gen_path_expr.rs:8:13:8:31 | <...> | hasQualifier: | no | hasPart: | yes | | gen_path_expr.rs:8:13:8:31 | <...> | hasQualifier: | no | hasSegment: | yes |
| gen_path_expr.rs:8:13:8:36 | ...::foo | hasQualifier: | yes | hasPart: | yes | | gen_path_expr.rs:8:13:8:36 | ...::foo | hasQualifier: | yes | hasSegment: | yes |
| gen_path_expr.rs:8:14:8:21 | TypeRepr | hasQualifier: | no | hasPart: | yes | | gen_path_expr.rs:8:14:8:21 | TypeRepr | hasQualifier: | no | hasSegment: | yes |
| gen_path_expr.rs:8:26:8:30 | Trait | hasQualifier: | no | hasPart: | yes | | gen_path_expr.rs:8:26:8:30 | Trait | hasQualifier: | no | hasSegment: | yes |
| gen_path_pat.rs:5:11:5:11 | x | hasQualifier: | no | hasPart: | yes | | gen_path_pat.rs:5:11:5:11 | x | hasQualifier: | no | hasSegment: | yes |
| gen_path_pat.rs:6:9:6:11 | Foo | hasQualifier: | no | hasPart: | yes | | gen_path_pat.rs:6:9:6:11 | Foo | hasQualifier: | no | hasSegment: | yes |
| gen_path_pat.rs:6:9:6:16 | ...::Bar | hasQualifier: | yes | hasPart: | yes | | gen_path_pat.rs:6:9:6:16 | ...::Bar | hasQualifier: | yes | hasSegment: | yes |
| gen_path_type_repr.rs:5:14:5:16 | std | hasQualifier: | no | hasPart: | yes | | gen_path_type_repr.rs:5:14:5:16 | std | hasQualifier: | no | hasSegment: | yes |
| gen_path_type_repr.rs:5:14:5:29 | ...::collections | hasQualifier: | yes | hasPart: | yes | | gen_path_type_repr.rs:5:14:5:29 | ...::collections | hasQualifier: | yes | hasSegment: | yes |
| gen_path_type_repr.rs:5:14:5:48 | ...::HashMap::<...> | hasQualifier: | yes | hasPart: | yes | | gen_path_type_repr.rs:5:14:5:48 | ...::HashMap::<...> | hasQualifier: | yes | hasSegment: | yes |
| gen_path_type_repr.rs:5:40:5:42 | i32 | hasQualifier: | no | hasPart: | yes | | gen_path_type_repr.rs:5:40:5:42 | i32 | hasQualifier: | no | hasSegment: | yes |
| gen_path_type_repr.rs:5:45:5:47 | i32 | hasQualifier: | no | hasPart: | yes | | gen_path_type_repr.rs:5:45:5:47 | i32 | hasQualifier: | no | hasSegment: | yes |
| gen_path_type_repr.rs:6:14:6:14 | X | hasQualifier: | no | hasPart: | yes | | gen_path_type_repr.rs:6:14:6:14 | X | hasQualifier: | no | hasSegment: | yes |
| gen_path_type_repr.rs:6:14:6:20 | ...::Item | hasQualifier: | yes | hasPart: | yes | | gen_path_type_repr.rs:6:14:6:20 | ...::Item | hasQualifier: | yes | hasSegment: | yes |

View File

@@ -2,10 +2,10 @@
import codeql.rust.elements import codeql.rust.elements
import TestUtils import TestUtils
from Path x, string hasQualifier, string hasPart from Path x, string hasQualifier, string hasSegment
where where
toBeTested(x) and toBeTested(x) and
not x.isUnknown() and not x.isUnknown() and
(if x.hasQualifier() then hasQualifier = "yes" else hasQualifier = "no") and (if x.hasQualifier() then hasQualifier = "yes" else hasQualifier = "no") and
if x.hasPart() then hasPart = "yes" else hasPart = "no" if x.hasSegment() then hasSegment = "yes" else hasSegment = "no"
select x, "hasQualifier:", hasQualifier, "hasPart:", hasPart select x, "hasQualifier:", hasQualifier, "hasSegment:", hasSegment

View File

@@ -0,0 +1,25 @@
| gen_path.rs:5:9:5:18 | some_crate | gen_path.rs:5:9:5:18 | some_crate |
| gen_path.rs:5:9:5:31 | ...::some_module | gen_path.rs:5:21:5:31 | some_module |
| gen_path.rs:5:9:5:42 | ...::some_item | gen_path.rs:5:34:5:42 | some_item |
| gen_path.rs:6:5:6:7 | foo | gen_path.rs:6:5:6:7 | foo |
| gen_path.rs:6:5:6:12 | ...::bar | gen_path.rs:6:10:6:12 | bar |
| gen_path_expr.rs:5:13:5:20 | variable | gen_path_expr.rs:5:13:5:20 | variable |
| gen_path_expr.rs:6:13:6:15 | foo | gen_path_expr.rs:6:13:6:15 | foo |
| gen_path_expr.rs:6:13:6:20 | ...::bar | gen_path_expr.rs:6:18:6:20 | bar |
| gen_path_expr.rs:7:13:7:15 | <...> | gen_path_expr.rs:7:13:7:15 | <...> |
| gen_path_expr.rs:7:13:7:20 | ...::foo | gen_path_expr.rs:7:18:7:20 | foo |
| gen_path_expr.rs:7:14:7:14 | T | gen_path_expr.rs:7:14:7:14 | T |
| gen_path_expr.rs:8:13:8:31 | <...> | gen_path_expr.rs:8:13:8:31 | <...> |
| gen_path_expr.rs:8:13:8:36 | ...::foo | gen_path_expr.rs:8:34:8:36 | foo |
| gen_path_expr.rs:8:14:8:21 | TypeRepr | gen_path_expr.rs:8:14:8:21 | TypeRepr |
| gen_path_expr.rs:8:26:8:30 | Trait | gen_path_expr.rs:8:26:8:30 | Trait |
| gen_path_pat.rs:5:11:5:11 | x | gen_path_pat.rs:5:11:5:11 | x |
| gen_path_pat.rs:6:9:6:11 | Foo | gen_path_pat.rs:6:9:6:11 | Foo |
| gen_path_pat.rs:6:9:6:16 | ...::Bar | gen_path_pat.rs:6:14:6:16 | Bar |
| gen_path_type_repr.rs:5:14:5:16 | std | gen_path_type_repr.rs:5:14:5:16 | std |
| gen_path_type_repr.rs:5:14:5:29 | ...::collections | gen_path_type_repr.rs:5:19:5:29 | collections |
| gen_path_type_repr.rs:5:14:5:48 | ...::HashMap::<...> | gen_path_type_repr.rs:5:32:5:48 | HashMap::<...> |
| gen_path_type_repr.rs:5:40:5:42 | i32 | gen_path_type_repr.rs:5:40:5:42 | i32 |
| gen_path_type_repr.rs:5:45:5:47 | i32 | gen_path_type_repr.rs:5:45:5:47 | i32 |
| gen_path_type_repr.rs:6:14:6:14 | X | gen_path_type_repr.rs:6:14:6:14 | X |
| gen_path_type_repr.rs:6:14:6:20 | ...::Item | gen_path_type_repr.rs:6:17:6:20 | Item |

View File

@@ -4,4 +4,4 @@ import TestUtils
from Path x from Path x
where toBeTested(x) and not x.isUnknown() where toBeTested(x) and not x.isUnknown()
select x, x.getPart() select x, x.getSegment()

View File

@@ -87,6 +87,7 @@ class _:
foo::bar; foo::bar;
``` ```
""" """
segment: _ | ql.db_table_name("path_segments_") | doc("last segment of this path")
@annotate(GenericArgList) @annotate(GenericArgList)

2
rust/schema/ast.py generated
View File

@@ -482,7 +482,7 @@ class ParenthesizedArgList(AstNode, ):
class Path(AstNode, ): class Path(AstNode, ):
qualifier: optional["Path"] | child qualifier: optional["Path"] | child
part: optional["PathSegment"] | child segment: optional["PathSegment"] | child
class PathExpr(Expr, ): class PathExpr(Expr, ):
attrs: list["Attr"] | child attrs: list["Attr"] | child