mirror of https://github.com/astral-sh/ruff
check if strings are just strings
This commit is contained in:
parent
86e9b4d337
commit
a87750a027
|
|
@ -7,7 +7,6 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::find_node::covering_node;
|
use crate::find_node::covering_node;
|
||||||
use crate::stub_mapping::StubMapper;
|
use crate::stub_mapping::StubMapper;
|
||||||
use ruff_db::Db;
|
|
||||||
use ruff_db::files::File;
|
use ruff_db::files::File;
|
||||||
use ruff_db::parsed::ParsedModuleRef;
|
use ruff_db::parsed::ParsedModuleRef;
|
||||||
use ruff_db::source::source_text;
|
use ruff_db::source::source_text;
|
||||||
|
|
@ -280,9 +279,10 @@ impl GotoTarget<'_> {
|
||||||
GotoTarget::ImportModuleAlias { alias } => alias.inferred_type(model),
|
GotoTarget::ImportModuleAlias { alias } => alias.inferred_type(model),
|
||||||
GotoTarget::ExceptVariable(except) => except.inferred_type(model),
|
GotoTarget::ExceptVariable(except) => except.inferred_type(model),
|
||||||
GotoTarget::KeywordArgument { keyword, .. } => keyword.value.inferred_type(model),
|
GotoTarget::KeywordArgument { keyword, .. } => keyword.value.inferred_type(model),
|
||||||
GotoTarget::StringAnnotationExprName { .. } => {
|
GotoTarget::StringAnnotationExprName { string_literal, .. } => {
|
||||||
// TODO: make a way to ask the inference engine about a sub-expr of a string annotation
|
// TODO: make a way to ask the inference engine about a sub-expr of a string annotation
|
||||||
return None;
|
// for now we just yield the type of the entire string expression
|
||||||
|
string_literal.inferred_type(model)
|
||||||
}
|
}
|
||||||
// TODO: Support identifier targets
|
// TODO: Support identifier targets
|
||||||
GotoTarget::PatternMatchRest(_)
|
GotoTarget::PatternMatchRest(_)
|
||||||
|
|
@ -528,7 +528,7 @@ impl GotoTarget<'_> {
|
||||||
|
|
||||||
/// Creates a `GotoTarget` from a `CoveringNode` and an offset within the node
|
/// Creates a `GotoTarget` from a `CoveringNode` and an offset within the node
|
||||||
pub(crate) fn from_covering_node<'a>(
|
pub(crate) fn from_covering_node<'a>(
|
||||||
db: &dyn Db,
|
db: &dyn crate::Db,
|
||||||
file: File,
|
file: File,
|
||||||
covering_node: &crate::find_node::CoveringNode<'a>,
|
covering_node: &crate::find_node::CoveringNode<'a>,
|
||||||
offset: TextSize,
|
offset: TextSize,
|
||||||
|
|
@ -680,13 +680,20 @@ impl GotoTarget<'_> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
AnyNodeRef::ExprStringLiteral(string_literal) => {
|
node @ AnyNodeRef::ExprStringLiteral(string_literal) => {
|
||||||
// If we encounter a string literal, blindly assume it's a string annotation
|
// If we encounter a string literal, try to figure out if it's actually
|
||||||
// like `x: "str | int"` by parsing it as a sub-AST.
|
// a string annotation by asking the type checker if its type is
|
||||||
//
|
// a StringLiteral equal to itself
|
||||||
// TODO: we *really* should be asking the semantic analysis if this is actually
|
let model = SemanticModel::new(db, file);
|
||||||
// a string annotation, because this behaviour will effect any random string
|
let string_ty = string_literal.inferred_type(&model);
|
||||||
// literal that looks like a type..!
|
if let Type::StringLiteral(string) = string_ty {
|
||||||
|
if string.value(db) == string_literal.value.to_str() {
|
||||||
|
return node.as_expr_ref().map(GotoTarget::Expression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok it has a different type, that means it's some kind of string annotation,
|
||||||
|
// so try to parse it as a sub-AST
|
||||||
let source = source_text(db, file);
|
let source = source_text(db, file);
|
||||||
let sub_ast = parse_string_annotation(
|
let sub_ast = parse_string_annotation(
|
||||||
source.as_str(),
|
source.as_str(),
|
||||||
|
|
@ -814,7 +821,7 @@ fn definitions_to_navigation_targets<'db>(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn find_goto_target<'a>(
|
pub(crate) fn find_goto_target<'a>(
|
||||||
db: &dyn Db,
|
db: &dyn crate::Db,
|
||||||
file: File,
|
file: File,
|
||||||
parsed: &'a ParsedModuleRef,
|
parsed: &'a ParsedModuleRef,
|
||||||
offset: TextSize,
|
offset: TextSize,
|
||||||
|
|
@ -823,7 +830,7 @@ pub(crate) fn find_goto_target<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_goto_target_impl<'a>(
|
fn find_goto_target_impl<'a>(
|
||||||
db: &dyn Db,
|
db: &dyn crate::Db,
|
||||||
file: File,
|
file: File,
|
||||||
tokens: &'a Tokens,
|
tokens: &'a Tokens,
|
||||||
root: AnyNodeRef<'a>,
|
root: AnyNodeRef<'a>,
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,24 @@ mod tests {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_snapshot!(test.goto_type_definition(), @"No goto target found");
|
assert_snapshot!(test.goto_type_definition(), @r#"
|
||||||
|
info[goto-type-definition]: Type definition
|
||||||
|
--> stdlib/builtins.pyi:892:7
|
||||||
|
|
|
||||||
|
890 | def __getitem__(self, key: int, /) -> str | int | None: ...
|
||||||
|
891 |
|
||||||
|
892 | class str(Sequence[str]):
|
||||||
|
| ^^^
|
||||||
|
893 | """str(object='') -> str
|
||||||
|
894 | str(bytes_or_buffer[, encoding[, errors]]) -> str
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main.py:2:22
|
||||||
|
|
|
||||||
|
2 | a: str = "test"
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -9942,7 +9942,7 @@ impl<'db> IntersectionType<'db> {
|
||||||
#[derive(PartialOrd, Ord)]
|
#[derive(PartialOrd, Ord)]
|
||||||
pub struct StringLiteralType<'db> {
|
pub struct StringLiteralType<'db> {
|
||||||
#[returns(deref)]
|
#[returns(deref)]
|
||||||
value: Box<str>,
|
pub value: Box<str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Salsa heap is tracked separately.
|
// The Salsa heap is tracked separately.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue