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 include/exclude check to codemods that did not have it #208

Merged
merged 5 commits into from
Jan 16, 2024

Conversation

clavedeluna
Copy link
Contributor

Overview

  • some non-semgrep codemods missed the include/exclude check*

Description

  • Right now any codemod that inherits directly from BaseCodemod is susceptible to being implemented without this check because the API doesn't enforce it.
  • It's hard right now to enforce adding this check because a codemod could implement any arbitrary number of leave_Node methods
  • I tried for a reasonable amount of time to add a pytest check to alert us if we wrote a codemod that did not pass thru filter_by_path_includes_or_excludes, but this is harder than it looks. I was hoping to add it to the existing BaseTest class so any new codemods would benefit from it. I have some basic code that doesn't work very well, so maybe I can iterate on it later on.

@clavedeluna clavedeluna marked this pull request as ready for review January 10, 2024 17:44
Copy link

codecov bot commented Jan 10, 2024

Codecov Report

Attention: 4 lines in your changes are missing coverage. Please review.

Comparison is base (a69a7ff) 96.25% compared to head (36a87fe) 96.26%.

❗ Current head 36a87fe differs from pull request most recent head 8727405. Consider uploading reports for the commit 8727405 to get more accurate results

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #208   +/-   ##
=======================================
  Coverage   96.25%   96.26%           
=======================================
  Files          89       89           
  Lines        4089     4097    +8     
=======================================
+ Hits         3936     3944    +8     
  Misses        153      153           
Files Coverage Δ
src/core_codemods/django_receiver_on_top.py 100.00% <ø> (ø)
src/core_codemods/exception_without_raise.py 100.00% <100.00%> (ø)
...c/core_codemods/fix_deprecated_abstractproperty.py 100.00% <100.00%> (ø)
src/core_codemods/fix_mutable_params.py 100.00% <ø> (ø)
src/core_codemods/remove_unnecessary_f_str.py 100.00% <100.00%> (ø)
src/core_codemods/use_generator.py 100.00% <100.00%> (ø)
src/core_codemods/use_walrus_if.py 100.00% <ø> (ø)
src/core_codemods/combine_startswith_endswith.py 96.29% <0.00%> (ø)
src/core_codemods/remove_debug_breakpoint.py 95.65% <50.00%> (ø)
src/core_codemods/remove_module_global.py 94.73% <0.00%> (ø)
... and 1 more

Comment on lines 26 to 32
def update_attribute(self, true_name, original_node, updated_node, new_args):
del true_name, original_node
del true_name
if not self.filter_by_path_includes_or_excludes(
self.node_position(original_node)
):
return original_node

Copy link
Contributor

Choose a reason for hiding this comment

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

The filtering call here is not needed as it is covered by the leave_Call in the parent class.

Comment on lines 40 to 46
def update_simple_name(self, true_name, original_node, updated_node, new_args):
del true_name
if not self.filter_by_path_includes_or_excludes(
self.node_position(original_node)
):
return original_node

Copy link
Contributor

Choose a reason for hiding this comment

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

Same as before.

Comment on lines 140 to 146
def leave_Assign(self, original_node: cst.Assign, updated_node: cst.Assign):
del updated_node
if not self.filter_by_path_includes_or_excludes(
self.node_position(original_node)
):
return original_node

Copy link
Contributor

Choose a reason for hiding this comment

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

As we discussed before, we only filter the nodes that "anchor" the changes. In this case the If node is the one being used for this purpose. Note that the change is reported with the If node position. Thus you don't need this check.

Comment on lines 160 to 164
if not self.filter_by_path_includes_or_excludes(
self.node_position(original_node)
):
return original_node

Copy link
Contributor

Choose a reason for hiding this comment

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

Same as the other comment.

@clavedeluna clavedeluna force-pushed the incl-exl branch 3 times, most recently from 876836a to c618a62 Compare January 11, 2024 14:14
self.node_position(original_node)
):
return original_node

Copy link
Contributor Author

Choose a reason for hiding this comment

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

in attempting to add a unit test here I discovered that this include/exclude check will not work because a function def node has a different start/end numbers. Here's an example:

For code

        from django.dispatch import receiver

        @csrf_exempt
        @receiver(request_finished)
        def foo():
            pass

If a user wanted to exclude a specific line here, say they pass in to exclude ln5 which is line def foo(): (not even the line for the decorator), when we hit leave_FunctionDef, we need to match pos.start.line == line and pos.end.line == line. However, the position for this leave_FunctionDef node is CodeRange(start=CodePosition(line=5, column=0), end=CodePosition(line=6, column=8)) (ends at ln6)

This is evidence that we need much more robust include/exclude behavior for these types of cases that are more subtle. I'm not quite prepared to implement this yet. @drdavella thoughts? Should I remove this include/exclude check for this (and any other case I find has this issue) for now?

Copy link
Member

Choose a reason for hiding this comment

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

@clavedeluna yes you can remove those checks for now but please make sure to add TODOs. None of our tooling is currently taking advantage of line-based filtering as far as I'm aware so the impact should be minimal for now.

if not self.filter_by_path_includes_or_excludes(
self.node_position(original_node)
):
return original_node
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry for not realizing this before, but we should return updated_node here just in case some node within the original_node subtree was changed. Otherwise we may revert those previous changes.

I don't think it will affect the current codemods that contains this snippet, but this will probably be copy/pasted a lot, so it should include the "safe" version.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I noticed we don't always return updated_node like the docs indicate we should. I kinda wanted this to read "if we are excluding this node bc of line, don't change". so returning original_node reads "no change happened" but it's true that's not always the case.

if not self.filter_by_path_includes_or_excludes(
self.node_position(_original_node)
):
return _original_node
Copy link
Contributor

Choose a reason for hiding this comment

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

Same

if not self.filter_by_path_includes_or_excludes(
self.node_position(original_node)
):
return original_node
Copy link
Contributor

Choose a reason for hiding this comment

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

Same

Copy link

Quality Gate Passed Quality Gate passed

The SonarCloud Quality Gate passed, but some issues were introduced.

3 New issues
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarCloud

@clavedeluna clavedeluna added this pull request to the merge queue Jan 16, 2024
Merged via the queue into main with commit 65878b1 Jan 16, 2024
12 checks passed
@clavedeluna clavedeluna deleted the incl-exl branch January 16, 2024 22:30
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.

3 participants