Skip to content

Commit 9e6ae18

Browse files
committed
[FIX] server: OLS01007 - various fixs about argument call validation
1 parent ffa1859 commit 9e6ae18

File tree

10 files changed

+164
-82
lines changed

10 files changed

+164
-82
lines changed

server/src/core/evaluation.rs

Lines changed: 92 additions & 51 deletions
Large diffs are not rendered by default.

server/src/core/python_arch_builder.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ impl PythonArchBuilder {
548548
if parent.is_some() {
549549
let parent = parent.unwrap();
550550
let mut deps = vec![vec![]]; //only arch level
551-
let eval = Evaluation::eval_from_ast(session, &assign.value.as_ref().unwrap(), parent, &assign_stmt.range.start(), &mut deps);
551+
let eval = Evaluation::eval_from_ast(session, &assign.value.as_ref().unwrap(), parent, &assign_stmt.range.start(), false, &mut deps);
552552
Symbol::insert_dependencies(&self.file, &mut deps, BuildSteps::ARCH);
553553
variable.as_variable_mut().evaluations = eval.0;
554554
self.diagnostics.extend(eval.1);
@@ -666,7 +666,8 @@ impl PythonArchBuilder {
666666
else if decorator.expression.as_name_expr().unwrap().id.to_string() == "classmethod" {
667667
func_sym.is_class_method = true;
668668
}
669-
else if decorator.expression.as_name_expr().unwrap().id.to_string() == "classproperty" {
669+
else if decorator.expression.as_name_expr().unwrap().id.to_string() == "classproperty" ||
670+
decorator.expression.as_name_expr().unwrap().id.to_string() == "lazy_classproperty" {
670671
func_sym.is_property = true;
671672
func_sym.is_class_method = true;
672673
}

server/src/core/python_arch_eval.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -460,13 +460,13 @@ impl PythonArchEval {
460460
if !self.file_mode {
461461
deps.push(vec![]);
462462
}
463-
let mut ann_evaluations = assign.annotation.as_ref().map(|annotation| Evaluation::eval_from_ast(session, annotation, parent.clone(), &range.start(), &mut deps));
463+
let mut ann_evaluations = assign.annotation.as_ref().map(|annotation| Evaluation::eval_from_ast(session, annotation, parent.clone(), &range.start(), true, &mut deps));
464464
Symbol::insert_dependencies(&self.file, &mut deps, self.current_step);
465465
deps = vec![vec![], vec![]];
466466
if !self.file_mode {
467467
deps.push(vec![]);
468468
}
469-
let value_evaluations = assign.value.as_ref().map(|value| Evaluation::eval_from_ast(session, value, parent.clone(), &range.start(), &mut deps));
469+
let value_evaluations = assign.value.as_ref().map(|value| Evaluation::eval_from_ast(session, value, parent.clone(), &range.start(), false, &mut deps));
470470
Symbol::insert_dependencies(&self.file, &mut deps, self.current_step);
471471
let mut take_value = false;
472472
if let Some((ref val_eval, ref _diags)) = value_evaluations{
@@ -561,7 +561,7 @@ impl PythonArchEval {
561561
// Check the whole attribute chain, to see if we are in a field of the model that is valid
562562
// so for z.a.b.c, checks, z.a, z.a.b, z.a.b.c, if one of them is valid it is okay
563563
'while_block: while matches!(expr, Expr::Attribute(_)){
564-
let assignee = Evaluation::eval_from_ast(session, &expr, self.sym_stack.last().unwrap().clone(), &attr_expr.range.start(), &mut vec![]);
564+
let assignee = Evaluation::eval_from_ast(session, &expr, self.sym_stack.last().unwrap().clone(), &attr_expr.range.start(), false, &mut vec![]);
565565
for evaluation in assignee.0{
566566
let evaluation_symbol_ptr = evaluation.symbol.get_symbol_weak_transformed(session, &mut None, &mut vec![], None);
567567
let Some(sym_rc) = evaluation_symbol_ptr.upgrade_weak() else {
@@ -627,7 +627,7 @@ impl PythonArchEval {
627627
fn load_base_classes(&mut self, session: &mut SessionInfo, loc_sym: &Rc<RefCell<Symbol>>, class_stmt: &StmtClassDef) {
628628
for base in class_stmt.bases() {
629629
let mut deps = vec![vec![], vec![]];
630-
let eval_base = Evaluation::eval_from_ast(session, base, self.sym_stack.last().unwrap().clone(), &class_stmt.range().start(), &mut deps);
630+
let eval_base = Evaluation::eval_from_ast(session, base, self.sym_stack.last().unwrap().clone(), &class_stmt.range().start(), false, &mut deps);
631631
Symbol::insert_dependencies(&self.file, &mut deps, BuildSteps::ARCH_EVAL);
632632
self.diagnostics.extend(eval_base.1);
633633
let eval_base = eval_base.0;
@@ -738,7 +738,9 @@ impl PythonArchEval {
738738
let (eval, diags) = Evaluation::eval_from_ast(session,
739739
&arg.parameter.annotation.as_ref().unwrap(),
740740
self.sym_stack.last().unwrap().clone(),
741-
&func_stmt.range.start(), &mut deps);
741+
&func_stmt.range.start(),
742+
true,
743+
&mut deps);
742744
Symbol::insert_dependencies(&self.file, &mut deps, self.current_step);
743745
let mut var_bw = function_sym.borrow_mut();
744746
let symbol = var_bw.as_func_mut().symbols.get(&OYarn::from(arg.parameter.name.id.to_string())).unwrap().get(&0).unwrap().get(0).unwrap(); //get first declaration
@@ -752,7 +754,9 @@ impl PythonArchEval {
752754
let (eval, diags) = Evaluation::eval_from_ast(session,
753755
arg.default.as_ref().unwrap(),
754756
self.sym_stack.last().unwrap().clone(),
755-
&func_stmt.range.start(), &mut deps);
757+
&func_stmt.range.start(),
758+
false,
759+
&mut deps);
756760
Symbol::insert_dependencies(&self.file, &mut deps, self.current_step);
757761
let mut var_bw = function_sym.borrow_mut();
758762
let symbol = var_bw.as_func_mut().symbols.get(&OYarn::from(arg.parameter.name.id.to_string())).unwrap().get(&0).unwrap().get(0).unwrap(); //get first declaration
@@ -801,7 +805,7 @@ impl PythonArchEval {
801805
let (eval_iter_node, diags) = Evaluation::eval_from_ast(session,
802806
&for_stmt.iter,
803807
self.sym_stack.last().unwrap().clone(),
804-
&for_stmt.target.range().start(), &mut deps);
808+
&for_stmt.target.range().start(), false, &mut deps);
805809
Symbol::insert_dependencies(&self.file, &mut deps, self.current_step);
806810
self.diagnostics.extend(diags);
807811
if eval_iter_node.len() == 1 { //Only handle values that we are sure about
@@ -874,7 +878,7 @@ impl PythonArchEval {
874878
if !self.file_mode {
875879
deps.push(vec![]);
876880
}
877-
let (eval, diags) = Evaluation::eval_from_ast(session, value, func.clone(), &return_stmt.range.start(), &mut deps);
881+
let (eval, diags) = Evaluation::eval_from_ast(session, value, func.clone(), &return_stmt.range.start(), false, &mut deps);
878882
Symbol::insert_dependencies(&self.file, &mut deps, self.current_step);
879883
self.diagnostics.extend(diags);
880884
FunctionSymbol::add_return_evaluations(func, session, eval);
@@ -897,7 +901,7 @@ impl PythonArchEval {
897901
if !self.file_mode {
898902
deps.push(vec![]);
899903
}
900-
let (eval, diags) = Evaluation::eval_from_ast(session, &item.context_expr, parent, &with_stmt.range.start(), &mut deps);
904+
let (eval, diags) = Evaluation::eval_from_ast(session, &item.context_expr, parent, &with_stmt.range.start(), false, &mut deps);
901905
Symbol::insert_dependencies(&self.file, &mut deps, self.current_step);
902906
let mut evals = vec![];
903907
for eval in eval.iter() {
@@ -953,13 +957,22 @@ impl PythonArchEval {
953957
if let Some(returns_ann) = func_stmt.returns.as_ref() {
954958
let file_sym = func_sym.borrow().get_file().and_then(|file_weak| file_weak.upgrade());
955959
let mut deps = vec![vec![], vec![]];
956-
let (evaluations, diags) = Evaluation::eval_from_ast(
960+
let (mut evaluations, diags) = Evaluation::eval_from_ast(
957961
session,
958962
&returns_ann,
959963
func_sym.borrow().parent().and_then(|p| p.upgrade()).unwrap(),
960964
max_infer,
965+
true,
961966
&mut deps,
962967
);
968+
for eval in evaluations.iter_mut() { //as this is an evaluation, we need to set the instance to true
969+
match eval.symbol.get_mut_symbol_ptr() {
970+
EvaluationSymbolPtr::WEAK(ref mut sym_weak) => {
971+
sym_weak.instance = Some(true);
972+
},
973+
_ => {}
974+
}
975+
}
963976
if file_sym.is_some() {
964977
Symbol::insert_dependencies(&file_sym.as_ref().unwrap(), &mut deps, BuildSteps::ARCH_EVAL);
965978
}

server/src/core/python_arch_eval_hooks.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ impl PythonArchEvalHooks {
672672
return diagnostics // failed to find parent
673673
};
674674
let mut deps = vec![vec![], vec![], vec![]];
675-
let (dec_evals, diags) = Evaluation::eval_from_ast(session, &decorator_base, parent, &func_stmt.range.start(),&mut deps);
675+
let (dec_evals, diags) = Evaluation::eval_from_ast(session, &decorator_base, parent, &func_stmt.range.start(), false, &mut deps);
676676
Symbol::insert_dependencies(&file, &mut deps, current_step);
677677
diagnostics.extend(diags);
678678
let mut followed_evals = vec![];
@@ -1006,12 +1006,12 @@ impl PythonArchEvalHooks {
10061006
);
10071007

10081008
for (arg_name, (field_name_expr, arg_range)) in contexts_to_add {
1009-
let maybe_related_string = Evaluation::expr_to_str(session, field_name_expr, parent.clone(), &parameters.range.start(), &mut vec![]).0;
1009+
let maybe_related_string = Evaluation::expr_to_str(session, field_name_expr, parent.clone(), &parameters.range.start(), false, &mut vec![]).0;
10101010
if let Some(related_string) = maybe_related_string {
10111011
context.insert(S!(arg_name), ContextValue::STRING(related_string.to_string()));
10121012
context.insert(format!("{arg_name}_arg_range"), ContextValue::RANGE(arg_range.clone()));
10131013
} else {
1014-
let maybe_boolean = Evaluation::expr_to_bool(session, field_name_expr, parent.clone(), &parameters.range.start(), &mut vec![]).0;
1014+
let maybe_boolean = Evaluation::expr_to_bool(session, field_name_expr, parent.clone(), &parameters.range.start(), false, &mut vec![]).0;
10151015
if let Some(boolean) = maybe_boolean {
10161016
context.insert(S!(arg_name), ContextValue::BOOLEAN(boolean));
10171017
}

server/src/core/python_validator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ impl PythonValidator {
594594

595595
fn validate_expr(&mut self, session: &mut SessionInfo, expr: &Expr, max_infer: &TextSize) {
596596
let mut deps = vec![vec![], vec![], vec![]];
597-
let (eval, diags) = Evaluation::eval_from_ast(session, expr, self.sym_stack.last().unwrap().clone(), max_infer, &mut deps);
597+
let (eval, diags) = Evaluation::eval_from_ast(session, expr, self.sym_stack.last().unwrap().clone(), max_infer, false, &mut deps);
598598
Symbol::insert_dependencies(&self.file, &mut deps, BuildSteps::VALIDATION);
599599
self.diagnostics.extend(diags);
600600
}

server/src/core/symbols/function_symbol.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ impl FunctionSymbol {
9090
is_class_method: false,
9191
noqas: NoqaInfo::None,
9292
};
93+
if name == "__new__" {
94+
res.is_static = true;
95+
}
9396
res._init_symbol_mgr();
9497
res
9598
}
@@ -160,7 +163,7 @@ impl FunctionSymbol {
160163
}
161164

162165
/* Given a call of this function and an index, return the corresponding parameter definition */
163-
pub fn get_indexed_arg_in_call(&self, call: &ExprCall, index: u32, is_on_instance: bool) -> Option<&Argument> {
166+
pub fn get_indexed_arg_in_call(&self, call: &ExprCall, index: u32, is_on_instance: Option<bool>) -> Option<&Argument> {
164167
if self.is_overloaded() {
165168
return None;
166169
}
@@ -169,7 +172,7 @@ impl FunctionSymbol {
169172
call_arg_keyword = call.arguments.keywords.get((index - call.arguments.args.len() as u32) as usize);
170173
}
171174
let mut arg_index = 0;
172-
if is_on_instance {
175+
if is_on_instance.is_some() {
173176
arg_index += 1;
174177
}
175178
if let Some(keyword) = call_arg_keyword {

server/src/core/symbols/symbol.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2111,7 +2111,14 @@ impl Symbol {
21112111
match sym {
21122112
EvaluationSymbolPtr::WEAK(ref mut w) => {
21132113
if let Some(base_attr) = symbol_context.get(&S!("base_attr")) {
2114-
w.context.insert(S!("base_attr"), base_attr.clone());
2114+
if !w.context.get(&S!("is_attr_of_instance")).map(|x| x.as_bool()).unwrap_or(false) {
2115+
w.context.insert(S!("base_attr"), base_attr.clone());
2116+
}
2117+
}
2118+
if let Some(base_attr) = symbol_context.get(&S!("is_attr_of_instance")) {
2119+
if !w.context.get(&S!("is_attr_of_instance")).map(|x| x.as_bool()).unwrap_or(false) {
2120+
w.context.insert(S!("is_attr_of_instance"), base_attr.clone());
2121+
}
21152122
}
21162123
},
21172124
_ => {}
@@ -2148,6 +2155,15 @@ impl Symbol {
21482155
if results.is_empty() {
21492156
return vec![evaluation.clone()];
21502157
}
2158+
if w.instance.is_some_and(|v| v) {
2159+
//if the previous evaluation was set to True, we want to keep it
2160+
results = results.into_iter().map(|mut r| {
2161+
if let EvaluationSymbolPtr::WEAK(ref mut weak) = r {
2162+
weak.instance = Some(true);
2163+
}
2164+
r
2165+
}).collect();
2166+
}
21512167
let mut acc: PtrWeakHashSet<Weak<RefCell<Symbol>>> = PtrWeakHashSet::new();
21522168
let can_eval_external = !symbol.borrow().is_external();
21532169
let mut index = 0;
@@ -2157,6 +2173,7 @@ impl Symbol {
21572173
match next_ref {
21582174
EvaluationSymbolPtr::WEAK(next_ref_weak) => {
21592175
let sym = next_ref_weak.weak.upgrade();
2176+
let next_ref_weak_instance = next_ref_weak.instance.clone();
21602177
if sym.is_none() {
21612178
index += 1;
21622179
continue;
@@ -2193,10 +2210,17 @@ impl Symbol {
21932210
}
21942211
}
21952212
}
2196-
let next_sym_refs = Symbol::next_refs(session, sym_rc.clone(), context, &next_ref_weak.context, stop_on_type, &mut vec![]);
2213+
let mut next_sym_refs = Symbol::next_refs(session, sym_rc.clone(), context, &next_ref_weak.context, stop_on_type, &mut vec![]);
21972214
if !next_sym_refs.is_empty() {
21982215
results.pop_front();
21992216
index -= 1;
2217+
// /!\ we want to keep instance = True if previous evaluation was set to True!
2218+
if next_ref_weak_instance.is_some_and(|v| v) {
2219+
next_sym_refs = next_sym_refs.into_iter().map(|mut next_results| {
2220+
next_results.as_mut_weak().instance = Some(true);
2221+
next_results
2222+
}).collect();
2223+
}
22002224
for next_results in next_sym_refs {
22012225
results.push_back(next_results);
22022226
}

server/src/features/ast_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ impl AstUtils {
4141
(S!("module"), from_module),
4242
(S!("range"), ContextValue::RANGE(expr.range()))
4343
]));
44-
let analyse_ast_result: AnalyzeAstResult = Evaluation::analyze_ast(session, &expr, parent_symbol.clone(), &expr.range().end(), &mut context, &mut vec![]);
44+
let analyse_ast_result: AnalyzeAstResult = Evaluation::analyze_ast(session, &expr, parent_symbol.clone(), &expr.range().end(), &mut context,false, &mut vec![]);
4545
(analyse_ast_result, Some(expr.range()), call_expr)
4646

4747
}

0 commit comments

Comments
 (0)