Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lint for debug_assert_with_mut_call #4680

Merged
merged 1 commit into from Oct 23, 2019

Conversation

hellow554
Copy link
Contributor

@hellow554 hellow554 commented Oct 16, 2019

closes #1526

What does not work:

  • detecting a mut call in the format string itself, e.g. debug_assert!(false, "{}", vec![1].pop())
  • detecting *mut T usage (pointer)

changelog: add new lint debug_assert_with_mut_call

clippy_lints/src/mutable_debug_assertion.rs Outdated Show resolved Hide resolved
clippy_lints/src/mutable_debug_assertion.rs Outdated Show resolved Hide resolved
clippy_lints/src/mutable_debug_assertion.rs Outdated Show resolved Hide resolved
clippy_lints/src/mutable_debug_assertion.rs Outdated Show resolved Hide resolved
src/lintlist/mod.rs Outdated Show resolved Hide resolved
@bors
Copy link
Collaborator

bors commented Oct 18, 2019

☔ The latest upstream changes (presumably #4657) made this pull request unmergeable. Please resolve the merge conflicts.

@hellow554
Copy link
Contributor Author

I think I'm done with this? @flip1995 do you want to see anything else? If not, I would rebase and force push the commits and pretty up the first comment in this thread. Are you okay with that?

@hellow554 hellow554 force-pushed the debug_assert_mut_call branch 2 times, most recently from 58f32c5 to 0dfeca0 Compare October 21, 2019 08:37
@hellow554
Copy link
Contributor Author

Rebased and ready to ship 🎉

@hellow554 hellow554 changed the title [WIP] Add first implementation for debug_assert macros with mutable parameters Add lint for debug_assert_with_mut_call Oct 21, 2019
@flip1995
Copy link
Member

I just got one more test idea:

let mut x = 42_usize;
debug_assert!({
    foo(&mut x);
    x > 10
});

@hellow554
Copy link
Contributor Author

hellow554 commented Oct 21, 2019

let mut x = 42_usize;
debug_assert!({
    foo(&mut x);
    x > 10
});

That's nasty! Who writes such code ^^
Ofc it isn't covered yet. Adding code for it :/

Btw: every block isn't covered yet, e.g. if, match, for, while. Do you think adding them is worth it? (I don't think so)

@hellow554
Copy link
Contributor Author

hellow554 commented Oct 21, 2019

error: do not call functions with mutable arguments inside of a `debug_assert!`
   --> tests/ui/debug_assert_with_mut_call.rs:104:19
    |
104 |       debug_assert!({
    |  ___________________^
105 | |         bool_mut(&mut x);
106 | |         x > 10
107 | |     });
    | |_____^

the span now doesn't point at the function call, but to the block itself. Meh :/

On the other hand:

error: do not call functions with mutable arguments inside of a `debug_assert!`
   --> tests/ui/debug_assert_with_mut_call.rs:105:9
    |
105 |         bool_mut(&mut x);
    |         ^^^^^^^^^^^^^^^^
    |

This doesn't look like if it's inside the debug_assert macro at all. What do you think about this @flip1995

@hellow554
Copy link
Contributor Author

I've gone full retard mode now and covered every ExprKind. I think this coveres everything, except closures and inline assembly (No... just, no) ^^

@flip1995
Copy link
Member

That's nasty! Who writes such code

This makes sense, when you want to write more complex verification code. Though the simplest example is asserting an enum variant:

debug_assert!(if let Variant(_) = expr {
    true
} else {
    false
});

I've gone full retard mode now and covered every ExprKind.

Uh, now you basically rewritten a Visitor. It may be better to just implement this, then you just have to do:

struct MutArgVisitor {
    mut_arg_found: bool,
}

