Split CallPath into QualifiedName and UnqualifiedName (#10210)

## Summary

Charlie can probably explain this better than I but it turns out,
`CallPath` is used for two different things:

* To represent unqualified names like `version` where `version` can be a
local variable or imported (e.g. `from sys import version` where the
full qualified name is `sys.version`)
* To represent resolved, full qualified names

This PR splits `CallPath` into two types to make this destinction clear.

> Note: I haven't renamed all `call_path` variables to `qualified_name`
or `unqualified_name`. I can do that if that's welcomed but I first want
to get feedback on the approach and naming overall.

## Test Plan

`cargo test`
This commit is contained in:
Micha Reiser 2024-03-04 10:06:51 +01:00 committed by GitHub
parent ba4328226d
commit a6d892b1f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
181 changed files with 1692 additions and 1412 deletions

View file

@ -1,5 +1,5 @@
use ruff_python_ast::call_path::CallPath;
use ruff_python_ast::helpers::is_const_true;
use ruff_python_ast::name::{QualifiedName, UnqualifiedName};
use ruff_python_ast::{self as ast, Arguments, Expr, Keyword};
use crate::model::SemanticModel;
@ -27,9 +27,9 @@ pub fn is_logger_candidate(
// If the symbol was imported from another module, ensure that it's either a user-specified
// logger object, the `logging` module itself, or `flask.current_app.logger`.
if let Some(call_path) = semantic.resolve_call_path(value) {
if let Some(qualified_name) = semantic.resolve_qualified_name(value) {
if matches!(
call_path.segments(),
qualified_name.segments(),
["logging"] | ["flask", "current_app", "logger"]
) {
return true;
@ -37,7 +37,7 @@ pub fn is_logger_candidate(
if logger_objects
.iter()
.any(|logger| CallPath::from_qualified_name(logger) == call_path)
.any(|logger| QualifiedName::from_dotted_name(logger) == qualified_name)
{
return true;
}
@ -47,8 +47,8 @@ pub fn is_logger_candidate(
// Otherwise, if the symbol was defined in the current module, match against some common
// logger names.
if let Some(call_path) = CallPath::from_expr(value) {
if let Some(tail) = call_path.segments().last() {
if let Some(name) = UnqualifiedName::from_expr(value) {
if let Some(tail) = name.segments().last() {
if tail.starts_with("log")
|| tail.ends_with("logger")
|| tail.ends_with("logging")
@ -78,8 +78,8 @@ pub fn exc_info<'a>(arguments: &'a Arguments, semantic: &SemanticModel) -> Optio
if exc_info
.value
.as_call_expr()
.and_then(|call| semantic.resolve_call_path(&call.func))
.is_some_and(|call_path| matches!(call_path.segments(), ["sys", "exc_info"]))
.and_then(|call| semantic.resolve_qualified_name(&call.func))
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["sys", "exc_info"]))
{
return Some(exc_info);
}