Skip to content

Commit 64956d6

Browse files
committed
add access visiblity check
1 parent 9bf87c1 commit 64956d6

File tree

4 files changed

+161
-3
lines changed

4 files changed

+161
-3
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
use emmylua_parser::{LuaAst, LuaAstNode, LuaAstToken, LuaIndexExpr, LuaNameExpr, VisibilityKind};
2+
use rowan::TextRange;
3+
4+
use crate::{DiagnosticCode, Emmyrc, LuaPropertyOwnerId, SemanticModel};
5+
6+
use super::DiagnosticContext;
7+
8+
pub const CODES: &[DiagnosticCode] = &[DiagnosticCode::AccessInvisible];
9+
10+
pub fn check(context: &mut DiagnosticContext, semantic_model: &mut SemanticModel) -> Option<()> {
11+
let file_id = semantic_model.get_file_id();
12+
let root = semantic_model.get_root().clone();
13+
for node in root.descendants::<LuaAst>() {
14+
match node {
15+
LuaAst::LuaNameExpr(name_expr) => {
16+
if semantic_model
17+
.get_db()
18+
.get_reference_index()
19+
.is_write_range(file_id, name_expr.get_range())
20+
{
21+
continue;
22+
}
23+
check_name_expr(context, semantic_model, name_expr);
24+
}
25+
LuaAst::LuaIndexExpr(index_expr) => {
26+
if semantic_model
27+
.get_db()
28+
.get_reference_index()
29+
.is_write_range(file_id, index_expr.get_range())
30+
{
31+
continue;
32+
}
33+
check_index_expr(context, semantic_model, index_expr);
34+
}
35+
_ => {}
36+
}
37+
}
38+
39+
Some(())
40+
}
41+
42+
fn check_name_expr(
43+
context: &mut DiagnosticContext,
44+
semantic_model: &mut SemanticModel,
45+
name_expr: LuaNameExpr,
46+
) -> Option<()> {
47+
let property_owner = semantic_model
48+
.get_property_owner_id(rowan::NodeOrToken::Node(name_expr.syntax().clone()))?;
49+
50+
let name_token = name_expr.get_name_token()?;
51+
if !semantic_model.is_property_visiable(name_token.syntax().clone(), property_owner.clone()) {
52+
let emmyrc = semantic_model.get_emmyrc();
53+
report_reson(context, &emmyrc, name_token.get_range(), property_owner);
54+
}
55+
Some(())
56+
}
57+
58+
fn check_index_expr(
59+
context: &mut DiagnosticContext,
60+
semantic_model: &mut SemanticModel,
61+
index_expr: LuaIndexExpr,
62+
) -> Option<()> {
63+
let property_owner = semantic_model
64+
.get_property_owner_id(rowan::NodeOrToken::Node(index_expr.syntax().clone()))?;
65+
66+
let index_token = index_expr.get_index_name_token()?;
67+
if !semantic_model.is_property_visiable(index_token.clone(), property_owner.clone()) {
68+
let emmyrc = semantic_model.get_emmyrc();
69+
report_reson(context, &emmyrc, index_token.text_range(), property_owner);
70+
}
71+
72+
Some(())
73+
}
74+
75+
fn report_reson(
76+
context: &mut DiagnosticContext,
77+
emmyrc: &Emmyrc,
78+
range: TextRange,
79+
property_owner_id: LuaPropertyOwnerId,
80+
) -> Option<()> {
81+
let property = context
82+
.db
83+
.get_property_index()
84+
.get_property(property_owner_id)?;
85+
86+
if let Some(version_conds) = &property.version_conds {
87+
let version_number = emmyrc.runtime.version.to_lua_version_number();
88+
let visiable = version_conds.iter().any(|cond| cond.check(&version_number));
89+
if !visiable {
90+
let message = t!(
91+
"The current Lua version %{version} is not accessible; expected %{conds}.",
92+
version = version_number,
93+
conds = version_conds
94+
.iter()
95+
.map(|it| format!("{}", it))
96+
.collect::<Vec<_>>()
97+
.join(", ")
98+
);
99+
100+
context.add_diagnostic(
101+
DiagnosticCode::AccessInvisible,
102+
range,
103+
message.to_string(),
104+
None,
105+
);
106+
return Some(());
107+
}
108+
}
109+
110+
if let Some(visiblity) = property.visibility {
111+
let message = match visiblity {
112+
VisibilityKind::Protected => {
113+
t!("The property is protected and cannot be accessed outside its subclasses.")
114+
}
115+
VisibilityKind::Private => {
116+
t!("The property is private and cannot be accessed outside the class.")
117+
}
118+
VisibilityKind::Package => {
119+
t!("The property is package-private and cannot be accessed outside the package.")
120+
}
121+
_ => {
122+
return None;
123+
}
124+
};
125+
126+
context.add_diagnostic(
127+
DiagnosticCode::AccessInvisible,
128+
range,
129+
message.to_string(),
130+
None,
131+
);
132+
}
133+
134+
Some(())
135+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod syntax_error;
33
mod unused;
44
mod deprecated;
55
mod undefined_global;
6+
mod access_invisible;
67

78
use lsp_types::{Diagnostic, DiagnosticSeverity, DiagnosticTag, NumberOrString};
89
use rowan::TextRange;
@@ -32,6 +33,7 @@ pub fn check_file(context: &mut DiagnosticContext, semantic_model:&mut SemanticM
3233
check!(unused);
3334
check!(deprecated);
3435
check!(undefined_global);
36+
check!(access_invisible);
3537

3638
Some(())
3739
}

crates/code_analysis/src/diagnostic/lua_diagnostic_code.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ pub enum DiagnosticCode {
2828
UndefinedGlobal,
2929
/// Deprecated
3030
Deprecated,
31-
/// Access invisible member
32-
AccessInvisibleMember,
31+
/// Access invisible
32+
AccessInvisible,
3333
/// Discard return value
3434
DiscardReturns,
3535
/// Disable global define
@@ -70,7 +70,7 @@ pub fn get_default_severity(code: DiagnosticCode) -> DiagnosticSeverity {
7070
DiagnosticCode::Unused => DiagnosticSeverity::HINT,
7171
DiagnosticCode::UndefinedGlobal => DiagnosticSeverity::ERROR,
7272
DiagnosticCode::Deprecated => DiagnosticSeverity::HINT,
73-
DiagnosticCode::AccessInvisibleMember => DiagnosticSeverity::WARNING,
73+
DiagnosticCode::AccessInvisible => DiagnosticSeverity::WARNING,
7474
DiagnosticCode::DiscardReturns => DiagnosticSeverity::WARNING,
7575
DiagnosticCode::DisableGlobalDefine => DiagnosticSeverity::ERROR,
7676
DiagnosticCode::UndefinedField => DiagnosticSeverity::WARNING,

crates/emmylua_parser/src/kind/lua_version.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::fmt;
2+
13
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24
pub struct LuaVersionNumber {
35
pub major: u32,
@@ -54,6 +56,15 @@ impl Ord for LuaVersionNumber {
5456
}
5557
}
5658

59+
impl fmt::Display for LuaVersionNumber {
60+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61+
match *self {
62+
LuaVersionNumber::LUA_JIT => write!(f, "Lua JIT"),
63+
LuaVersionNumber { major, minor, .. } => write!(f, "Lua {}.{}", major, minor),
64+
}
65+
}
66+
}
67+
5768
#[allow(unused)]
5869
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5970
pub enum LuaVersionCondition {
@@ -71,4 +82,14 @@ impl LuaVersionCondition {
7182
LuaVersionCondition::Lte(v) => version <= v,
7283
}
7384
}
85+
}
86+
87+
impl fmt::Display for LuaVersionCondition {
88+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89+
match self {
90+
LuaVersionCondition::Eq(v) => write!(f, "{}", v),
91+
LuaVersionCondition::Gte(v) => write!(f, ">= {}", v),
92+
LuaVersionCondition::Lte(v) => write!(f, "<= {}", v),
93+
}
94+
}
7495
}

0 commit comments

Comments
 (0)