semgrep-rules icon indicating copy to clipboard operation
semgrep-rules copied to clipboard

python.lang.maintainability.useless-inner-function false positives

Open ievans opened this issue 4 years ago • 10 comments

https://semgrep.live/7KvR?registry=python.lang.maintainability.useless-innerfunction&sourceurl=https%3A%2F%2Fraw.githubusercontent.com%2Fdropbox%2Fdropbox-api-v2-repl%2Fa057a71995e12fb4cd2fff6fa4d917969e665fda%2Frepl.py

ievans avatar Jun 24 '20 21:06 ievans

See also https://github.com/returntocorp/semgrep-app/pull/229/checks?check_run_id=890538919

underyx avatar Jul 20 '20 15:07 underyx

Note that https://semgrep.live/YD8W/ would fix the rule.

nbrahms avatar Jul 20 '20 16:07 nbrahms

This also fires on e.g.

def foo():
    def bar(n):
        return range(n)
    for i in bar(3):
        print(i)

which is not covered by the above proposed fix. It also fires on conditionals, which can be handled by adding

  - pattern-not-inside: |
      def $F(...):
          ...
          def $FF(...):
             ...
          ...
          if <...$FF...>:
             ...

but (what I think is) the loop equivalent

  - pattern-not-inside: |
      def $F(...):
          ...
          def $FF(...):
             ...
          ...
          for ... in <...$FF...>:
             ...

doesn't appear to catch this case. Playing around at https://semgrep.live/kbq1/.

VeniVidiVici42 avatar Jul 26 '20 06:07 VeniVidiVici42

@aryx It seems to me that deep-expression matching should apply to conditional expressions and generator expressions, non?

nbrahms avatar Jul 27 '20 15:07 nbrahms

yes it should. Not sure what's going on. Maybe the generic AST for Python generators is wrong.

aryx avatar Jul 28 '20 08:07 aryx

Can someone write a single pattern showing the problem?

aryx avatar Jul 28 '20 08:07 aryx

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Mar 30 '22 03:03 stale[bot]

@aryx not a single pattern, but probably the shortest I can write... https://semgrep.dev/s/KLDP

p4p3r avatar Sep 01 '22 09:09 p4p3r

@brandonspark, want to have a look?

aryx avatar Sep 01 '22 09:09 aryx

Here's my report from Slack: OK, the problem simply seems to be the fact that the pattern:

def $F(...):
  ...
  def $FF(...):
    ...
  ...

permits a match to the $F being the outermost function, and $FF being the innermost. This happens even though the indentation of the rule seems to suggest that the def $FF ought to occur at the top-level of the body of $F.

This messes things up because later when we discard ranges due to the pattern-not-inside, the discard doesn't go through, because the metavariables used in both sub-patterns do not match. To be honest, I don't know why we require that the metavariables must match.

You can see this demonstrated by the following playground link, where I've simply changed the names of the metavariables in the not-inside and thus no finding is produced: https://semgrep.dev/s/PL6e

The way I see it, there are three ways forward: Either we do not actually want the $FF to be able to match something at a deeper nested level, in which case we should change that, or we can change the requirement that metavariables match when discarding ranges, or we can live with the fact that this is how it works, and just use this renaming fix to fix the rule.

Open to suggestions on where to proceed next.

brandonspark avatar Sep 06 '22 15:09 brandonspark