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

Feature/more rules and tests #12

Merged
merged 17 commits into from Feb 1, 2020
4 changes: 2 additions & 2 deletions .circleci/config.yml
Expand Up @@ -4,9 +4,9 @@ jobs:
docker:
- image: returntocorp/sgrep
steps:
- run: apk add make
- checkout
- run: sgrep-lint --validate python .
- run: sgrep-lint --validate c .
- run: make test
workflows:
version: 2.1
build_and_test:
Expand Down
4 changes: 4 additions & 0 deletions Makefile
@@ -0,0 +1,4 @@
test:
sgrep-lint --validate --config=./python .
sgrep-lint --validate --config=./c .
./test.py --ignore-todo .
17 changes: 17 additions & 0 deletions python/compatibility/python37.py
@@ -0,0 +1,17 @@
import os

# ruleid:python37-compatability-os-module
os.pwrite('a')

if hasattr(os, 'pwrite'):
# OK
os.pwrite('a')


if hasattr(os, 'pwritev'):
# OK
os.pwritev('a')


# ruleid:python37-compatibility-os2-ok2
os.pwritev('b')
2 changes: 1 addition & 1 deletion python/compatibility/python37.yaml
Expand Up @@ -86,7 +86,7 @@ rules:
- id: python37-compatibility-os2-ok2
patterns:
- pattern-not-inside: |
if hasattr(os, 'pwritev):
if hasattr(os, 'pwritev'):
...
- pattern: os.pwritev(...)
message: "this function is only available on Python 3.7+"
Expand Down
19 changes: 19 additions & 0 deletions python/deadcode/baseclass-attribute-override.py
@@ -0,0 +1,19 @@

class A:
def method1(self, args):
pass


class A2:
def method2(self, args):
pass


class B:
def method1(self, args):
print('hello there')

# todoruleid: baseclass-attribute-override
class C(A, B):
def __init__():
print('initialized')
17 changes: 17 additions & 0 deletions python/deadcode/baseclass-attribute-override.yaml
@@ -0,0 +1,17 @@
rules:
- id: baseclass-attribute-override
patterns:
- pattern: |
class $A(...):
def $F(...):
...
...
class $B(...):
def $F(...):
...
...
class $C(..., $A, $B, ...):
...
message: "Class $C inherits from both `$A` and `$B` which both have a method named `$F`; one of these methods will be overwritten"
languages: [python]
severity: WARNING
3 changes: 3 additions & 0 deletions python/deadcode/missing-fstring.py
@@ -0,0 +1,3 @@
x = y
print('hi')
print('now {x} is {y}')
10 changes: 10 additions & 0 deletions python/deadcode/missing-fstring.yaml
@@ -0,0 +1,10 @@
rules:
- id: should-be-fstring
patterns:
- pattern: |
$X = $Y
...
print('...{$X}...')
message: "possibly missing an f-string specifier for string containing variable $X"
languages: [python]
severity: WARNING
19 changes: 19 additions & 0 deletions python/deadcode/return.py
@@ -0,0 +1,19 @@

# ruleid: return-not-in-function
return 5


def alwaysblue():
if isblue():
return 'blue'
# todoruleid: code-after-unconditional-return
return 'red'
return 'green'


def alwaysblue():
if isblue():
return 'blue'
# todoruleid: code-after-unconditional-return
return 'red'
x = 5
18 changes: 18 additions & 0 deletions python/deadcode/return.yaml
@@ -0,0 +1,18 @@
rules:
- id: code-after-unconditional-return
patterns:
- pattern: |
return $X
$S
message: "code after return statement will not be executed"
languages: [python]
severity: WARNING
- id: return-not-in-function
patterns:
- pattern-not-inside: |
def $F(...):
...
- pattern: return $X
message: "`return` only makes sense inside a function"
languages: [python]
severity: WARNING
23 changes: 23 additions & 0 deletions python/deadcode/useless-assign.py
@@ -0,0 +1,23 @@
d = {}
z = {}
a = {}
for i in xrange(100):
# ruleid: useless-assignment-keyed
d[i] = z[i]
d[i] = z[i]
d[i+1] = z[i]

for i in xrange(100):
# todoruleid: useless-assignment-keyed
da[i*1][j] = z[i]
da[i*1][j] = z[i]
da[i*4] = z[i]

# todoruleid: useless-assignment
x = 5
x = 5

x = y
x = y()

y() = y()
21 changes: 21 additions & 0 deletions python/deadcode/useless-assign.yaml
@@ -0,0 +1,21 @@
rules:
- id: useless-assignment-keyed
patterns:
- pattern-either:
- pattern: |
$X[$Y] = ...
$X[$Y] = ...
- pattern: |
$X[$Y][$Z] = ...
$X[$Y][$Z] = ...
message: "key `$Y` in `$X` is uselessly assigned the same value twice"
languages: [python]
severity: WARNING
- id: useless-assignment
patterns:
- pattern: |
$X = $Y
$X = $Y
message: "`$X` is uselessly assigned to the same value (`$Y`) twice"
languages: [python]
severity: WARNING
2 changes: 1 addition & 1 deletion python/deadcode/useless-eqeq.yaml
Expand Up @@ -11,6 +11,6 @@ rules:
- pattern: $X == $X
- pattern: $X != $X
- pattern-not: 1 == 1
message: "useless comparison operation `$X == $X` or `$X != $X`; possible bug?"
message: "useless comparison operation `$X == $X` or `$X != $X`; if testing for floating point NaN, use `math.isnan`, or `cmath.isnan` if the number is complex."
languages: [python]
severity: ERROR
39 changes: 39 additions & 0 deletions python/deadcode/useless-ifelse.py
@@ -0,0 +1,39 @@
a, b, c = 1

# ruleid: useless-if-conditional
if a:
print('1')
elif a:
print('2')

# ruleid: useless-if-body
if a:
print('1')
else:
print('1')

# ruleid: useless-if-body
if a:
print('1')
elif b:
print('1')


# todoruleid: useless-if-body
if a:
print('this is a')
elif b:
print('this is b')
elif c:
print('this is c')
elif d:
print('this is d')


if a:
print('this is a')
# ruleid: useless-if-body
elif b:
print('this is b')
elif c:
print('this is b')
35 changes: 35 additions & 0 deletions python/deadcode/useless-ifelse.yaml
@@ -0,0 +1,35 @@
rules:
- id: useless-if-conditional
patterns:
- pattern-either:
- pattern: |
if $X:
...
elif $X:
...
message: "if block checks for the same condition on both branches (`$X`)"
languages: [python]
severity: WARNING
- id: useless-if-body
patterns:
- pattern-either:
- pattern: |
if $X:
$S
elif $Y:
$S
- pattern: |
if $X:
$S
else:
$S
- pattern: |
if $X:
$S
elif $Z:
...
elif $Y:
$S
message: "useless if statment; both blocks have the same body"
languages: [python]
severity: WARNING
21 changes: 21 additions & 0 deletions python/deadcode/useless-innerfunction.py
@@ -0,0 +1,21 @@
# todoruleid:useless-inner-function
def A():
print_error('test')

def B():
print_error('again')

def C():
print_error('another')
return None

# todoruleid:useless-inner-function
def A():
print_error('test')

def B():
print_error('again')

def C():
print_error('another')
return B(), C()
19 changes: 19 additions & 0 deletions python/deadcode/useless-innerfunction.yaml
@@ -0,0 +1,19 @@
rules:
- id: useless-inner-function
patterns:
- pattern-not-inside: |
def $F(...):
...
def $F2(...):
...
...
$F2
- pattern: |
def $F(...):
...
def $F2(...):
...
...
message: "function `$F2` is defined inside a function but never used"
languages: [python]
severity: ERROR
12 changes: 12 additions & 0 deletions python/deadcode/useless-literal.py
@@ -0,0 +1,12 @@
# todoruleid: useless-literal-dict
d = dict(1: 'a', 2: 'b', 1: 'a')
# todoruleid: useless-literal-set
d = set(1: 'a', 2: 'b', 1: 'a')

# todoruleid: useless-literal-dict
d = {1: 'a', 2: 'b', 1: 'a'}
# todoruleid: useless-literal-dict
d = {'a': 1, 'a': 1}

# OK
d = {1: 'a', 2: 'b', 3: 'a'}
18 changes: 18 additions & 0 deletions python/deadcode/useless-literal.yaml
@@ -0,0 +1,18 @@
rules:
- id: useless-literal-dict
patterns:
- pattern-either:
# - pattern: |
# dict(..., $X: $A, ..., $X: $B, ...)
- pattern: |
{..., $X: $A, ..., $X: $B, ...}
message: "key `$X` is uselessly assigned twice"
languages: [python]
severity: WARNING
- id: useless-literal-set
patterns:
# - pattern: |
# set(..., $X: $A, ..., $X: $B, ...)
message: "`$X` is uselessly assigned twice inside the creation of the set"
languages: [python]
severity: ERROR
24 changes: 24 additions & 0 deletions python/exceptions/exceptions.py
@@ -0,0 +1,24 @@
# ruleid:raise-not-base-exception
raise "error here"

# todoruleid:raise-not-base-exception
raise 5


class Foobar:
x = 5


# todoruleid:raise-not-base-exception
raise Foobar()


class Foobar2(BaseException):
x = 5


# OK
raise Foobar2()

# OK
raise Exception()
16 changes: 16 additions & 0 deletions python/exceptions/exceptions.yaml
@@ -0,0 +1,16 @@
rules:
- id: raise-not-base-exception
patterns:
- pattern-either:
- pattern: raise "..."
#- pattern: |
# raise $X: int
#- pattern: |
# raise $X: float
# TODO, the second pattern requires sgrep typing support
- pattern: |
$X: BaseException
raise $X(...)
message: "In Python3, a runtime `TypeError` will be thrown if you attempt to raise an object or class which does not inherit from `BaseException`"
languages: [python]
severity: ERROR
13 changes: 13 additions & 0 deletions python/smells/missing-hash-with-eq.py
@@ -0,0 +1,13 @@

# todoruleid:missing-hash-with-eq
class A:
def __eq__(self, someother):
pass


class A2:
def __eq__(self, someother):
pass

def __hash__(self):
pass