Skip to content

Commit f1a2a7b

Browse files
committed
补充语法初检状态聚合及误报边界测试
1 parent 5579b69 commit f1a2a7b

9 files changed

Lines changed: 404 additions & 1 deletion

File tree

‎crates/codeguard-core/src/lib.rs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ mod native_checker_binding;
1414
mod obligation_result;
1515
mod observation_port;
1616
mod repository_path_safety;
17+
mod syntax_file_observation;
18+
mod syntax_file_state;
19+
mod syntax_precheck;
20+
mod syntax_precheck_outcome;
21+
mod syntax_precheck_status;
1722
mod syntax_recovery_anchor;
1823
mod task_graph;
1924
mod task_node;
@@ -44,6 +49,11 @@ pub use native_checker_binding::NativeCheckerBinding;
4449
pub use obligation_result::ObligationResult;
4550
pub use observation_port::{ObservationPort, ObservedPathKind};
4651
pub use repository_path_safety::{RepositoryPathViolation, check_repository_paths};
52+
pub use syntax_file_observation::SyntaxFileObservation;
53+
pub use syntax_file_state::SyntaxFileState;
54+
pub use syntax_precheck::assess_syntax_precheck;
55+
pub use syntax_precheck_outcome::SyntaxPrecheckOutcome;
56+
pub use syntax_precheck_status::SyntaxPrecheckStatus;
4757
pub use syntax_recovery_anchor::SyntaxRecoveryAnchor;
4858
pub use task_graph::{TaskGraph, TaskGraphError};
4959
pub use task_node::TaskNode;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use serde::Serialize;
2+
3+
use crate::SyntaxFileState;
4+
5+
/// 已选范围中一个文件的观察,path 为工作区相对路径。
6+
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
7+
pub struct SyntaxFileObservation {
8+
/// 文件的工作区相对路径。
9+
pub path: String,
10+
/// 该文件的实际解析状态。
11+
pub state: SyntaxFileState,
12+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use serde::Serialize;
2+
3+
/// 单个已选源码文件的语法初检观察;不表示原生 lint 或编译结果。
4+
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
5+
#[serde(tag = "status", rename_all = "snake_case")]
6+
pub enum SyntaxFileState {
7+
/// 已解析;grammar_qualified 仅表示该文件的版本与方言已被验收。
8+
Checked {
9+
/// ERROR/MISSING 原始恢复节点数,尚未确认是否为源码违规。
10+
recoveries: usize,
11+
/// 该文件版本与方言是否落在已验收范围内。
12+
grammar_qualified: bool,
13+
/// 恢复节点或遍历预算是否截断。
14+
truncated: bool,
15+
},
16+
/// 解析、位置映射、预算或输入身份等未能完成。
17+
Incomplete {
18+
/// 具体失败原因。
19+
reason: String,
20+
},
21+
/// 不支持的文件、语言区域或方言。
22+
Unsupported {
23+
/// 具体不支持原因。
24+
reason: String,
25+
},
26+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use std::collections::BTreeSet;
2+
3+
use crate::{SyntaxFileObservation, SyntaxFileState, SyntaxPrecheckOutcome, SyntaxPrecheckStatus};
4+
5+
/// 按选定文件范围聚合语法初检;枚举中断、取消、未知版本和局部失败不能成为 clean。
6+
/// 参数为每个已选文件的唯一观察、范围是否完成及取消状态;返回初检状态或输入契约错误。
7+
pub fn assess_syntax_precheck(
8+
files: &[SyntaxFileObservation],
9+
scope_complete: bool,
10+
cancelled: bool,
11+
) -> Result<SyntaxPrecheckOutcome, &'static str> {
12+
let mut paths = BTreeSet::new();
13+
let mut outcome = SyntaxPrecheckOutcome {
14+
status: SyntaxPrecheckStatus::NotRun,
15+
scope_complete,
16+
cancelled,
17+
selected_files: files.len(),
18+
checked_files: 0,
19+
incomplete_files: 0,
20+
unsupported_files: 0,
21+
unqualified_files: 0,
22+
truncated_files: 0,
23+
suspected_recoveries: 0,
24+
};
25+
for file in files {
26+
if !valid_relative_path(&file.path) || !paths.insert(file.path.as_str()) {
27+
return Err("syntax_scope_invalid_or_duplicate_path");
28+
}
29+
match &file.state {
30+
SyntaxFileState::Checked {
31+
recoveries,
32+
grammar_qualified,
33+
truncated,
34+
} => {
35+
outcome.checked_files += 1;
36+
outcome.suspected_recoveries = outcome
37+
.suspected_recoveries
38+
.checked_add(*recoveries)
39+
.ok_or("syntax_recovery_count_overflow")?;
40+
if !grammar_qualified {
41+
outcome.unqualified_files += 1;
42+
}
43+
if *truncated {
44+
outcome.truncated_files += 1;
45+
}
46+
}
47+
SyntaxFileState::Incomplete { reason } => {
48+
if reason.is_empty() {
49+
return Err("syntax_incomplete_reason_missing");
50+
}
51+
outcome.incomplete_files += 1;
52+
}
53+
SyntaxFileState::Unsupported { reason } => {
54+
if reason.is_empty() {
55+
return Err("syntax_unsupported_reason_missing");
56+
}
57+
outcome.unsupported_files += 1;
58+
}
59+
}
60+
}
61+
outcome.status = if !scope_complete || cancelled {
62+
SyntaxPrecheckStatus::Incomplete
63+
} else if files.is_empty() {
64+
SyntaxPrecheckStatus::NotRun
65+
} else if outcome.unsupported_files == files.len() {
66+
SyntaxPrecheckStatus::Unsupported
67+
} else if outcome.incomplete_files > 0
68+
|| outcome.unsupported_files > 0
69+
|| outcome.unqualified_files > 0
70+
|| outcome.truncated_files > 0
71+
{
72+
SyntaxPrecheckStatus::Incomplete
73+
} else if outcome.suspected_recoveries > 0 {
74+
SyntaxPrecheckStatus::SuspectedIssue
75+
} else {
76+
SyntaxPrecheckStatus::Clean
77+
};
78+
Ok(outcome)
79+
}
80+
81+
fn valid_relative_path(path: &str) -> bool {
82+
!path.is_empty()
83+
&& !path.starts_with('/')
84+
&& !path.contains('\\')
85+
&& !path.chars().any(char::is_control)
86+
&& path
87+
.split('/')
88+
.all(|part| !part.is_empty() && part != "." && part != "..")
89+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use serde::Serialize;
2+
3+
use crate::SyntaxPrecheckStatus;
4+
5+
/// 选定文件集的纯领域聚合;不能作为 lint 通过或项目门禁依据。
6+
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
7+
pub struct SyntaxPrecheckOutcome {
8+
/// 总体初检状态。
9+
pub status: SyntaxPrecheckStatus,
10+
/// 选定范围的枚举与输入核对是否完成。
11+
pub scope_complete: bool,
12+
/// 本次初检是否收到取消请求。
13+
pub cancelled: bool,
14+
/// 选定源码文件数。
15+
pub selected_files: usize,
16+
/// 已解析文件数,含版本/方言尚未验收者。
17+
pub checked_files: usize,
18+
/// 解析或输入核对未完成的文件数。
19+
pub incomplete_files: usize,
20+
/// 不支持的文件数。
21+
pub unsupported_files: usize,
22+
/// 虽已解析但 grammar 版本/方言未获验收的文件数。
23+
pub unqualified_files: usize,
24+
/// 恢复节点或遍历预算截断的文件数。
25+
pub truncated_files: usize,
26+
/// 已观察 ERROR/MISSING 数;疑似观察不等于原生违规。
27+
pub suspected_recoveries: usize,
28+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use serde::Serialize;
2+
3+
/// 语法初检的总体状态,与原生检查和交付结论分离。
4+
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
5+
#[serde(rename_all = "snake_case")]
6+
pub enum SyntaxPrecheckStatus {
7+
/// 没有选定文件,初检没有执行。
8+
NotRun,
9+
/// 非空选定范围全部由已验收 grammar 检查,且无恢复节点。
10+
Clean,
11+
/// 完整初检观察到 ERROR/MISSING,仍需原生确认。
12+
SuspectedIssue,
13+
/// 有未完成或范围混合缺口;已观察疑似节点仍保留。
14+
Incomplete,
15+
/// 全部选定文件均不受支持。
16+
Unsupported,
17+
}

0 commit comments

Comments
 (0)