feat: release Dever 0.1.4 with enforceable project guidance
This commit is contained in:
1 parent
201bdee372
commit
89629c2197
86 files changed
+2798
-338
No files matched your search
@@ -17,24 +17,51 @@ pub(crate) fn check(program: &mut Program) {
|
||||
continue;
|
||||
}
|
||||
if !function.public {
|
||||
let key = (function.owner, function_key(function));
|
||||
if let Some(previous) = implementations.get(&key).copied() {
|
||||
let previous: &Function = &program.functions[previous];
|
||||
warnings.push(related("W003", format!("private function '{}' has the same implementation and contract as '{}'; consider sharing one implementation", function.name, previous.name), function.span, previous.span));
|
||||
} else {
|
||||
implementations.insert(key, id);
|
||||
if let Some(target) = forwarding_target(function, program) {
|
||||
warnings.push(related("W005", format!("private function '{}' only forwards unchanged inputs to '{}' without adding a contract; review whether this wrapper is needed", function.name, target.name), function.span, target.span));
|
||||
}
|
||||
if let Some(duplicate) =
|
||||
duplicate_implementation(program, id, &mut implementations, "W003")
|
||||
{
|
||||
warnings.push(duplicate);
|
||||
} else if let Some(target) = forwarding_target(function, program) {
|
||||
warnings.push(related("W005", format!("private function '{}' only forwards unchanged inputs to '{}' without adding a contract; review whether this wrapper is needed", function.name, target.name), function.span, target.span));
|
||||
}
|
||||
}
|
||||
for clause in &function.clauses {
|
||||
repeated_calls(clause, program, &mut warnings);
|
||||
repeated_calls(clause, program, "W004", &mut warnings);
|
||||
}
|
||||
}
|
||||
program.warnings.extend(warnings);
|
||||
}
|
||||
|
||||
fn duplicate_implementation(
|
||||
program: &Program,
|
||||
id: usize,
|
||||
implementations: &mut BTreeMap<(usize, String), usize>,
|
||||
code: &'static str,
|
||||
) -> Option<Diagnostic> {
|
||||
let function = &program.functions[id];
|
||||
let key = (function.owner, function_key(function));
|
||||
if let Some(previous) = implementations.get(&key).copied() {
|
||||
let previous = &program.functions[previous];
|
||||
let action = if code == "C016" {
|
||||
"reuse one implementation"
|
||||
} else {
|
||||
"consider sharing one implementation"
|
||||
};
|
||||
Some(related(
|
||||
code,
|
||||
format!(
|
||||
"private function '{}' has the same implementation and contract as '{}'; {action}",
|
||||
function.name, previous.name
|
||||
),
|
||||
function.span,
|
||||
previous.span,
|
||||
))
|
||||
} else {
|
||||
implementations.insert(key, id);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn related(code: &'static str, message: String, primary: Span, previous: Span) -> Diagnostic {
|
||||
let mut warning = Diagnostic::error(code, message, primary);
|
||||
warning.related.push(Label {
|
||||
@@ -291,7 +318,12 @@ struct Computation {
|
||||
result_version: usize,
|
||||
}
|
||||
|
||||
fn repeated_calls(clause: &Clause, program: &Program, warnings: &mut Vec<Diagnostic>) {
|
||||
fn repeated_calls(
|
||||
clause: &Clause,
|
||||
program: &Program,
|
||||
code: &'static str,
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
) {
|
||||
let mut versions = vec![0; clause.locals.len()];
|
||||
let mut previous = BTreeMap::<String, Computation>::new();
|
||||
for statement in &clause.body {
|
||||
@@ -310,7 +342,17 @@ fn repeated_calls(clause: &Clause, program: &Program, warnings: &mut Vec<Diagnos
|
||||
if let Some(computation) = previous.get(&key)
|
||||
&& versions[computation.result_slot] == computation.result_version
|
||||
{
|
||||
warnings.push(related("W004", "this pure call repeats unchanged inputs while the earlier result is still available; consider reusing that result".into(), value.span, computation.span));
|
||||
let action = if code == "C016" {
|
||||
"reuse that result"
|
||||
} else {
|
||||
"consider reusing that result"
|
||||
};
|
||||
diagnostics.push(related(
|
||||
code,
|
||||
format!("this pure call repeats unchanged inputs while the earlier result is still available; {action}"),
|
||||
value.span,
|
||||
computation.span,
|
||||
));
|
||||
}
|
||||
}
|
||||
// A field write invalidates every projection from the containing value.
|
||||
@@ -360,6 +402,7 @@ pub(crate) fn application_errors(
|
||||
reachable: &BTreeSet<usize>,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut errors = Vec::new();
|
||||
let mut implementations = BTreeMap::new();
|
||||
for (id, function) in program.functions.iter().enumerate() {
|
||||
let package = &program.packages[function.owner];
|
||||
if package.bundled || function.port.is_some() || function.setting.is_some() {
|
||||
@@ -379,12 +422,27 @@ pub(crate) fn application_errors(
|
||||
),
|
||||
function.span,
|
||||
));
|
||||
} else if !function.public {
|
||||
continue;
|
||||
}
|
||||
if !function.public {
|
||||
// Model 查询等有副作用的操作还需比较此结构键未记录的元数据。
|
||||
if program.effects[id].is_empty()
|
||||
&& let Some(duplicate) =
|
||||
duplicate_implementation(program, id, &mut implementations, "C016")
|
||||
{
|
||||
errors.push(duplicate);
|
||||
continue;
|
||||
}
|
||||
if let Some(target) = forwarding_target(function, program) {
|
||||
errors.push(related("C016", format!("private function '{}' only forwards unchanged inputs to '{}' without adding a contract", function.name, target.name), function.span, target.span));
|
||||
continue;
|
||||
}
|
||||
} else if app && trivial_model_wrapper(function) {
|
||||
errors.push(Diagnostic::error("C016", format!("App function '{}' only forwards a Model CRUD operation; declare rest for plain CRUD", function.name), function.span));
|
||||
continue;
|
||||
}
|
||||
for clause in &function.clauses {
|
||||
repeated_calls(clause, program, "C016", &mut errors);
|
||||
}
|
||||
}
|
||||
errors.sort_by_key(|error| (error.primary.source, error.primary.start));
|
||||
|
||||
Reference in new issue
Block a user