mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 13:59:08 +00:00
Two non-functional problem reports
This commit is contained in:
parent
a00ed8a1ca
commit
221581432a
4 changed files with 142 additions and 7 deletions
|
@ -431,20 +431,19 @@ pub fn canonicalize_expr<'a>(
|
|||
loc_body_expr.region,
|
||||
&loc_body_expr.value,
|
||||
);
|
||||
|
||||
// Now that we've collected all the references, check to see if any of the args we defined
|
||||
// went unreferenced. If any did, report them as unused arguments.
|
||||
for (symbol, region) in scope.symbols() {
|
||||
if !original_scope.contains_symbol(*symbol) {
|
||||
if !output.references.has_lookup(*symbol) {
|
||||
for (sub_symbol, region) in scope.symbols() {
|
||||
if !original_scope.contains_symbol(*sub_symbol) {
|
||||
if !output.references.has_lookup(*sub_symbol) {
|
||||
// The body never referenced this argument we declared. It's an unused argument!
|
||||
env.problem(Problem::UnusedArgument(*symbol, *region));
|
||||
env.problem(Problem::UnusedArgument(symbol, *sub_symbol, *region));
|
||||
}
|
||||
|
||||
// We shouldn't ultimately count arguments as referenced locals. Otherwise,
|
||||
// we end up with weird conclusions like the expression (\x -> x + 1)
|
||||
// references the (nonexistant) local variable x!
|
||||
output.references.lookups.remove(symbol);
|
||||
output.references.lookups.remove(sub_symbol);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@ use roc_region::all::{Located, Region};
|
|||
pub enum Problem {
|
||||
UnusedDef(Symbol, Region),
|
||||
UnusedImport(ModuleId, Region),
|
||||
UnusedArgument(Symbol, Region),
|
||||
/// First symbol is the name of the closure with that argument
|
||||
/// Second symbol is the name of the argument that is unused
|
||||
UnusedArgument(Symbol, Symbol, Region),
|
||||
PrecedenceProblem(PrecedenceProblem),
|
||||
// Example: (5 = 1 + 2) is an unsupported pattern in an assignment; Int patterns aren't allowed in assignments!
|
||||
UnsupportedPattern(PatternType, Region),
|
||||
|
|
|
@ -84,6 +84,41 @@ pub fn can_problem(filename: PathBuf, problem: Problem) -> Report {
|
|||
" then remove it so future readers of your code don't wonder why it is there.",
|
||||
));
|
||||
}
|
||||
Problem::UnusedImport(module_id, region) => {
|
||||
texts.push(plain_text("Nothing from "));
|
||||
texts.push(Module(module_id));
|
||||
texts.push(plain_text(" is used in this module."));
|
||||
texts.push(newline());
|
||||
texts.push(newline());
|
||||
texts.push(Region(region));
|
||||
texts.push(newline());
|
||||
texts.push(newline());
|
||||
texts.push(plain_text("Since "));
|
||||
texts.push(Module(module_id));
|
||||
texts.push(plain_text(" isn't used, you don't need to import it."));
|
||||
}
|
||||
Problem::UnusedArgument(closure_symbol, argument_symbol, region) => {
|
||||
texts.push(Value(closure_symbol));
|
||||
texts.push(plain_text(" doesn't use "));
|
||||
texts.push(Value(argument_symbol));
|
||||
texts.push(plain_text("."));
|
||||
texts.push(newline());
|
||||
texts.push(newline());
|
||||
texts.push(Region(region));
|
||||
texts.push(newline());
|
||||
texts.push(newline());
|
||||
texts.push(plain_text("If you don't need "));
|
||||
texts.push(Value(argument_symbol));
|
||||
texts.push(plain_text(
|
||||
", then you can just remove it. However, if you really do need ",
|
||||
));
|
||||
texts.push(Value(argument_symbol));
|
||||
texts.push(plain_text(" as an argument of "));
|
||||
texts.push(Value(closure_symbol));
|
||||
texts.push(plain_text(", prefix it with an underscore, like this: \"_"));
|
||||
texts.push(Value(argument_symbol));
|
||||
texts.push(plain_text("\". Adding an underscore at the start of a variable name is a way of saying that the variable is not used."));
|
||||
}
|
||||
_ => {
|
||||
panic!("TODO implement others");
|
||||
}
|
||||
|
|
|
@ -287,6 +287,105 @@ mod test_report {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn report_unused_argument() {
|
||||
let src: &str = indoc!(
|
||||
r#"
|
||||
y = 9
|
||||
|
||||
box = \class, htmlChildren ->
|
||||
div [ class ] []
|
||||
|
||||
div = 4
|
||||
|
||||
box "wizard" []
|
||||
"#
|
||||
);
|
||||
|
||||
let (_type_problems, can_problems, mut subs, home, interns) = infer_expr_help(src);
|
||||
|
||||
let mut buf: String = String::new();
|
||||
let src_lines: Vec<&str> = src.split('\n').collect();
|
||||
|
||||
match can_problems.first() {
|
||||
None => {}
|
||||
Some(problem) => {
|
||||
let report = can_problem(
|
||||
filename_from_string(r"\code\proj\Main.roc"),
|
||||
problem.clone(),
|
||||
);
|
||||
report
|
||||
.text
|
||||
.render_ci(&mut buf, &mut subs, home, &src_lines, &interns)
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
buf,
|
||||
indoc!(
|
||||
r#"
|
||||
box doesn't use htmlChildren.
|
||||
|
||||
3 ┆ box = \class, htmlChildren ->
|
||||
|
||||
If you don't need htmlChildren, then you can just remove it. However, if you really do need htmlChildren as an argument of box, prefix it with an underscore, like this: "_htmlChildren". Adding an underscore at the start of a variable name is a way of saying that the variable is not used."#
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn report_unused_import() {
|
||||
let src: &str = indoc!(
|
||||
r#"
|
||||
interface Report
|
||||
exposes [
|
||||
plainText,
|
||||
emText
|
||||
]
|
||||
imports [
|
||||
Symbol.{ Interns }
|
||||
]
|
||||
|
||||
plainText = \str -> PlainText str
|
||||
|
||||
emText = \str -> EmText str
|
||||
"#
|
||||
);
|
||||
|
||||
let (_type_problems, can_problems, mut subs, home, interns) = infer_expr_help(src);
|
||||
|
||||
let mut buf: String = String::new();
|
||||
let src_lines: Vec<&str> = src.split('\n').collect();
|
||||
|
||||
match can_problems.first() {
|
||||
None => {}
|
||||
Some(problem) => {
|
||||
let report = can_problem(
|
||||
filename_from_string(r"\code\proj\Main.roc"),
|
||||
problem.clone(),
|
||||
);
|
||||
report
|
||||
.text
|
||||
.render_ci(&mut buf, &mut subs, home, &src_lines, &interns)
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
buf,
|
||||
indoc!(
|
||||
r#"
|
||||
Nothing from Symbol is used in this module.
|
||||
|
||||
6 ┆ imports [
|
||||
7 ┆ Symbol.{ Interns }
|
||||
^^^^^^
|
||||
8 ┆ ]
|
||||
|
||||
Since Symbol isn't used, you don't need to import it."#
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn report_plain_text_color() {
|
||||
report_renders_in_color(to_simple_report(plain_text("y")), "<white>y<reset>");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue