diff --git a/crates/ty/docs/rules.md b/crates/ty/docs/rules.md index b6c57a9d6d..7f9931cdf5 100644 --- a/crates/ty/docs/rules.md +++ b/crates/ty/docs/rules.md @@ -380,11 +380,24 @@ class A: # Crash at runtime Default level: error · Added in 0.0.1-alpha.1 · Related issues · -View source +View source -TODO #14889 +**What it does** + +Checks for forward annotations that contain escape characters. + +**Why is this bad?** + +Static analysis tools like ty can't analyze type annotations that contain escape characters. + +**Example** + + +```python +def foo() -> "intt\b": ... +``` ## `fstring-type-annotation` @@ -1597,7 +1610,45 @@ Added in 0. -TODO #14889 +**What it does** + +Checks for string-literal annotations where the string cannot be +parsed as a Python expression. + +**Why is this bad?** + +Type annotations are expected to be Python expressions that +describe the expected type of a variable, parameter, attribute or +`return` statement. + +Type annotations are permitted to be string-literal expressions, in +order to enable forward references to names not yet defined. +However, it must be possible to parse the contents of that string +literal as a normal Python expression. + +**Example** + + +```python +def foo() -> "intstance of C": + return 42 + +class C: ... +``` + +Use instead: + +```python +def foo() -> "C": + return 42 + +class C: ... +``` + +**References** + +- [Typing spec: The meaning of annotations](https://typing.python.org/en/latest/spec/annotations.html#the-meaning-of-annotations) +- [Typing spec: String annotations](https://typing.python.org/en/latest/spec/annotations.html#string-annotations) ## `invalid-type-alias-type` diff --git a/crates/ty_python_semantic/src/types/string_annotation.rs b/crates/ty_python_semantic/src/types/string_annotation.rs index 7ea673f3aa..cddbd9ec57 100644 --- a/crates/ty_python_semantic/src/types/string_annotation.rs +++ b/crates/ty_python_semantic/src/types/string_annotation.rs @@ -34,23 +34,23 @@ declare_lint! { } declare_lint! { - /// ## What it does - /// Checks for byte-strings in type annotation positions. - /// - /// ## Why is this bad? - /// Static analysis tools like ty can't analyze type annotations that use byte-string notation. - /// - /// ## Examples - /// ```python - /// def test(): -> b"int": - /// ... - /// ``` - /// - /// Use instead: - /// ```python - /// def test(): -> "int": - /// ... - /// ``` + /// ## What it does + /// Checks for byte-strings in type annotation positions. + /// + /// ## Why is this bad? + /// Static analysis tools like ty can't analyze type annotations that use byte-string notation. + /// + /// ## Examples + /// ```python + /// def test(): -> b"int": + /// ... + /// ``` + /// + /// Use instead: + /// ```python + /// def test(): -> "int": + /// ... + /// ``` pub(crate) static BYTE_STRING_TYPE_ANNOTATION = { summary: "detects byte strings in type annotation positions", status: LintStatus::stable("0.0.1-alpha.1"), @@ -59,23 +59,23 @@ declare_lint! { } declare_lint! { - /// ## What it does - /// Checks for raw-strings in type annotation positions. - /// - /// ## Why is this bad? - /// Static analysis tools like ty can't analyze type annotations that use raw-string notation. - /// - /// ## Examples - /// ```python - /// def test(): -> r"int": - /// ... - /// ``` - /// - /// Use instead: - /// ```python - /// def test(): -> "int": - /// ... - /// ``` + /// ## What it does + /// Checks for raw-strings in type annotation positions. + /// + /// ## Why is this bad? + /// Static analysis tools like ty can't analyze type annotations that use raw-string notation. + /// + /// ## Examples + /// ```python + /// def test(): -> r"int": + /// ... + /// ``` + /// + /// Use instead: + /// ```python + /// def test(): -> "int": + /// ... + /// ``` pub(crate) static RAW_STRING_TYPE_ANNOTATION = { summary: "detects raw strings in type annotation positions", status: LintStatus::stable("0.0.1-alpha.1"), @@ -84,23 +84,23 @@ declare_lint! { } declare_lint! { - /// ## What it does - /// Checks for implicit concatenated strings in type annotation positions. - /// - /// ## Why is this bad? - /// Static analysis tools like ty can't analyze type annotations that use implicit concatenated strings. - /// - /// ## Examples - /// ```python - /// def test(): -> "Literal[" "5" "]": - /// ... - /// ``` - /// - /// Use instead: - /// ```python - /// def test(): -> "Literal[5]": - /// ... - /// ``` + /// ## What it does + /// Checks for implicit concatenated strings in type annotation positions. + /// + /// ## Why is this bad? + /// Static analysis tools like ty can't analyze type annotations that use implicit concatenated strings. + /// + /// ## Examples + /// ```python + /// def test(): -> "Literal[" "5" "]": + /// ... + /// ``` + /// + /// Use instead: + /// ```python + /// def test(): -> "Literal[5]": + /// ... + /// ``` pub(crate) static IMPLICIT_CONCATENATED_STRING_TYPE_ANNOTATION = { summary: "detects implicit concatenated strings in type annotations", status: LintStatus::stable("0.0.1-alpha.1"), @@ -109,7 +109,41 @@ declare_lint! { } declare_lint! { - /// TODO #14889 + /// ## What it does + /// Checks for string-literal annotations where the string cannot be + /// parsed as a Python expression. + /// + /// ## Why is this bad? + /// Type annotations are expected to be Python expressions that + /// describe the expected type of a variable, parameter, attribute or + /// `return` statement. + /// + /// Type annotations are permitted to be string-literal expressions, in + /// order to enable forward references to names not yet defined. + /// However, it must be possible to parse the contents of that string + /// literal as a normal Python expression. + /// + /// ## Example + /// + /// ```python + /// def foo() -> "intstance of C": + /// return 42 + /// + /// class C: ... + /// ``` + /// + /// Use instead: + /// + /// ```python + /// def foo() -> "C": + /// return 42 + /// + /// class C: ... + /// ``` + /// + /// ## References + /// - [Typing spec: The meaning of annotations](https://typing.python.org/en/latest/spec/annotations.html#the-meaning-of-annotations) + /// - [Typing spec: String annotations](https://typing.python.org/en/latest/spec/annotations.html#string-annotations) pub(crate) static INVALID_SYNTAX_IN_FORWARD_ANNOTATION = { summary: "detects invalid syntax in forward annotations", status: LintStatus::stable("0.0.1-alpha.1"), @@ -118,7 +152,17 @@ declare_lint! { } declare_lint! { - /// TODO #14889 + /// ## What it does + /// Checks for forward annotations that contain escape characters. + /// + /// ## Why is this bad? + /// Static analysis tools like ty can't analyze type annotations that contain escape characters. + /// + /// ## Example + /// + /// ```python + /// def foo() -> "intt\b": ... + /// ``` pub(crate) static ESCAPE_CHARACTER_IN_FORWARD_ANNOTATION = { summary: "detects forward type annotations with escape characters", status: LintStatus::stable("0.0.1-alpha.1"), diff --git a/ty.schema.json b/ty.schema.json index 3d96def8f6..7992d64dc2 100644 --- a/ty.schema.json +++ b/ty.schema.json @@ -425,7 +425,7 @@ }, "escape-character-in-forward-annotation": { "title": "detects forward type annotations with escape characters", - "description": "TODO #14889", + "description": "## What it does\nChecks for forward annotations that contain escape characters.\n\n## Why is this bad?\nStatic analysis tools like ty can't analyze type annotations that contain escape characters.\n\n## Example\n\n```python\ndef foo() -> \"intt\\b\": ...\n```", "default": "error", "oneOf": [ { @@ -745,7 +745,7 @@ }, "invalid-syntax-in-forward-annotation": { "title": "detects invalid syntax in forward annotations", - "description": "TODO #14889", + "description": "## What it does\nChecks for string-literal annotations where the string cannot be\nparsed as a Python expression.\n\n## Why is this bad?\nType annotations are expected to be Python expressions that\ndescribe the expected type of a variable, parameter, attribute or\n`return` statement.\n\nType annotations are permitted to be string-literal expressions, in\norder to enable forward references to names not yet defined.\nHowever, it must be possible to parse the contents of that string\nliteral as a normal Python expression.\n\n## Example\n\n```python\ndef foo() -> \"intstance of C\":\n return 42\n\nclass C: ...\n```\n\nUse instead:\n\n```python\ndef foo() -> \"C\":\n return 42\n\nclass C: ...\n```\n\n## References\n- [Typing spec: The meaning of annotations](https://typing.python.org/en/latest/spec/annotations.html#the-meaning-of-annotations)\n- [Typing spec: String annotations](https://typing.python.org/en/latest/spec/annotations.html#string-annotations)", "default": "error", "oneOf": [ {