Skip to content

Commit c48e9cd

Browse files
authored
Disable alias recursion (for real) (#8557)
1 parent 6a274b8 commit c48e9cd

2 files changed

Lines changed: 48 additions & 67 deletions

File tree

crates/nu-command/tests/commands/alias.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use nu_test_support::fs::Stub::FileWithContentToBeTrimmed;
2+
use nu_test_support::playground::Playground;
13
use nu_test_support::{nu, pipeline};
24

35
#[ignore = "TODO?: Aliasing parser keywords does not work anymore"]
@@ -110,3 +112,28 @@ fn alias_wont_recurse() {
110112
assert_eq!(actual.out, "hello world");
111113
assert!(actual.err.is_empty());
112114
}
115+
116+
// Issue https://github.com/nushell/nushell/issues/8246
117+
#[test]
118+
fn alias_wont_recurse2() {
119+
Playground::setup("alias_wont_recurse2", |dirs, sandbox| {
120+
sandbox.with_files(vec![FileWithContentToBeTrimmed(
121+
"spam.nu",
122+
r#"
123+
def eggs [] { spam 'eggs' }
124+
alias spam = spam 'spam'
125+
"#,
126+
)]);
127+
let actual = nu!(
128+
cwd: dirs.test(), pipeline(
129+
r#"
130+
def spam [what: string] { 'spam ' + $what };
131+
source spam.nu;
132+
spam
133+
"#
134+
));
135+
136+
assert_eq!(actual.out, "spam spam");
137+
assert!(actual.err.is_empty());
138+
})
139+
}

crates/nu-parser/src/parse_keywords.rs

Lines changed: 21 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -189,34 +189,6 @@ pub fn parse_def_predecl(
189189
signature,
190190
};
191191

192-
if working_set.add_predecl(Box::new(decl)).is_some() {
193-
return Some(ParseError::DuplicateCommandDef(spans[1]));
194-
}
195-
}
196-
} else if name == b"alias" && spans.len() >= 4 {
197-
let (name_expr, ..) = parse_string(working_set, spans[1], expand_aliases_denylist);
198-
let name = name_expr.as_string();
199-
200-
if let Some(name) = name {
201-
if name.contains('#')
202-
|| name.contains('^')
203-
|| name.parse::<bytesize::ByteSize>().is_ok()
204-
|| name.parse::<f64>().is_ok()
205-
{
206-
return Some(ParseError::CommandDefNotValid(spans[1]));
207-
}
208-
209-
// The signature will get replaced by the replacement signature
210-
// let mut signature = Signature::new(name.clone());
211-
// signature.name = name;
212-
213-
// The fields get replaced during parsing
214-
let decl = Alias {
215-
name,
216-
command: None,
217-
wrapped_call: Expression::garbage(name_expr.span),
218-
};
219-
220192
if working_set.add_predecl(Box::new(decl)).is_some() {
221193
return Some(ParseError::DuplicateCommandDef(spans[1]));
222194
}
@@ -780,19 +752,31 @@ pub fn parse_alias(
780752
alias_name.to_vec()
781753
};
782754

755+
let checked_name = String::from_utf8_lossy(&alias_name).to_string();
756+
if checked_name.contains('#')
757+
|| checked_name.contains('^')
758+
|| checked_name.parse::<bytesize::ByteSize>().is_ok()
759+
|| checked_name.parse::<f64>().is_ok()
760+
{
761+
return (
762+
Pipeline::from_vec(vec![garbage(name_span)]),
763+
Some(ParseError::AliasNotValid(name_span)),
764+
);
765+
}
766+
783767
if let Some(mod_name) = module_name {
784-
if alias_name == mod_name {
768+
if checked_name.as_bytes() == mod_name {
785769
return (
786770
alias_pipeline,
787771
Some(ParseError::NamedAsModule(
788772
"alias".to_string(),
789-
String::from_utf8_lossy(&alias_name).to_string(),
773+
checked_name,
790774
spans[split_id],
791775
)),
792776
);
793777
}
794778

795-
if &alias_name == b"main" {
779+
if checked_name == "main" {
796780
return (
797781
alias_pipeline,
798782
Some(ParseError::ExportMainAliasNotAllowed(spans[split_id])),
@@ -804,13 +788,6 @@ pub fn parse_alias(
804788

805789
let replacement_spans = &spans[(split_id + 2)..];
806790

807-
// Temporarily hide the alias itself to prevent recursion
808-
let predecl_id = working_set
809-
.delta
810-
.last_scope_frame_mut()
811-
.predecls
812-
.remove(&alias_name);
813-
814791
let (expr, err) = parse_call(
815792
working_set,
816793
replacement_spans,
@@ -819,14 +796,6 @@ pub fn parse_alias(
819796
false, // TODO: Should this be set properly???
820797
);
821798

822-
if let Some(id) = predecl_id {
823-
working_set
824-
.delta
825-
.last_scope_frame_mut()
826-
.predecls
827-
.insert(alias_name.to_vec(), id);
828-
}
829-
830799
if let Some(e) = err {
831800
if let ParseError::MissingPositional(..) = e {
832801
// ignore missing required positional
@@ -875,28 +844,13 @@ pub fn parse_alias(
875844
}
876845
};
877846

878-
if let Some(decl_id) = working_set.find_predecl(&alias_name) {
879-
let alias_decl = working_set.get_decl_mut(decl_id);
880-
881-
let alias = Alias {
882-
name: String::from_utf8_lossy(&alias_name).to_string(),
883-
command,
884-
wrapped_call,
885-
};
886-
887-
*alias_decl = Box::new(alias);
888-
} else {
889-
return (
890-
garbage_pipeline(spans),
891-
Some(ParseError::InternalError(
892-
"Predeclaration failed to add declaration".into(),
893-
spans[split_id],
894-
)),
895-
);
896-
}
847+
let decl = Alias {
848+
name: checked_name,
849+
command,
850+
wrapped_call,
851+
};
897852

898-
// It's OK if it returns None: The decl was already merged in previous parse pass.
899-
working_set.merge_predecl(&alias_name);
853+
working_set.add_decl(Box::new(decl));
900854
}
901855

902856
let err = if spans.len() < 4 {

0 commit comments

Comments
 (0)