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": [
{