astral-sh / ruff

An extremely fast Python linter and code formatter, written in Rust.
https://docs.astral.sh/ruff
MIT License
31.16k stars 1.04k forks source link

Add support for `vulture`-like dead code detection #872

Open charliermarsh opened 1 year ago

charliermarsh commented 1 year ago

As a maintainer of a large Python codebase, I found vulture to be really useful, especially for detecting unused functions and unused modules.

This would require us to introduce some new patterns and capabilities that don't yet exist in Ruff, but should! For example, we need to be able to run some analysis over every file (list the used members), then reconcile that analysis post-hoc. We also need to be able to map from references to local modules.

olliemath commented 1 year ago

By the way there is a subset of vulture (and pylint) that would be useful even without mapping out the entire codebase, namely this sort of dead-code detection:

def oops():
    return 1
    return 2  # <- guaranteed never to run
charliermarsh commented 1 year ago

Yeah I'm interested in doing this. @MichaReiser shared some links with me around building these kinds of control-flow graphs. I may write it up as a more detailed issue.

saippuakauppias commented 1 year ago

+1 we really miss this kind of linter in ruff

The most interesting thing is to find those functions and classes that are forgotten and do not run

eronning commented 1 year ago

Also +1 on linting these issues in ruff.

akx commented 1 year ago

+1 – would be nice.

Being 100% certain about deadness of names (even locals) can be tricky – e.g. PyCharm generally highlights (well, lowlights) unused locals, unless it notices vars(), locals(), etc. being used in the same scope, in which case it just throws its paws up and doesn't do that highlighting anymore.

For globals, it gets even harder because a tricky user could be getattring (or vars().geting) from any given module.

FilipeBento commented 11 months ago

This would be extremely useful. I understand full implementation requires a lot of work, but checking if methods or variables are unused is very helpful.

choweth commented 9 months ago

This vulture-like tool is great: https://github.com/asottile/dead

ofek commented 7 months ago

Since this was opened a while ago, have there been any changes internally that would make such an implementation easier?

dhruvmanila commented 7 months ago

Since this was opened a while ago, have there been any changes internally that would make such an implementation easier?

Not yet. Adding multi-file analysis is a feature that's on our roadmap which will allow us to support this.

alexbondar92 commented 1 month ago

also +1 for this feature

NeilGirdhar commented 2 days ago

If this is implemented, one kind of dead code that is not caught by vulture is when a derived class has a useless override:

class Problem:
    def reward_threshold(self) -> float:
        """The average return threshold at which the problem is considered solved."""
        raise NotImplementedError

class BasicProblem(Problem):  # This class was inserted as part of a refactor.
    @override
    def reward_threshold(self) -> float:
        return 100.0

@dataclass
class GeometryProblem(BasicProblem):
    @override
    def reward_threshold(self) -> float:  # Useless override — this was forgotten during the refactor.
        return 100.0