impl intravisit::Visitor for MutArgVisitor {
    fn visit_expr(&mut self, expr: &'_ Expr) {
        match &expr.kind {
            ExprKind::Call(.., args) | ExprKind::MethodCall(.., args) => {
                // check args, 
                if /* any arg is mutable */ {
                     self.mut_arg_found = true;
                }
            }
        }

        walk_expr(expr);
    }
}

Just grep the Clippy Codebase for intravisit to find more examples on how to write and use Visitors.

@hellow554
Copy link
Contributor Author

@Manishearth can you help me again please? I try to solve the *mut pointer issue, but I can't get the type from adjustments table:

[clippy_lints/src/mutable_debug_assertion.rs:131] &expr.kind = Call(
    expr(HirId { owner: DefIndex(36), local_id: 1089 }: bool_ptr_mut),
    [
        expr(HirId { owner: DefIndex(36), local_id: 1091 }: v),
    ],
)
[clippy_lints/src/mutable_debug_assertion.rs:131] &expr.kind = Path(
    Resolved(
        None,
        path(bool_ptr_mut),
    ),
)
[clippy_lints/src/mutable_debug_assertion.rs:138] self.cx.tables.adjustments().get(expr.hir_id) = None
[clippy_lints/src/mutable_debug_assertion.rs:131] &expr.kind = Path(
    Resolved(
        None,
        path(v),
    ),
)
[clippy_lints/src/mutable_debug_assertion.rs:138] self.cx.tables.adjustments().get(expr.hir_id) = None

This is the debug output of bool_ptr_mut(v) where v is a *mut u32 with fn bool_ptr_mut(_: *mut u32) -> bool { false }.
As you can see the adjustements table doesn't have the type of v in it's Vec. What am I missing here?

@Manishearth
Copy link
Member

tbh I feel like it's fine if we don't detect that case. The lint is already quite advanced (and I'm hoping it's not too slow to apply)

Copy link
Member

@flip1995 flip1995 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage of the visitor should be more like the one of other visitors in the code base. Also as @Manishearth wrote, you can just leave out the mut pointer case.

clippy_lints/src/mutable_debug_assertion.rs Outdated Show resolved Hide resolved
clippy_lints/src/mutable_debug_assertion.rs Outdated Show resolved Hide resolved
clippy_lints/src/mutable_debug_assertion.rs Outdated Show resolved Hide resolved
@hellow554
Copy link
Contributor Author

If you give the okay fir this PR, I will rebase it again and then it can be merged (finally) 🎉

Copy link
Member

@flip1995 flip1995 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great now, thanks! Rebase and this is ready to go

This lint will complain when you put a mutable function/method call
inside a `debug_assert` macro, because it will not be executed in
release mode, therefore it will change the execution flow, which is not
wanted.
@hellow554
Copy link
Contributor Author

Done. Waiting for travis (which failed the last two times, is there something broken?)

@flip1995
Copy link
Member

Unrelated to this PR. Rustup in #4715

@phansch
Copy link
Member

phansch commented Oct 23, 2019

@bors r=flip1995

@bors
Copy link
Collaborator

bors commented Oct 23, 2019

📌 Commit 5572476 has been approved by flip1995

@bors
Copy link
Collaborator

bors commented Oct 23, 2019

⌛ Testing commit 5572476 with merge 850dfda...

bors added a commit that referenced this pull request Oct 23, 2019
Add lint for debug_assert_with_mut_call

closes #1526

**What does not work:**

* detecting a mut call in the format string itself, e.g. `debug_assert!(false, "{}", vec![1].pop())`
* detecting `*mut T` usage (pointer)

---

changelog: add new lint `debug_assert_with_mut_call`
@bors
Copy link
Collaborator

bors commented Oct 23, 2019

☀️ Test successful - checks-travis, status-appveyor
Approved by: flip1995
Pushing 850dfda to master...

@bors bors merged commit 5572476 into rust-lang:master Oct 23, 2019
@hellow554 hellow554 deleted the debug_assert_mut_call branch January 16, 2020 10:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Detecting mutation in debug_assert!
6 participants