From 36313f09152dba1ec18d65646a1ceff598a10d8f Mon Sep 17 00:00:00 2001 From: William Wallace Date: Fri, 8 May 2020 17:42:34 +0100 Subject: [PATCH] emit error when proc is defined multiple times (#181) * emit error when proc is defined multiple times * simplify * simpler Co-authored-by: spookydonut --- CONFIGURING.md | 1 + src/dreamchecker/README.md | 7 ++++++ src/dreamchecker/lib.rs | 12 +++++++++- src/dreamchecker/tests/directive_tests.rs | 29 +++++++++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/CONFIGURING.md b/CONFIGURING.md index f31fcf65..1f5e6fdd 100644 --- a/CONFIGURING.md +++ b/CONFIGURING.md @@ -38,6 +38,7 @@ Raised by DreamChecker: * `protected_var` - `SpacemanDMM_protected` var type * `must_be_pure` - `SpacemanDMM_should_be_pure` directive * `must_not_sleep` - `SpacemanDMM_should_not_sleep` directive +* `redefined_proc` - `SpacemanDMM_can_be_redefined` directive * `ambiguous_in_lhs` - Raised on ambiguous operations on the left hand side of an `in` operation * `no_typehint_implicit_new` - Raised on the use of `new` where no typehint is avaliable * `field_access_static_type` - Raised on using `.field_name` on a variable with no typehint diff --git a/src/dreamchecker/README.md b/src/dreamchecker/README.md index ba5faa55..7af0d2e6 100644 --- a/src/dreamchecker/README.md +++ b/src/dreamchecker/README.md @@ -65,6 +65,7 @@ be enabled: #define SHOULD_BE_PURE(X) set SpacemanDMM_should_be_pure = X #define PRIVATE_PROC(X) set SpacemanDMM_private_proc = X #define PROTECTED_PROC(X) set SpacemanDMM_protected_proc = X + #define CAN_BE_REDEFINED(X) set SpacemanDMM_can_be_redefined = X #define VAR_FINAL var/SpacemanDMM_final #define VAR_PRIVATE var/SpacemanDMM_private #define VAR_PROTECTED var/SpacemanDMM_protected @@ -77,6 +78,7 @@ be enabled: #define SHOULD_BE_PURE(X) #define PRIVATE_PROC(X) #define PROTECTED_PROC(X) + #define CAN_BE_REDEFINED(X) #define VAR_FINAL var #define VAR_PRIVATE var #define VAR_PROTECTED var @@ -153,3 +155,8 @@ This also checks to make sure anything using this proc doesn't invoke it without making use of the return value. This cannot be disabled by child overrides. + +## Proc redefinitions + +Multiple definitions of a proc in the same type-path will raise a warning. +Use `set SpacemanDMM_can_be_redefined = 1` to allow a proc to be redefined. diff --git a/src/dreamchecker/lib.rs b/src/dreamchecker/lib.rs index f795844a..16707510 100644 --- a/src/dreamchecker/lib.rs +++ b/src/dreamchecker/lib.rs @@ -533,6 +533,7 @@ pub struct AnalyzeObjectTree<'o> { must_not_sleep: ProcDirective<'o>, sleep_exempt: ProcDirective<'o>, must_be_pure: ProcDirective<'o>, + can_be_redefined: ProcDirective<'o>, // Debug(ProcRef) -> KwargInfo used_kwargs: BTreeMap, @@ -559,6 +560,7 @@ impl<'o> AnalyzeObjectTree<'o> { must_not_sleep: ProcDirective::new("SpacemanDMM_should_not_sleep", false, true, true), sleep_exempt: ProcDirective::new("SpacemanDMM_allowed_to_sleep", false, true, true), must_be_pure: ProcDirective::new("SpacemanDMM_should_be_pure", false, true, true), + can_be_redefined: ProcDirective::new("SpacemanDMM_can_be_redefined", false, false, false), used_kwargs: Default::default(), call_tree: Default::default(), sleeping_procs: Default::default(), @@ -582,6 +584,7 @@ impl<'o> AnalyzeObjectTree<'o> { "SpacemanDMM_should_not_sleep" => &mut self.must_not_sleep, "SpacemanDMM_allowed_to_sleep" => &mut self.sleep_exempt, "SpacemanDMM_should_be_pure" => &mut self.must_be_pure, + "SpacemanDMM_can_be_redefined" => &mut self.can_be_redefined, other => { error(location, format!("unknown linter setting {:?}", directive)) .with_errortype("unknown_linter_setting") @@ -1113,7 +1116,7 @@ impl<'o, 's> AnalyzeProc<'o, 's> { //println!("purity {}", self.is_pure); - if self.proc_ref.parent_proc().is_some() { + if let Some(parent) = self.proc_ref.parent_proc() { if let Some((proc, true, location)) = self.env.private.get_self_or_parent(self.proc_ref) { if proc != self.proc_ref { error(self.proc_ref.location, format!("proc overrides private parent, prohibited by {}", proc)) @@ -1138,6 +1141,13 @@ impl<'o, 's> AnalyzeProc<'o, 's> { .register(self.context); } } + if !parent.is_builtin() && self.proc_ref.ty() == parent.ty() + && self.env.can_be_redefined.get_self_or_parent(self.proc_ref).is_none() { + error(self.proc_ref.location, format!("redefining proc {}/{}", self.ty, self.proc_ref.name())) + .with_errortype("redefined_proc") + .with_note(parent.location, "previous definition is here") + .register(self.context); + } } } diff --git a/src/dreamchecker/tests/directive_tests.rs b/src/dreamchecker/tests/directive_tests.rs index bb2315e9..d40d4d3b 100644 --- a/src/dreamchecker/tests/directive_tests.rs +++ b/src/dreamchecker/tests/directive_tests.rs @@ -79,3 +79,32 @@ fn no_override_disable() { "##.trim(); check_errors_match(code, NO_OVERRIDE_DISABLE_ERRORS); } + +#[test] +fn can_be_redefined() { + let code = r##" +/mob/proc/test() + set SpacemanDMM_can_be_redefined = 1 + return + +/mob/test() + return +"##.trim(); + check_errors_match(code, NO_ERRORS); +} + +pub const NO_CAN_BE_REDEFINED_ERRORS: &[(u32, u16, &str)] = &[ + (4, 10, "redefining proc /mob/test"), +]; + +#[test] +fn no_can_be_redefined() { + let code = r##" +/mob/proc/test() + return + +/mob/test() + return +"##.trim(); + check_errors_match(code, NO_CAN_BE_REDEFINED_ERRORS); +} \ No newline at end of file