Skip to content

Commit

Permalink
Merge branch 'master' into check-CFG-edge-constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
david-yz-liu committed Sep 27, 2024
2 parents ee18274 + 2e3061a commit fd5d0ab
Show file tree
Hide file tree
Showing 68 changed files with 296 additions and 247 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- Renamed `reduce` method of `Z3Parser` to `parse`
- Renamed `test_expr_wrapper` to `test_z3_parser`
- Added `is_feasible` attribute for `CFGEdge` and implemented update to edge feasibility based on lists of Z3 constraints
- Refactored codebase to use modern type annotations. Replaced `List` with `list`, `Dict` with `dict`, `Set` with `set`, and `Tuple` with `tuple`
- Checked for variable reassignment in `AugAssign` and `AnnAssign` node in parsing edge Z3 constraints
- Rendered logically infeasible control flow graph edges in light grey

Expand Down
31 changes: 16 additions & 15 deletions docs/checkers/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ example below is considered to have _six_ nested blocks, not seven.
The code above can be fixed using a helper function:

```python
def drop_none(lst: List[Optional[int]]) -> List[int]:
def drop_none(lst: list[Optional[int]]) -> list[int]:
"""Return a copy of `lst` with all `None` elements removed."""
new_lst = []
for element in lst:
Expand All @@ -692,8 +692,8 @@ def drop_none(lst: List[Optional[int]]) -> List[int]:
return new_lst


def cross_join(x_list: List[Optional[int]], y_list: List[Optional[int]],
z_list: List[Optional[int]]) -> List[Tuple[int, int, int]]:
def cross_join(x_list: list[Optional[int]], y_list: list[Optional[int]],
z_list: list[Optional[int]]) -> list[tuple[int, int, int]]:
"""Perform an all-by-all join of all elements in the input lists."""
cross_join_list = []
for x in drop_none(x_list):
Expand All @@ -706,8 +706,8 @@ def cross_join(x_list: List[Optional[int]], y_list: List[Optional[int]],
or using list comprehension:

```python
def cross_join(x_list: List[Optional[int]], y_list: List[Optional[int]],
z_list: List[Optional[int]]) -> List[Tuple[int, int, int]]:
def cross_join(x_list: list[Optional[int]], y_list: list[Optional[int]],
z_list: list[Optional[int]]) -> list[tuple[int, int, int]]:
"""Perform an all-by-all join of all elements in the input lists."""
cross_join_list = [
(x, y, z)
Expand Down Expand Up @@ -2349,7 +2349,7 @@ lines: 5-11
We can simplify the above code by changing the loop to go over the elements of the list directly:

```python
def sum_items(lst: List[int]) -> int:
def sum_items(lst: list[int]) -> int:
"""Return the sum of a list of numbers."""
s = 0
for x in lst:
Expand Down Expand Up @@ -2381,7 +2381,7 @@ One common example is if we want to iterate over two lists in parallel:
For loop:

```python
def print_sum(lst1: List[int], lst2: List[int]) -> None:
def print_sum(lst1: list[int], lst2: list[int]) -> None:
"""Print the sums of each corresponding pair of items in lst1 and lst2.
Precondition: lst1 and lst2 have the same length.
"""
Expand All @@ -2392,7 +2392,7 @@ def print_sum(lst1: List[int], lst2: List[int]) -> None:
Comprehension:

```python
def parallel_lst(lst1: List[int], lst2: List[int]) -> list:
def parallel_lst(lst1: list[int], lst2: list[int]) -> list:
"""Return a list of the concatenation of the values of lst1 and lst2 at index i.
Precondition: lst1 and lst2 have the same length."""
return [lst1[i] + lst2[i] for i in range(len(lst1))]
Expand Down Expand Up @@ -2427,7 +2427,7 @@ For example:
For loop:

```python
def example1(lst: List[int]) -> int:
def example1(lst: list[int]) -> int:
s = 0
for number in lst: # Fixed
s += number
Expand All @@ -2437,7 +2437,7 @@ def example1(lst: List[int]) -> int:
Comprehension:

```python
def example7(lst: List[int]) -> List[int]:
def example7(lst: list[int]) -> list[int]:
return [number for number in lst] # Fixed
```

Expand Down Expand Up @@ -2531,7 +2531,7 @@ Example:
To fix these errors, one may make the following changes.

```python
from typing import List
from __future__ import annotations
import datetime


Expand All @@ -2541,7 +2541,7 @@ class Person:

def add_two_numbers(
x: int,
y: List[float],
y: list[float],
z: type = complex
) -> int:
return (x + y) * z
Expand Down Expand Up @@ -2939,9 +2939,10 @@ then check for `None` inside the function body. For example, the following code
output:

```python
from typing import List, Optional
from __future__ import annotations
from typing import Optional

def make_list(n: int, lst: Optional[List[int]]=None) -> List[int]:
def make_list(n: int, lst: Optional[list[int]]=None) -> list[int]:
if lst is None:
lst = []
for i in range(n):
Expand Down Expand Up @@ -3122,7 +3123,7 @@ Corrected version:
class Company:
"""A company with some employees."""

def __init__(self, employees: List[str]) -> None:
def __init__(self, employees: list[str]) -> None:
self._employees = employees

def __len__(self) -> int:
Expand Down
20 changes: 10 additions & 10 deletions examples/custom_checkers/e9984_invalid_for_target.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
"""Examples for E9984: invalid-for-target."""
from typing import List, Tuple
from __future__ import annotations


def example1(lst: List[int]) -> int:
def example1(lst: list[int]) -> int:
"""For loop target is an element of a list."""
s = 0
for lst[0] in lst: # Error on this line. lst[0] is highlighted.
s += lst[0]
return s


def example2(lst: List[int]) -> List[int]:
def example2(lst: list[int]) -> list[int]:
"""For loop target is a slice of a list."""
s = []
for lst[0:1] in lst: # Error on this line. lst[0:1] is highlighted.
s += lst[0:1]
return s


def example3(lst: List[int]) -> int:
def example3(lst: list[int]) -> int:
"""For loop target is an object's attribute"""
x = type("EmptyClass", (), {})
s = 0
Expand All @@ -27,41 +27,41 @@ def example3(lst: List[int]) -> int:
return s


def example4(lst: List[Tuple[int, int]]) -> int:
def example4(lst: list[tuple[int, int]]) -> int:
"""There are more than one for loop targets."""
s = 0
for lst[0], i in lst: # Error on this line. lst[0] is highlighted.
s += lst[0] * i
return s


def example5(lst: List[Tuple[int, int]]) -> int:
def example5(lst: list[tuple[int, int]]) -> int:
"""Multiple for loop targets are in a list"""
s = 0
for [lst[0], i] in lst: # Error on this line. lst[0] is highlighted.
s += lst[0] * i
return s


def example6(lst: List[Tuple[int, Tuple[int, int]]]) -> int:
def example6(lst: list[tuple[int, tuple[int, int]]]) -> int:
"""For loop targets nested in lists or tuples"""
s = 0
for i, [j, lst[0]] in lst: # Error on this line. lst[0] is highlighted.
s += i * j * lst[0]
return s


def example7(lst: List[int]) -> List[int]:
def example7(lst: list[int]) -> list[int]:
"""Comprehension target is an element of a list."""
return [lst[0] for lst[0] in lst] # Error on this line. lst[0] is highlighted.


def example8(lst: List[int]) -> List[int]:
def example8(lst: list[int]) -> list[int]:
"""Comprehension target is a slice of a list."""
return [lst[0] for lst[0:1] in lst] # Error on this line. lst[0:1] is highlighted.


def example9(lst: List[int]) -> list:
def example9(lst: list[int]) -> list:
"""Comprehension target is an object's attribute"""
x = type("EmptyClass", (), {})
return [x.attr for x.attr in lst] # Error on this line. x.attr is highlighted
6 changes: 3 additions & 3 deletions examples/custom_checkers/e9988_shadowing_in_comprehension.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"""Example for E9988: shadowing-in-comprehension."""
from typing import List
from __future__ import annotations


# There are four different types of comprehensions:
# list comprehension, dict comprehension, set comprehension, and generator comprehension
# below are examples with each type of comprehensions in respective order


def num_lst(n: int) -> List[int]:
def num_lst(n: int) -> list[int]:
"""Return a list of integers from 0 to <n>, in that order."""
return [n for n in range(n)]

Expand All @@ -28,7 +28,7 @@ def common_items(lst1: list, lst2: list) -> int:
return s


def print_pos(lst: List[int]) -> None:
def print_pos(lst: list[int]) -> None:
"""Print items in lst one by one if they are greater than 0."""
for k in (k for k in lst if k > 0):
print(k)
14 changes: 7 additions & 7 deletions examples/custom_checkers/e9994_unnecessary_indexing.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""Example for E9994: unnecessary-indexing."""
from typing import List
from __future__ import annotations


def sum_items(lst: List[int]) -> int:
def sum_items(lst: list[int]) -> int:
"""Return the sum of a list of numbers."""
s = 0
for i in range(len(lst)): # Error on this line (i is highlighted).
Expand All @@ -11,7 +11,7 @@ def sum_items(lst: List[int]) -> int:
return s


def sum_items2(lst: List[int]) -> int:
def sum_items2(lst: list[int]) -> int:
"""Return the sum of a list of numbers."""
s = 0
for i in range(0, len(lst)): # Error on this line (i is highlighted).
Expand All @@ -20,7 +20,7 @@ def sum_items2(lst: List[int]) -> int:
return s


def sum_items3(lst: List[int]) -> int:
def sum_items3(lst: list[int]) -> int:
"""Return the sum of a list of numbers."""
s = 0
for i in range(0, len(lst), 1): # Error on this line (i is highlighted).
Expand All @@ -29,7 +29,7 @@ def sum_items3(lst: List[int]) -> int:
return s


def sum_pairs(lst1: List[int], lst2: List[int]) -> int:
def sum_pairs(lst1: list[int], lst2: list[int]) -> int:
"""Return the sum of corresponding products of two list of numbers."""
s = 0
# NO error reported; the loop index is used to index lst2 as well.
Expand All @@ -39,7 +39,7 @@ def sum_pairs(lst1: List[int], lst2: List[int]) -> int:
return s


def nested_sum(items: List[List[int]]) -> int:
def nested_sum(items: list[list[int]]) -> int:
"""Return a repeated sum of the items in the list."""
s = 0
for i in range(len(items)): # Error on this line (i is highlighted).
Expand Down Expand Up @@ -81,7 +81,7 @@ def nested_comprehensions4(items: list) -> None:
print([[items[j] for _ in range(10)] for j in [1, 2, 3]])


def loop_variable_reassigned(items: List[int]) -> int:
def loop_variable_reassigned(items: list[int]) -> int:
"""Illustrate this checker on a loop where the loop variable is reassigned
in the loop body."""
s = 0
Expand Down
4 changes: 2 additions & 2 deletions examples/custom_checkers/e9995_type_is_assigned.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List
from __future__ import annotations
import datetime


Expand All @@ -8,7 +8,7 @@ class Person:

def add_two_numbers(
x=int, # Error on this line
y=List[float], # Error on this line
y=list[float], # Error on this line
z: type = complex # No error on this line
) -> int:
return (x + y) * z
Expand Down
5 changes: 3 additions & 2 deletions examples/custom_checkers/r9711_missing_return_statement.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from typing import List, Optional
from __future__ import annotations
from typing import Optional


def index_of(numbers: List[int], n: int) -> Optional[int]:
def index_of(numbers: list[int], n: int) -> Optional[int]:
"""Return the index of the first occurrence of n in numbers,
or None if n doesn't appear in the list.
"""
Expand Down
7 changes: 3 additions & 4 deletions examples/ending_locations/subscript.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

y[0]
z [ 0 ]
a[:]
Expand All @@ -16,8 +18,5 @@
x = m[ : ]


from typing import List


def add(numbers: List[int]) -> List[int]:
def add(numbers: list[int]) -> list[int]:
return numbers + [1]
4 changes: 2 additions & 2 deletions examples/pylint/e0103_not_in_loop.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import List
from __future__ import annotations

def add(lst: List[int]) -> int:
def add(lst: list[int]) -> int:
"""Calculate the sum of the elements in the given list."""
temp = 0
for item in lst:
Expand Down
4 changes: 2 additions & 2 deletions examples/pylint/e0104_return_outside_function.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import List
from __future__ import annotations

def add(lst: List[int]) -> None:
def add(lst: list[int]) -> None:
"""Calculate the sum of the elements in the given list."""
temp = 0
for item in lst:
Expand Down
4 changes: 2 additions & 2 deletions examples/pylint/e0108_duplicate_argument_name.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import List
from __future__ import annotations

def add(lst: List[int], lst: List[int]) -> int: # Error on this line
def add(lst: list[int], lst: list[int]) -> int: # Error on this line
"""Calculate the sum of the elements in the given list."""
temp = 0
for item in lst:
Expand Down
4 changes: 2 additions & 2 deletions examples/pylint/e0303_invalid_length_returned.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from typing import List
from __future__ import annotations

class Company:
"""A company with some employees."""

def __init__(self, employees: List[str]) -> None:
def __init__(self, employees: list[str]) -> None:
self._employees = employees

def __len__(self) -> int:
Expand Down
4 changes: 2 additions & 2 deletions examples/pylint/e0304_invalid_bool_returned.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from typing import List
from __future__ import annotations

class Company:
"""A company with some employees."""

def __init__(self, employees: List[str]) -> None:
def __init__(self, employees: list[str]) -> None:
self._employees = employees

def __bool__(self) -> bool:
Expand Down
4 changes: 2 additions & 2 deletions examples/pylint/e0306_invalid_repr_returned.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from typing import List
from __future__ import annotations

class Company:
"""A company with some employees."""

def __init__(self, employees: List[str]) -> None:
def __init__(self, employees: list[str]) -> None:
self._employees = employees

def __repr__(self) -> str:
Expand Down
4 changes: 2 additions & 2 deletions examples/pylint/e0307_invalid_str_returned.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from typing import List
from __future__ import annotations

class Company:
"""A company with some employees."""

def __init__(self, employees: List[str]) -> None:
def __init__(self, employees: list[str]) -> None:
self._employees = employees

def __str__(self) -> str:
Expand Down
Loading

0 comments on commit fd5d0ab

Please sign in to comment.