diff --git a/.bazelrc b/.bazelrc index 71c954c2b0b..449345bfb62 100644 --- a/.bazelrc +++ b/.bazelrc @@ -37,5 +37,6 @@ build --java_language_version=17 build --tool_java_language_version=17 build --tool_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 diff --git a/.bazelrc.internal b/.bazelrc.internal index f7718959c9d..245cd98fbd8 100644 --- a/.bazelrc.internal +++ b/.bazelrc.internal @@ -8,3 +8,5 @@ common --registry=https://bcr.bazel.build # its implementation packages without providing any code itself. # We either can depend on internal implementation details, or turn of strict deps. common --@rules_dotnet//dotnet/settings:strict_deps=false + +build --@rules_python//python/config_settings:python_version=3.12 diff --git a/MODULE.bazel b/MODULE.bazel index ce3aa32cb76..fe418cd40c6 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -155,7 +155,7 @@ use_repo(csharp_main_extension, "paket.main") pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") pip.parse( hub_name = "codegen_deps", - python_version = "3.11", + python_version = "3.12", requirements_lock = "//misc/codegen:requirements_lock.txt", ) use_repo(pip, "codegen_deps") diff --git a/misc/codegen/.python-version b/misc/codegen/.python-version index 2c0733315e4..e4fba218358 100644 --- a/misc/codegen/.python-version +++ b/misc/codegen/.python-version @@ -1 +1 @@ -3.11 +3.12 diff --git a/misc/codegen/generators/cppgen.py b/misc/codegen/generators/cppgen.py index de53b771d35..1a9a64663c1 100644 --- a/misc/codegen/generators/cppgen.py +++ b/misc/codegen/generators/cppgen.py @@ -37,12 +37,19 @@ def _get_type(t: str, add_or_none_except: typing.Optional[str] = None) -> str: 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: - 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( field_name=p.name + ("_" if p.name in cpp.cpp_keywords else ""), 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_predicate=p.is_predicate, is_unordered=p.is_unordered, - trap_name=trap_name, + trap_name=_get_trap_name(cls, p), ) args.update(cpp.get_field_override(p.name)) return cpp.Field(**args) diff --git a/misc/codegen/generators/dbschemegen.py b/misc/codegen/generators/dbschemegen.py index e2cc4220dc7..f861972cdd6 100755 --- a/misc/codegen/generators/dbschemegen.py +++ b/misc/codegen/generators/dbschemegen.py @@ -24,6 +24,10 @@ from misc.codegen.lib.dbscheme import * log = logging.getLogger(__name__) +class Error(Exception): + pass + + 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. 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 for f in cls.properties: + overridden_table_name = f.pragmas.get("ql_db_table_name") if f.synth: continue if f.is_unordered: yield Table( - name=inflection.tableize(f"{cls.name}_{f.name}"), + name=overridden_table_name or inflection.tableize(f"{cls.name}_{f.name}"), columns=[ Column("id", type=dbtype(cls.name)), 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: yield Table( 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=[ Column("id", type=dbtype(cls.name)), 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: yield Table( keyset=KeySet(["id"]), - name=inflection.tableize(f"{cls.name}_{f.name}"), + name=overridden_table_name or inflection.tableize(f"{cls.name}_{f.name}"), columns=[ Column("id", type=dbtype(cls.name)), 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: yield Table( keyset=KeySet(["id"]), - name=inflection.underscore(f"{cls.name}_{f.name}"), + name=overridden_table_name or inflection.underscore(f"{cls.name}_{f.name}"), columns=[ 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): 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, @@ -120,6 +136,7 @@ def get_declarations(data: schema.Schema): declarations += [ Union(dbtype(t, data.null), [dbtype(t), dbtype(data.null)]) for t in sorted(property_classes) ] + check_name_conflicts(declarations) return declarations diff --git a/misc/codegen/generators/qlgen.py b/misc/codegen/generators/qlgen.py index 5cdc16a8af5..eefcad3e943 100755 --- a/misc/codegen/generators/qlgen.py +++ b/misc/codegen/generators/qlgen.py @@ -130,6 +130,9 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, lookup: typing.Dic internal="ql_internal" in prop.pragmas, ) 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: args.update( singular=inflection.camelize(ql_name), @@ -141,7 +144,7 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, lookup: typing.Dic args.update( singular=inflection.singularize(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"], doc=_get_doc(cls, prop, plural=False), 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: args.update( 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"], doc=_get_doc(cls, prop), ) elif prop.is_predicate: args.update( 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"], doc=_get_doc(cls, prop), ) diff --git a/misc/codegen/generators/rustgen.py b/misc/codegen/generators/rustgen.py index 38d2ae55d44..d7025830bcb 100644 --- a/misc/codegen/generators/rustgen.py +++ b/misc/codegen/generators/rustgen.py @@ -27,14 +27,20 @@ def _get_type(t: str) -> str: 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: - 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( field_name=rust.avoid_keywords(p.name), 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_predicate=p.is_predicate, is_unordered=p.is_unordered, - table_name=table_name, + table_name=_get_table_name(cls, p), ) args.update(rust.get_field_override(p.name)) return rust.Field(**args) diff --git a/misc/codegen/lib/schemadefs.py b/misc/codegen/lib/schemadefs.py index c81b2f2e215..b0cf2b038a8 100644 --- a/misc/codegen/lib/schemadefs.py +++ b/misc/codegen/lib/schemadefs.py @@ -2,8 +2,9 @@ from typing import ( Callable as _Callable, Dict as _Dict, Iterable as _Iterable, - ClassVar as _ClassVar, + Union as _Union, ) +from copy import deepcopy as _deepcopy from misc.codegen.lib import schema as _schema import inspect as _inspect from dataclasses import dataclass as _dataclass @@ -75,7 +76,7 @@ class _Namespace: """ simple namespacing mechanism """ _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 pragma.pragma = key or f"{self._name}_{pragma.pragma}" @@ -101,6 +102,10 @@ synth = _SynthModifier("synth") @_dataclass class _PragmaBase: pragma: str + value: object = None + + def _apply(self, pragmas: _Dict[str, object]) -> None: + pragmas[self.pragma] = self.value @_dataclass @@ -109,7 +114,6 @@ class _ClassPragma(_PragmaBase): For schema classes it acts as a python decorator with `@`. """ inherited: bool = False - value: object = None def __call__(self, cls: type) -> type: """ use this pragma as a decorator on classes """ @@ -122,15 +126,11 @@ class _ClassPragma(_PragmaBase): self._apply(cls._pragmas) return cls - def _apply(self, pragmas: _Dict[str, object]) -> None: - pragmas[self.pragma] = self.value - @_dataclass -class _Pragma(_ClassPragma, _schema.PropertyModifier): - """ A class or property pragma. - For properties, it functions similarly to a `_PropertyModifier` with `|`, adding the pragma. - For schema classes it acts as a python decorator with `@`. +class _PropertyPragma(_PragmaBase, _schema.PropertyModifier): + """ A property pragma. + It functions similarly to a `_PropertyModifier` with `|`, adding the pragma. """ remove: bool = False @@ -138,7 +138,7 @@ class _Pragma(_ClassPragma, _schema.PropertyModifier): self._apply(prop.pragmas) 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: if self.remove: @@ -148,31 +148,38 @@ class _Pragma(_ClassPragma, _schema.PropertyModifier): @_dataclass -class _ParametrizedClassPragma(_PragmaBase): - """ A class parametrized pragma. - Needs to be applied to a parameter to give a class pragma. +class _Pragma(_ClassPragma, _PropertyPragma): + """ A class or property 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 _ParametrizedPragma(_ParametrizedClassPragma): - """ A class or property parametrized pragma. +class _Parametrized[P, **Q, T]: + """ A parametrized pragma. Needs to be applied to a parameter to give a pragma. """ - _pragma_class: _ClassVar[type] = _Pragma - def __invert__(self) -> _Pragma: - return _Pragma(self.pragma, remove=True) + def __init__(self, pragma_instance: P, factory: _Callable[Q, T]): + 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): @@ -232,30 +239,31 @@ desc = _DescModifier use_for_null = _ClassPragma("null") -qltest.add(_Pragma("skip")) +qltest.add(_ClassPragma("skip")) qltest.add(_ClassPragma("collapse_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(_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")) -rust.add(_Pragma("detach")) +rust.add(_PropertyPragma("detach")) 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") -synth.add(_ParametrizedClassPragma("on_arguments", factory=lambda **kwargs: - _schema.SynthInfo(on_arguments={k: _schema.get_type_name(t) for k, t in kwargs.items()})), key="synth") +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") @_dataclass(frozen=True) diff --git a/misc/codegen/requirements_lock.txt b/misc/codegen/requirements_lock.txt index f0ae5d82ba7..d29fbd56076 100644 --- a/misc/codegen/requirements_lock.txt +++ b/misc/codegen/requirements_lock.txt @@ -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: # # 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 iniconfig==2.0.0 # via pytest -packaging==23.2 +packaging==24.2 # via pytest -pluggy==1.4.0 +pluggy==1.5.0 # via pytest -pystache==0.6.5 +pystache==0.6.8 # via -r misc/codegen/requirements_in.txt -pytest==8.0.0 +pytest==8.3.5 # via -r misc/codegen/requirements_in.txt -pyyaml==6.0.1 +pyyaml==6.0.2 # via -r misc/codegen/requirements_in.txt toposort==1.10 # via -r misc/codegen/requirements_in.txt diff --git a/misc/codegen/test/test_cppgen.py b/misc/codegen/test/test_cppgen.py index fea9be2037f..06394032241 100644 --- a/misc/codegen/test/test_cppgen.py +++ b/misc/codegen/test/test_cppgen.py @@ -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__': sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/misc/codegen/test/test_dbschemegen.py b/misc/codegen/test/test_dbschemegen.py index 96a6b0d0f7f..653ad7fc8a3 100644 --- a/misc/codegen/test/test_dbschemegen.py +++ b/misc/codegen/test/test_dbschemegen.py @@ -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__': sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/misc/codegen/test/test_qlgen.py b/misc/codegen/test/test_qlgen.py index 431f25d5aae..01dee251999 100644 --- a/misc/codegen/test/test_qlgen.py +++ b/misc/codegen/test/test_qlgen.py @@ -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__': sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/misc/codegen/test/test_schemaloader.py b/misc/codegen/test/test_schemaloader.py index 6c6fccfb3ea..1c8bfba271b 100644 --- a/misc/codegen/test/test_schemaloader.py +++ b/misc/codegen/test/test_schemaloader.py @@ -272,10 +272,10 @@ def test_builtin_predicate_and_set_children_not_allowed(spec): _class_pragmas = [ (defs.qltest.collapse_hierarchy, "qltest_collapse_hierarchy"), (defs.qltest.uncollapse_hierarchy, "qltest_uncollapse_hierarchy"), + (defs.qltest.skip, "qltest_skip"), ] _property_pragmas = [ - (defs.qltest.skip, "qltest_skip"), (defs.cpp.skip, "cpp_skip"), (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(): @load class data: @@ -838,7 +849,7 @@ def test_annotate_fields_negations(): @load class data: 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") z: defs.string | defs.synth | defs.doc("foo") @@ -850,7 +861,7 @@ def test_annotate_fields_negations(): assert data.classes == { "Root": schema.Class("Root", properties=[ - schema.SingleProperty("x", "int", pragmas=["qltest_skip"]), + schema.SingleProperty("x", "int"), schema.OptionalProperty("y", "Root"), schema.SingleProperty("z", "string"), ]), diff --git a/rust/ast-generator/src/main.rs b/rust/ast-generator/src/main.rs index 9616ee8ba01..4b5cd6506cd 100644 --- a/rust/ast-generator/src/main.rs +++ b/rust/ast-generator/src/main.rs @@ -36,7 +36,6 @@ fn property_name(type_name: &str, field_name: &str) -> String { ("CallExpr", "expr") => "function", ("LetExpr", "expr") => "scrutinee", ("MatchExpr", "expr") => "scrutinee", - ("Path", "segment") => "part", (_, "then_branch") => "then", (_, "else_branch") => "else_", ("ArrayType", "ty") => "element_type_repr", diff --git a/rust/extractor/src/crate_graph.rs b/rust/extractor/src/crate_graph.rs index fa8cb657db9..976c60abc8b 100644 --- a/rust/extractor/src/crate_graph.rs +++ b/rust/extractor/src/crate_graph.rs @@ -1004,7 +1004,7 @@ fn make_qualified_path( id: trap::TrapId::Star, text: Some(name), })); - let part = Some(trap.emit(generated::PathSegment { + let segment = Some(trap.emit(generated::PathSegment { id: trap::TrapId::Star, generic_arg_list: None, name_ref, @@ -1015,7 +1015,7 @@ fn make_qualified_path( trap.emit(generated::Path { id: trap::TrapId::Star, qualifier, - part, + segment, }) } path.into_iter() diff --git a/rust/extractor/src/generated/.generated.list b/rust/extractor/src/generated/.generated.list index a014ae1c110..3c520983a6c 100644 --- a/rust/extractor/src/generated/.generated.list +++ b/rust/extractor/src/generated/.generated.list @@ -1,2 +1,2 @@ mod.rs 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7 -top.rs fcff2f1d468e6bc5384e5c0d7f3249773fa3ef38db054c0ec555c43d143117da fcff2f1d468e6bc5384e5c0d7f3249773fa3ef38db054c0ec555c43d143117da +top.rs 49e4f3abb137d6eed5a7c5202b3a31c9cafa1f565ee63dd5960e971950fafaa1 49e4f3abb137d6eed5a7c5202b3a31c9cafa1f565ee63dd5960e971950fafaa1 diff --git a/rust/extractor/src/generated/top.rs b/rust/extractor/src/generated/top.rs index e9604e08387..a49cae61ade 100644 --- a/rust/extractor/src/generated/top.rs +++ b/rust/extractor/src/generated/top.rs @@ -2027,7 +2027,7 @@ impl From> for trap::Label { pub struct Path { pub id: trap::TrapId, pub qualifier: Option>, - pub part: Option>, + pub segment: Option>, } impl trap::TrapEntry for Path { @@ -2040,8 +2040,8 @@ impl trap::TrapEntry for Path { if let Some(v) = self.qualifier { out.add_tuple("path_qualifiers", vec![id.into(), v.into()]); } - if let Some(v) = self.part { - out.add_tuple("path_parts", vec![id.into(), v.into()]); + if let Some(v) = self.segment { + out.add_tuple("path_segments_", vec![id.into(), v.into()]); } } } diff --git a/rust/extractor/src/translate/generated.rs b/rust/extractor/src/translate/generated.rs index 9479f793961..25ae576d64c 100644 --- a/rust/extractor/src/translate/generated.rs +++ b/rust/extractor/src/translate/generated.rs @@ -1659,11 +1659,11 @@ impl Translator<'_> { pub(crate) fn emit_path(&mut self, node: ast::Path) -> Option> { 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 { id: TrapId::Star, qualifier, - part, + segment, }); self.emit_location(label, &node); emit_detached!(Path, self, node, label); diff --git a/rust/ql/.generated.list b/rust/ql/.generated.list index 89138a2b01b..b4a2eda0cbb 100644 --- a/rust/ql/.generated.list +++ b/rust/ql/.generated.list @@ -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/ParenPat.qll 4f168ef5d5bb87a903251cc31b2e44a759b099ec69c90af31783fbb15778c940 0e34f94a45a13396fd57d94c245dc64d1adde2ab0e22b56946f7e94c04e297fc 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/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/PathExpr.qll 34ebad4d062ce8b7e517f2ab09d52745fb8455203f4a936df7284ad296638387 ba66781cdbdeb89c27a4bfb2be0f27f85fb34978d699b4e343446fb0d7ad2aa6 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/RangeExpr.qll 23cca03bf43535f33b22a38894f70d669787be4e4f5b8fe5c8f7b964d30e9027 18624cef6c6b679eeace2a98737e472432e0ead354cca02192b4d45330f047c9 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/RefExpr.qll 7d995884e3dc1c25fc719f5d7253179344d63650e217e9ff6530285fe7a57f64 f2c3c12551deea4964b66553fb9b6423ee16fec53bd63db4796191aa60dc6c66 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_getTypeRepr.ql 64fe4ea708bc489ba64ed845f63cfbcd57c1179c57d95be309db37eac2f5eb71 0f4cbbfdf39d89830b5249cabf26d834fc2310b8a9579c19383c90cb4333afb7 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_getAttr.ql 2ccac48cd91d86670c1d2742de20344135d424e6f0e3dafcc059555046f92d92 9b7b5f5f9e3674fad9b3a5bcd3cabc0dff32a95640da0fce6f4d0eb931f1757d 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/PathTypeRepr.ql c2e069acc5111088a7287d98b4bd4bf44bd79c5a786b275f7448ebafc3613500 6e016750e5fef92a98bc5cc60bfd40d85fbb5eb2d251b4d69ffe600813f81df0 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_getSegment.ql 475f344ee24a14468745d50922fdfd63f5d817f14cc041a184c2f8ec144a01dd 4f663c5c2b1e0cb8b9a8a0b2d8b5d81f12a3bf333c71ecbb43d9258f7dfe4ec7 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_getExpr.ql 2d1d97f6277794871fbb032ea87ac30b1aa902a74cd874720156162057ea202e b1b9880fce07d66df7ec87f12189c37adf9f233a1d0b38a1b09808d052a95642 diff --git a/rust/ql/.gitattributes b/rust/ql/.gitattributes index 2c66ca19d95..804b88274a5 100644 --- a/rust/ql/.gitattributes +++ b/rust/ql/.gitattributes @@ -1008,8 +1008,8 @@ /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_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_getSegment.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_getExpr.ql linguist-generated diff --git a/rust/ql/lib/codeql/rust/elements/internal/PathImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/PathImpl.qll index 285b423331d..0ff11175b2c 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/PathImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/PathImpl.qll @@ -32,14 +32,14 @@ module Impl { result = "...::" or index = 1 and - result = this.getPart().toAbbreviatedString() + result = this.getSegment().toAbbreviatedString() } /** * Gets the text of this path, if it exists. */ pragma[nomagic] - string getText() { result = this.getPart().getNameRef().getText() } + string getText() { result = this.getSegment().getNameRef().getText() } } /** A simple identifier path. */ @@ -49,7 +49,7 @@ module Impl { IdentPath() { not this.hasQualifier() and exists(PathSegment ps | - ps = this.getPart() and + ps = this.getSegment() and not ps.hasGenericArgList() and not ps.hasParenthesizedArgList() and not ps.hasTypeRepr() and diff --git a/rust/ql/lib/codeql/rust/elements/internal/generated/ParentChild.qll b/rust/ql/lib/codeql/rust/elements/internal/generated/ParentChild.qll index fa00fe88ddc..cd76b6846ce 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/generated/ParentChild.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/generated/ParentChild.qll @@ -809,12 +809,12 @@ private module Impl { } 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 bAstNode = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfAstNode(e, i, _)) | i) and n = bAstNode and nQualifier = n + 1 and - nPart = nQualifier + 1 and + nSegment = nQualifier + 1 and ( none() or @@ -822,7 +822,7 @@ private module Impl { or index = n and result = e.getQualifier() and partialPredicateCall = "Qualifier()" or - index = nQualifier and result = e.getPart() and partialPredicateCall = "Part()" + index = nQualifier and result = e.getSegment() and partialPredicateCall = "Segment()" ) ) } diff --git a/rust/ql/lib/codeql/rust/elements/internal/generated/Path.qll b/rust/ql/lib/codeql/rust/elements/internal/generated/Path.qll index 5cb827c3357..60248dc9d30 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/generated/Path.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/generated/Path.qll @@ -42,15 +42,16 @@ module Generated { 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() { - result = Synth::convertPathSegmentFromRaw(Synth::convertPathToRaw(this).(Raw::Path).getPart()) + PathSegment getSegment() { + 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()) } } } diff --git a/rust/ql/lib/codeql/rust/elements/internal/generated/Raw.qll b/rust/ql/lib/codeql/rust/elements/internal/generated/Raw.qll index 3ff1e0c2ae8..2258b810da3 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/generated/Raw.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/generated/Raw.qll @@ -721,9 +721,9 @@ module Raw { 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) } } /** diff --git a/rust/ql/lib/codeql/rust/frameworks/rustcrypto/RustCrypto.qll b/rust/ql/lib/codeql/rust/frameworks/rustcrypto/RustCrypto.qll index 18ece8b2408..c043cbf6033 100644 --- a/rust/ql/lib/codeql/rust/frameworks/rustcrypto/RustCrypto.qll +++ b/rust/ql/lib/codeql/rust/frameworks/rustcrypto/RustCrypto.qll @@ -31,14 +31,14 @@ class StreamCipherInit extends Cryptography::CryptographicOperation::Range { rawAlgorithmName = p.getPath() .getQualifier() - .getPart() + .getSegment() .getGenericArgList() .getGenericArg(0) .(TypeArg) .getTypeRepr() .(PathTypeRepr) .getPath() - .getPart() + .getSegment() .getNameRef() .getText() ) and diff --git a/rust/ql/lib/codeql/rust/internal/PathResolution.qll b/rust/ql/lib/codeql/rust/internal/PathResolution.qll index 169e3c365b0..bd98bf6ec03 100644 --- a/rust/ql/lib/codeql/rust/internal/PathResolution.qll +++ b/rust/ql/lib/codeql/rust/internal/PathResolution.qll @@ -378,7 +378,7 @@ class ImplItemNode extends ImplOrTraitItemNode instanceof Impl { pragma[nomagic] private TypeRepr getASelfTyArg() { result = - this.getSelfPath().getPart().getGenericArgList().getAGenericArg().(TypeArg).getTypeRepr() + this.getSelfPath().getSegment().getGenericArgList().getAGenericArg().(TypeArg).getTypeRepr() } /** diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 6e74be7dc82..1e468edc5a7 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -240,7 +240,7 @@ private Type inferImplicitSelfType(SelfParam self, TypePath path) { */ private TypeMention getExplicitTypeArgMention(Path path, TypeParam tp) { 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)) ) or diff --git a/rust/ql/lib/codeql/rust/internal/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/TypeMention.qll index 7def62da554..f8fa7923f21 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeMention.qll @@ -78,7 +78,7 @@ class TypeReprMention extends TypeMention, TypeRepr { class PathMention extends TypeMention, Path { override TypeMention getTypeArgument(int i) { - result = this.getPart().getGenericArgList().getTypeArg(i) + result = this.getSegment().getGenericArgList().getTypeArg(i) or // `Self` paths inside traits and `impl` blocks have implicit type arguments // 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`. exists(ImplOrTraitItemNode node | this = node.getASelfPath() | - result = node.(ImplItemNode).getSelfPath().getPart().getGenericArgList().getTypeArg(i) + result = node.(ImplItemNode).getSelfPath().getSegment().getGenericArgList().getTypeArg(i) or result = node.(Trait).getGenericParamList().getTypeParam(i) ) @@ -140,7 +140,7 @@ private predicate isImplSelfTypeParam( ) { exists(PathMention path | 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() ) } diff --git a/rust/ql/lib/codeql/rust/security/regex/RegexInjectionExtensions.qll b/rust/ql/lib/codeql/rust/security/regex/RegexInjectionExtensions.qll index 5ab77b63b6a..ec0dfa56e1d 100644 --- a/rust/ql/lib/codeql/rust/security/regex/RegexInjectionExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/regex/RegexInjectionExtensions.qll @@ -63,7 +63,7 @@ private class RegexInjectionDefaultBarrier extends RegexInjectionBarrier { .getFunction() .(PathExpr) .getPath() - .getPart() + .getSegment() .getNameRef() .getText() = "escape" } diff --git a/rust/ql/lib/rust.dbscheme b/rust/ql/lib/rust.dbscheme index 89e67e90eec..d2c0bfa049f 100644 --- a/rust/ql/lib/rust.dbscheme +++ b/rust/ql/lib/rust.dbscheme @@ -772,9 +772,9 @@ path_qualifiers( ); #keyset[id] -path_parts( +path_segments_( int id: @path ref, - int part: @path_segment ref + int segment: @path_segment ref ); path_segments( diff --git a/rust/ql/test/extractor-tests/generated/Path/Path.expected b/rust/ql/test/extractor-tests/generated/Path/Path.expected index 4cda1d25932..7cf8362293e 100644 --- a/rust/ql/test/extractor-tests/generated/Path/Path.expected +++ b/rust/ql/test/extractor-tests/generated/Path/Path.expected @@ -1,25 +1,25 @@ -| gen_path.rs:5:9:5:18 | some_crate | hasQualifier: | no | hasPart: | yes | -| gen_path.rs:5:9:5:31 | ...::some_module | hasQualifier: | yes | hasPart: | yes | -| gen_path.rs:5:9:5:42 | ...::some_item | hasQualifier: | yes | hasPart: | yes | -| gen_path.rs:6:5:6:7 | foo | hasQualifier: | no | hasPart: | yes | -| gen_path.rs:6:5:6:12 | ...::bar | hasQualifier: | yes | hasPart: | yes | -| gen_path_expr.rs:5:13:5:20 | variable | hasQualifier: | no | hasPart: | yes | -| gen_path_expr.rs:6:13:6:15 | foo | hasQualifier: | no | hasPart: | yes | -| gen_path_expr.rs:6:13:6:20 | ...::bar | hasQualifier: | yes | hasPart: | yes | -| gen_path_expr.rs:7:13:7:15 | <...> | hasQualifier: | no | hasPart: | yes | -| gen_path_expr.rs:7:13:7:20 | ...::foo | hasQualifier: | yes | hasPart: | yes | -| gen_path_expr.rs:7:14:7:14 | T | hasQualifier: | no | hasPart: | yes | -| gen_path_expr.rs:8:13:8:31 | <...> | hasQualifier: | no | hasPart: | yes | -| gen_path_expr.rs:8:13:8:36 | ...::foo | hasQualifier: | yes | hasPart: | yes | -| gen_path_expr.rs:8:14:8:21 | TypeRepr | hasQualifier: | no | hasPart: | yes | -| gen_path_expr.rs:8:26:8:30 | Trait | hasQualifier: | no | hasPart: | yes | -| gen_path_pat.rs:5:11:5:11 | x | hasQualifier: | no | hasPart: | yes | -| gen_path_pat.rs:6:9:6:11 | Foo | hasQualifier: | no | hasPart: | yes | -| gen_path_pat.rs:6:9:6:16 | ...::Bar | hasQualifier: | yes | hasPart: | yes | -| gen_path_type_repr.rs:5:14:5:16 | std | hasQualifier: | no | hasPart: | yes | -| gen_path_type_repr.rs:5:14:5:29 | ...::collections | hasQualifier: | yes | hasPart: | yes | -| gen_path_type_repr.rs:5:14:5:48 | ...::HashMap::<...> | hasQualifier: | yes | hasPart: | yes | -| gen_path_type_repr.rs:5:40:5:42 | i32 | hasQualifier: | no | hasPart: | yes | -| gen_path_type_repr.rs:5:45:5:47 | i32 | hasQualifier: | no | hasPart: | yes | -| gen_path_type_repr.rs:6:14:6:14 | X | hasQualifier: | no | hasPart: | yes | -| gen_path_type_repr.rs:6:14:6:20 | ...::Item | hasQualifier: | yes | 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 | hasSegment: | yes | +| gen_path.rs:5:9:5:42 | ...::some_item | hasQualifier: | yes | hasSegment: | yes | +| gen_path.rs:6:5:6:7 | foo | hasQualifier: | no | hasSegment: | yes | +| gen_path.rs:6:5:6:12 | ...::bar | hasQualifier: | yes | hasSegment: | 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 | hasSegment: | yes | +| gen_path_expr.rs:6:13:6:20 | ...::bar | hasQualifier: | yes | hasSegment: | yes | +| gen_path_expr.rs:7:13:7:15 | <...> | hasQualifier: | no | hasSegment: | 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 | hasSegment: | yes | +| gen_path_expr.rs:8:13:8:31 | <...> | hasQualifier: | no | hasSegment: | 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 | hasSegment: | 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 | hasSegment: | 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 | hasSegment: | 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 | hasSegment: | 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 | hasSegment: | 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 | hasSegment: | yes | +| gen_path_type_repr.rs:6:14:6:20 | ...::Item | hasQualifier: | yes | hasSegment: | yes | diff --git a/rust/ql/test/extractor-tests/generated/Path/Path.ql b/rust/ql/test/extractor-tests/generated/Path/Path.ql index c5e1ba9d78a..2f32fa34147 100644 --- a/rust/ql/test/extractor-tests/generated/Path/Path.ql +++ b/rust/ql/test/extractor-tests/generated/Path/Path.ql @@ -2,10 +2,10 @@ import codeql.rust.elements import TestUtils -from Path x, string hasQualifier, string hasPart +from Path x, string hasQualifier, string hasSegment where toBeTested(x) and not x.isUnknown() and (if x.hasQualifier() then hasQualifier = "yes" else hasQualifier = "no") and - if x.hasPart() then hasPart = "yes" else hasPart = "no" -select x, "hasQualifier:", hasQualifier, "hasPart:", hasPart + if x.hasSegment() then hasSegment = "yes" else hasSegment = "no" +select x, "hasQualifier:", hasQualifier, "hasSegment:", hasSegment diff --git a/rust/ql/test/extractor-tests/generated/Path/Path_getSegment.expected b/rust/ql/test/extractor-tests/generated/Path/Path_getSegment.expected new file mode 100644 index 00000000000..54cad7249d6 --- /dev/null +++ b/rust/ql/test/extractor-tests/generated/Path/Path_getSegment.expected @@ -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 | diff --git a/rust/ql/test/extractor-tests/generated/Path/Path_getPart.ql b/rust/ql/test/extractor-tests/generated/Path/Path_getSegment.ql similarity index 84% rename from rust/ql/test/extractor-tests/generated/Path/Path_getPart.ql rename to rust/ql/test/extractor-tests/generated/Path/Path_getSegment.ql index 402b1354588..7ccbefb4149 100644 --- a/rust/ql/test/extractor-tests/generated/Path/Path_getPart.ql +++ b/rust/ql/test/extractor-tests/generated/Path/Path_getSegment.ql @@ -4,4 +4,4 @@ import TestUtils from Path x where toBeTested(x) and not x.isUnknown() -select x, x.getPart() +select x, x.getSegment() diff --git a/rust/schema/annotations.py b/rust/schema/annotations.py index f3fa3cd5b3a..56c9fc34b1b 100644 --- a/rust/schema/annotations.py +++ b/rust/schema/annotations.py @@ -87,6 +87,7 @@ class _: foo::bar; ``` """ + segment: _ | ql.db_table_name("path_segments_") | doc("last segment of this path") @annotate(GenericArgList) diff --git a/rust/schema/ast.py b/rust/schema/ast.py index e014105c5a9..3f91cab5835 100644 --- a/rust/schema/ast.py +++ b/rust/schema/ast.py @@ -482,7 +482,7 @@ class ParenthesizedArgList(AstNode, ): class Path(AstNode, ): qualifier: optional["Path"] | child - part: optional["PathSegment"] | child + segment: optional["PathSegment"] | child class PathExpr(Expr, ): attrs: list["Attr"] | child