Skip to content

Commit ac149f8

Browse files
Seppli11sonartech
authored andcommitted
SONARPY-3592 Fix S930 related to TypeVar and type instances (#736)
GitOrigin-RevId: d86556f9005b4eb687c46a74bc1b75fe2ad0209c
1 parent 1654912 commit ac149f8

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

python-checks/src/main/java/org/sonar/python/checks/ArgumentNumberCheck.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ private static boolean isException(SubscriptionContext ctx, CallExpression callE
136136
|| callExpression.arguments().stream().anyMatch(argument -> argument.is(Tree.Kind.UNPACKING_EXPR))
137137
|| extendsZopeInterface(ctx, callExpression)
138138
|| isCalledAsBoundInstanceMethod(callExpression)
139-
|| isSuperCall(ctx, callExpression);
139+
|| isSuperCall(ctx, callExpression)
140+
|| isReceiverTypeVar(ctx, callExpression)
141+
|| isReceiverTypeInstance(ctx, callExpression);
140142
}
141143

142144
private static boolean extendsZopeInterface(SubscriptionContext ctx, CallExpression callExpression) {
@@ -153,6 +155,23 @@ private static boolean isCalledAsBoundInstanceMethod(CallExpression callExpressi
153155
return false;
154156
}
155157

158+
private static boolean isReceiverTypeVar(SubscriptionContext ctx, CallExpression callExpression) {
159+
if (callExpression.callee() instanceof QualifiedExpression qualifiedExpression) {
160+
return TypeMatchers.isObjectSatisfying(TypeMatchers.isOrExtendsType("typing.TypeVar"))
161+
.isTrueFor(qualifiedExpression.qualifier(), ctx);
162+
}
163+
return false;
164+
}
165+
166+
private static boolean isReceiverTypeInstance(SubscriptionContext ctx, CallExpression callExpression) {
167+
// see SONARPY-3591
168+
if (callExpression.callee() instanceof QualifiedExpression qualifiedExpression) {
169+
return TypeMatchers.isObjectSatisfying(TypeMatchers.isOrExtendsType("type"))
170+
.isTrueFor(qualifiedExpression.qualifier(), ctx);
171+
}
172+
return false;
173+
}
174+
156175
private static boolean isSuperCall(SubscriptionContext ctx, CallExpression callExpression) {
157176
if (callExpression.callee() instanceof QualifiedExpression qualifiedExpression) {
158177
return TypeMatchers.isObjectOfType("super").isTrueFor(qualifiedExpression.qualifier(), ctx);

python-checks/src/test/resources/checks/argumentNumber.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,37 @@ def something(self, importing=None):
193193
importing = set()
194194
importing.discard(1)
195195
importing.discard(1, 2) # FN
196+
197+
def methods_on_types():
198+
class Test: pass
199+
200+
sys_type = type(Test)
201+
sys_type.__setattr__(sys, key, "42") # Ok
202+
sys_type.__setattr__(key, "42") # FN see SONARPY-3591
203+
204+
type.mro() # Noncompliant
205+
type.mro(type) # Ok
206+
207+
sys_type.mro() # FN see SONARPY-3591
208+
sys_type.mro(Test) # Ok
209+
210+
test_instance = Test()
211+
test_instance_type = type(test_instance)
212+
test_instance_type.mro() # Ok
213+
test_instance_type.mro(test_instance) # see SONARPY-3591
214+
215+
216+
import typing
217+
_T = typing.TypeVar('_T')
218+
219+
class GenericTest(typing.Generic[_T]):
220+
cls: _T
221+
def __new__(cls):
222+
pass
223+
224+
def test(self):
225+
GenericTest.cls.__new__(self.cls) # Ok
226+
GenericTest.cls.__new__(self.cls, 1) # FN
196227

197228

198229
def builtin_method():

0 commit comments

Comments
 (0)