mirror of
https://github.com/github/codeql.git
synced 2026-04-27 17:55:19 +02:00
Swift: tag -> pragma in codegen
For the use the former tags are meant for, pragma is a more meaningful name. It now also accepts both strings and lists of strings.
This commit is contained in:
@@ -19,7 +19,7 @@ class FormatError(Exception):
|
||||
def get_ql_property(cls: schema.Class, prop: schema.Property):
|
||||
common_args = dict(
|
||||
type=prop.type if not prop.is_predicate else "predicate",
|
||||
skip_qltest="no_qltest" in prop.tags,
|
||||
skip_qltest="skip_qltest" in prop.pragmas,
|
||||
is_child=prop.is_child,
|
||||
is_optional=prop.is_optional,
|
||||
is_predicate=prop.is_predicate,
|
||||
@@ -64,7 +64,7 @@ def get_ql_class(cls: schema.Class):
|
||||
final=not cls.derived,
|
||||
properties=[get_ql_property(cls, p) for p in cls.properties],
|
||||
dir=cls.dir,
|
||||
skip_qltest="no_qltest" in cls.tags,
|
||||
skip_qltest="skip_qltest" in cls.pragmas,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import pathlib
|
||||
import re
|
||||
import typing
|
||||
from dataclasses import dataclass, field
|
||||
from typing import List, Set, Union, Dict, ClassVar
|
||||
|
||||
@@ -11,7 +12,7 @@ import yaml
|
||||
class Error(Exception):
|
||||
|
||||
def __str__(self):
|
||||
return f"schema.Error{args}"
|
||||
return self.args[0]
|
||||
|
||||
|
||||
root_class_name = "Element"
|
||||
@@ -27,7 +28,7 @@ class Property:
|
||||
name: str
|
||||
type: str = None
|
||||
is_child: bool = False
|
||||
tags: List[str] = field(default_factory=list)
|
||||
pragmas: List[str] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -63,7 +64,7 @@ class Class:
|
||||
derived: Set[str] = field(default_factory=set)
|
||||
properties: List[Property] = field(default_factory=list)
|
||||
dir: pathlib.Path = pathlib.Path()
|
||||
tags: List[str] = field(default_factory=list)
|
||||
pragmas: List[str] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -72,24 +73,38 @@ class Schema:
|
||||
includes: Set[str] = field(default_factory=set)
|
||||
|
||||
|
||||
def _parse_property(name: str, type: Union[str, Dict[str, str]], is_child: bool = False):
|
||||
if isinstance(type, dict):
|
||||
tags = type.get("_tags", [])
|
||||
type = type["type"]
|
||||
_StrOrList = Union[str, List[str]]
|
||||
|
||||
|
||||
def _auto_list(data: _StrOrList) -> List[str]:
|
||||
if isinstance(data, list):
|
||||
return data
|
||||
return [data]
|
||||
|
||||
|
||||
def _parse_property(name: str, data: Union[str, Dict[str, _StrOrList]], is_child: bool = False):
|
||||
if isinstance(data, dict):
|
||||
if "type" not in data:
|
||||
raise Error(f"property {name} has no type")
|
||||
pragmas = _auto_list(data.pop("_pragma", []))
|
||||
type = data.pop("type")
|
||||
if data:
|
||||
raise Error(f"unknown metadata {', '.join(data)} in property {name}")
|
||||
else:
|
||||
tags = []
|
||||
pragmas = []
|
||||
type = data
|
||||
if is_child and type[0].islower():
|
||||
raise Error(f"children must have class type, got {type} for {name}")
|
||||
if type.endswith("?*"):
|
||||
return RepeatedOptionalProperty(name, type[:-2], is_child=is_child, tags=tags)
|
||||
return RepeatedOptionalProperty(name, type[:-2], is_child=is_child, pragmas=pragmas)
|
||||
elif type.endswith("*"):
|
||||
return RepeatedProperty(name, type[:-1], is_child=is_child, tags=tags)
|
||||
return RepeatedProperty(name, type[:-1], is_child=is_child, pragmas=pragmas)
|
||||
elif type.endswith("?"):
|
||||
return OptionalProperty(name, type[:-1], is_child=is_child, tags=tags)
|
||||
return OptionalProperty(name, type[:-1], is_child=is_child, pragmas=pragmas)
|
||||
elif type == "predicate":
|
||||
return PredicateProperty(name, tags=tags)
|
||||
return PredicateProperty(name, pragmas=pragmas)
|
||||
else:
|
||||
return SingleProperty(name, type, is_child=is_child, tags=tags)
|
||||
return SingleProperty(name, type, is_child=is_child, pragmas=pragmas)
|
||||
|
||||
|
||||
class _DirSelector:
|
||||
@@ -120,8 +135,7 @@ def load(path):
|
||||
if not k.startswith("_"):
|
||||
cls.properties.append(_parse_property(k, v))
|
||||
elif k == "_extends":
|
||||
if not isinstance(v, list):
|
||||
v = [v]
|
||||
v = _auto_list(v)
|
||||
for base in v:
|
||||
cls.bases.add(base)
|
||||
classes[base].derived.add(name)
|
||||
@@ -129,8 +143,8 @@ def load(path):
|
||||
cls.dir = pathlib.Path(v)
|
||||
elif k == "_children":
|
||||
cls.properties.extend(_parse_property(kk, vv, is_child=True) for kk, vv in v.items())
|
||||
elif k == "_tags":
|
||||
cls.tags = v
|
||||
elif k == "_pragma":
|
||||
cls.pragmas = _auto_list(v)
|
||||
else:
|
||||
raise Error(f"unknown metadata {k} for class {name}")
|
||||
if not cls.bases and cls.name != root_class_name:
|
||||
|
||||
@@ -14,14 +14,14 @@ _directories:
|
||||
|
||||
Element:
|
||||
is_unknown: predicate
|
||||
_tags: [ no_qltest ]
|
||||
_pragma: skip_qltest
|
||||
|
||||
File:
|
||||
name: string
|
||||
|
||||
Locatable:
|
||||
location: Location?
|
||||
_tags: [ no_qltest ]
|
||||
_pragma: skip_qltest
|
||||
|
||||
Location:
|
||||
file: File
|
||||
@@ -29,7 +29,7 @@ Location:
|
||||
start_column: int
|
||||
end_line: int
|
||||
end_column: int
|
||||
_tags: [ no_qltest ]
|
||||
_pragma: skip_qltest
|
||||
|
||||
Type:
|
||||
diagnostics_name: string
|
||||
@@ -385,7 +385,7 @@ EnumIsCaseExpr:
|
||||
|
||||
ErrorExpr:
|
||||
_extends: Expr
|
||||
_tags: [ no_qltest ] # unexpected emission
|
||||
_pragma: skip_qltest # unexpected emission
|
||||
|
||||
ExplicitCastExpr:
|
||||
_extends: Expr
|
||||
@@ -460,7 +460,7 @@ ObjCSelectorExpr:
|
||||
_children:
|
||||
sub_expr: Expr
|
||||
method: AbstractFunctionDecl
|
||||
_tags: [ no_qltest ] # to be tested in integration tests
|
||||
_pragma: skip_qltest # to be tested in integration tests
|
||||
|
||||
OneWayExpr:
|
||||
_extends: Expr
|
||||
@@ -502,7 +502,7 @@ SequenceExpr:
|
||||
_extends: Expr
|
||||
_children:
|
||||
elements: Expr*
|
||||
_tags: [ no_qltest ] # we should really never extract these, as these should be resolved to trees of operations
|
||||
_pragma: skip_qltest # we should really never extract these, as these should be resolved to trees of operations
|
||||
|
||||
SuperRefExpr:
|
||||
_extends: Expr
|
||||
@@ -534,7 +534,7 @@ TypeExpr:
|
||||
UnresolvedDeclRefExpr:
|
||||
_extends: Expr
|
||||
name: string?
|
||||
_tags: [ no_qltest ] # we should really never extract these
|
||||
_pragma: skip_qltest # we should really never extract these
|
||||
|
||||
UnresolvedDotExpr:
|
||||
_extends: Expr
|
||||
@@ -545,15 +545,15 @@ UnresolvedDotExpr:
|
||||
UnresolvedMemberExpr:
|
||||
_extends: Expr
|
||||
name: string
|
||||
_tags: [ no_qltest ] # we should really never extract these
|
||||
_pragma: skip_qltest # we should really never extract these
|
||||
|
||||
UnresolvedPatternExpr:
|
||||
_extends: Expr
|
||||
_tags: [ no_qltest ] # we should really never extract these
|
||||
_pragma: skip_qltest # we should really never extract these
|
||||
|
||||
UnresolvedSpecializeExpr:
|
||||
_extends: Expr
|
||||
_tags: [ no_qltest ] # we should really never extract these
|
||||
_pragma: skip_qltest # we should really never extract these
|
||||
|
||||
VarargExpansionExpr:
|
||||
_extends: Expr
|
||||
@@ -821,11 +821,11 @@ ArrayToPointerExpr:
|
||||
|
||||
BridgeFromObjCExpr:
|
||||
_extends: ImplicitConversionExpr
|
||||
_tags: [ no_qltest ] # to be tested in integration tests
|
||||
_pragma: skip_qltest # to be tested in integration tests
|
||||
|
||||
BridgeToObjCExpr:
|
||||
_extends: ImplicitConversionExpr
|
||||
_tags: [ no_qltest ] # to be tested in integration tests
|
||||
_pragma: skip_qltest # to be tested in integration tests
|
||||
|
||||
ClassMetatypeToObjectExpr:
|
||||
_extends: ImplicitConversionExpr
|
||||
@@ -835,7 +835,7 @@ CollectionUpcastConversionExpr:
|
||||
|
||||
ConditionalBridgeFromObjCExpr:
|
||||
_extends: ImplicitConversionExpr
|
||||
_tags: [ no_qltest ] # to be tested in integration tests
|
||||
_pragma: skip_qltest # to be tested in integration tests
|
||||
|
||||
CovariantFunctionConversionExpr:
|
||||
_extends: ImplicitConversionExpr
|
||||
|
||||
@@ -458,13 +458,13 @@ def test_test_properties_skipped(opts, generate_tests):
|
||||
write(opts.ql_test_output / "Derived" / "test.swift")
|
||||
assert generate_tests([
|
||||
schema.Class("Base", derived={"Derived"}, properties=[
|
||||
schema.SingleProperty("x", "string", tags=["no_qltest", "foo"]),
|
||||
schema.RepeatedProperty("y", "int", tags=["bar", "no_qltest"]),
|
||||
schema.SingleProperty("x", "string", pragmas=["skip_qltest", "foo"]),
|
||||
schema.RepeatedProperty("y", "int", pragmas=["bar", "skip_qltest"]),
|
||||
]),
|
||||
schema.Class("Derived", bases={"Base"}, properties=[
|
||||
schema.PredicateProperty("a", tags=["no_qltest"]),
|
||||
schema.PredicateProperty("a", pragmas=["skip_qltest"]),
|
||||
schema.OptionalProperty(
|
||||
"b", "int", tags=["bar", "no_qltest", "baz"]),
|
||||
"b", "int", pragmas=["bar", "skip_qltest", "baz"]),
|
||||
]),
|
||||
]) == {
|
||||
"Derived/Derived.ql": ql.ClassTester(class_name="Derived"),
|
||||
@@ -474,7 +474,7 @@ def test_test_properties_skipped(opts, generate_tests):
|
||||
def test_test_base_class_skipped(opts, generate_tests):
|
||||
write(opts.ql_test_output / "Derived" / "test.swift")
|
||||
assert generate_tests([
|
||||
schema.Class("Base", derived={"Derived"}, tags=["no_qltest", "foo"], properties=[
|
||||
schema.Class("Base", derived={"Derived"}, pragmas=["skip_qltest", "foo"], properties=[
|
||||
schema.SingleProperty("x", "string"),
|
||||
schema.RepeatedProperty("y", "int"),
|
||||
]),
|
||||
@@ -488,7 +488,7 @@ def test_test_final_class_skipped(opts, generate_tests):
|
||||
write(opts.ql_test_output / "Derived" / "test.swift")
|
||||
assert generate_tests([
|
||||
schema.Class("Base", derived={"Derived"}),
|
||||
schema.Class("Derived", bases={"Base"}, tags=["no_qltest", "foo"], properties=[
|
||||
schema.Class("Derived", bases={"Base"}, pragmas=["skip_qltest", "foo"], properties=[
|
||||
schema.SingleProperty("x", "string"),
|
||||
schema.RepeatedProperty("y", "int"),
|
||||
]),
|
||||
|
||||
@@ -217,32 +217,81 @@ A:
|
||||
]
|
||||
|
||||
|
||||
def test_property_with_explicit_type_and_tags(load):
|
||||
def test_property_with_explicit_type_and_pragmas(load):
|
||||
ret = load("""
|
||||
A:
|
||||
x:
|
||||
type: string*
|
||||
_tags: [foo, bar]
|
||||
_pragma: [foo, bar]
|
||||
""")
|
||||
assert ret.classes == [
|
||||
schema.Class(root_name, derived={'A'}),
|
||||
schema.Class('A', bases={root_name}, properties=[
|
||||
schema.RepeatedProperty('x', 'string', tags=["foo", "bar"]),
|
||||
schema.RepeatedProperty('x', 'string', pragmas=["foo", "bar"]),
|
||||
]),
|
||||
]
|
||||
|
||||
|
||||
def test_class_with_tags(load):
|
||||
def test_property_with_explicit_type_and_one_pragma(load):
|
||||
ret = load("""
|
||||
A:
|
||||
x:
|
||||
type: string*
|
||||
_pragma: foo
|
||||
""")
|
||||
assert ret.classes == [
|
||||
schema.Class(root_name, derived={'A'}),
|
||||
schema.Class('A', bases={root_name}, properties=[
|
||||
schema.RepeatedProperty('x', 'string', pragmas=["foo"]),
|
||||
]),
|
||||
]
|
||||
|
||||
|
||||
def test_property_with_explicit_type_and_unknown_metadata(load):
|
||||
with pytest.raises(schema.Error):
|
||||
load("""
|
||||
A:
|
||||
x:
|
||||
type: string*
|
||||
_what_is_this: [foo, bar]
|
||||
""")
|
||||
|
||||
|
||||
def test_property_with_dict_without_explicit_type(load):
|
||||
with pytest.raises(schema.Error):
|
||||
load("""
|
||||
A:
|
||||
x:
|
||||
typo: string*
|
||||
""")
|
||||
|
||||
|
||||
|
||||
def test_class_with_pragmas(load):
|
||||
ret = load("""
|
||||
A:
|
||||
x: string*
|
||||
_tags: [foo, bar]
|
||||
_pragma: [foo, bar]
|
||||
""")
|
||||
assert ret.classes == [
|
||||
schema.Class(root_name, derived={'A'}),
|
||||
schema.Class('A', bases={root_name}, properties=[
|
||||
schema.RepeatedProperty('x', 'string'),
|
||||
], tags=["foo", "bar"]),
|
||||
], pragmas=["foo", "bar"]),
|
||||
]
|
||||
|
||||
|
||||
def test_class_with_one_pragma(load):
|
||||
ret = load("""
|
||||
A:
|
||||
x: string*
|
||||
_pragma: foo
|
||||
""")
|
||||
assert ret.classes == [
|
||||
schema.Class(root_name, derived={'A'}),
|
||||
schema.Class('A', bases={root_name}, properties=[
|
||||
schema.RepeatedProperty('x', 'string'),
|
||||
], pragmas=["foo"]),
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user