Skip to content

Commit 2725d5e

Browse files
committed
support undfined_global check
1 parent 3be9fa9 commit 2725d5e

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

crates/code_analysis/src/diagnostic/checker/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod analyze_error;
22
mod syntax_error;
33
mod unused;
44
mod deprecated;
5+
mod undefined_global;
56

67
use lsp_types::{Diagnostic, DiagnosticSeverity, DiagnosticTag, NumberOrString};
78
use rowan::TextRange;
@@ -30,6 +31,7 @@ pub fn check_file(context: &mut DiagnosticContext, semantic_model:&mut SemanticM
3031
check!(analyze_error);
3132
check!(unused);
3233
check!(deprecated);
34+
check!(undefined_global);
3335

3436
Some(())
3537
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
use std::collections::HashSet;
2+
3+
use emmylua_parser::{LuaAstNode, LuaNameExpr};
4+
use rowan::TextRange;
5+
6+
use crate::{DiagnosticCode, LuaMemberKey, SemanticModel};
7+
8+
use super::DiagnosticContext;
9+
10+
pub const CODES: &[DiagnosticCode] = &[DiagnosticCode::UndefinedGlobal];
11+
12+
pub fn check(context: &mut DiagnosticContext, semantic_model: &SemanticModel) -> Option<()> {
13+
let root = semantic_model.get_root().clone();
14+
let mut use_range_set = HashSet::new();
15+
calc_name_expr_ref(semantic_model, &mut use_range_set);
16+
for name_expr in root.descendants::<LuaNameExpr>() {
17+
check_name_expr(context, semantic_model, &mut use_range_set, name_expr);
18+
}
19+
20+
Some(())
21+
}
22+
23+
fn calc_name_expr_ref(
24+
semantic_model: &SemanticModel,
25+
use_range_set: &mut HashSet<TextRange>,
26+
) -> Option<()> {
27+
let file_id = semantic_model.get_file_id();
28+
let db = semantic_model.get_db();
29+
let refs_index = db.get_reference_index().get_local_reference(&file_id)?;
30+
for (_, ranges) in refs_index.get_local_references_map() {
31+
for range in ranges {
32+
use_range_set.insert(range.clone());
33+
}
34+
}
35+
36+
None
37+
}
38+
39+
fn check_name_expr(
40+
context: &mut DiagnosticContext,
41+
semantic_model: &SemanticModel,
42+
use_range_set: &mut HashSet<TextRange>,
43+
name_expr: LuaNameExpr,
44+
) -> Option<()> {
45+
let name_range = name_expr.get_range();
46+
if use_range_set.contains(&name_range) {
47+
return Some(());
48+
}
49+
50+
let name_text = name_expr.get_name_text()?;
51+
if name_text == "self" || name_text == "_" {
52+
return Some(());
53+
}
54+
55+
let decl_index = semantic_model.get_db().get_decl_index();
56+
let member_key = LuaMemberKey::Name(name_text.clone().into());
57+
if decl_index.get_global_decl_id(&member_key).is_some() {
58+
return Some(());
59+
}
60+
61+
let emmyrc = semantic_model.get_emmyrc();
62+
if emmyrc.diagnostics.globals.contains(&name_text) {
63+
return Some(());
64+
}
65+
66+
context.add_diagnostic(
67+
DiagnosticCode::UndefinedGlobal,
68+
name_range,
69+
t!("undefined global variable: %{name}", name = name_text).to_string(),
70+
None,
71+
);
72+
73+
Some(())
74+
}

0 commit comments

Comments
 (0)