Skip to content

Commit

Permalink
SONARPY-2254 resolved nested static fields
Browse files Browse the repository at this point in the history
  • Loading branch information
Seppli11 committed Oct 25, 2024
1 parent f1b1a64 commit 3e383e9
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ class MyClass:

def foo():
mc = MyClass()
mc.x()
mc.x() #Noncompliant

def using_isinstance_with_runtime_type():
my_non_callable = MyNonCallable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ private ClassType buildClassType(ClassDef classDef) {
resolveTypeHierarchy(classDef, classTypeBuilder);
ClassType classType = classTypeBuilder.build();

if(currentType() instanceof ClassType ownerClass) {
if (currentType() instanceof ClassType ownerClass) {
PythonType memberType = className.symbolV2().hasSingleBindingUsage() ? classType : PythonType.UNKNOWN;
ownerClass.members().add(new Member(classType.name(), memberType));
}
Expand Down Expand Up @@ -385,19 +385,31 @@ private static UnknownType.UnresolvedImportType createUnresolvedImportType(List<
public void visitAssignmentStatement(AssignmentStatement assignmentStatement) {
scan(assignmentStatement.assignedValue());
scan(assignmentStatement.lhsExpressions());
Optional.of(assignmentStatement)

getFirstAssignmentName(assignmentStatement).ifPresent(lhsName -> {
var assignedValueType = assignmentStatement.assignedValue().typeV2();
lhsName.typeV2(assignedValueType);
addStaticFieldToClass(lhsName);
});
}

private static Optional<NameImpl> getFirstAssignmentName(AssignmentStatement assignmentStatement) {
return Optional.of(assignmentStatement)
.map(AssignmentStatement::lhsExpressions)
.filter(lhs -> lhs.size() == 1)
.map(lhs -> lhs.get(0))
.map(ExpressionList::expressions)
.filter(lhs -> lhs.size() == 1)
.map(lhs -> lhs.get(0))
.filter(NameImpl.class::isInstance)
.map(NameImpl.class::cast)
.ifPresent(lhsName -> {
var assignedValueType = assignmentStatement.assignedValue().typeV2();
lhsName.typeV2(assignedValueType);
});
.map(NameImpl.class::cast);
}

private void addStaticFieldToClass(Name name) {
if (currentType() instanceof ClassType ownerClass) {
PythonType memberType = name.symbolV2().hasSingleBindingUsage() ? name.typeV2() : PythonType.UNKNOWN;
ownerClass.members().add(new Member(name.name(), memberType));
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ void testImportWithAlias() {
assertThat(importedNames)
.flatExtracting(Expression::typeV2)
.allMatch(PythonType.UNKNOWN::equals);

assertThat(aliasedName.alias())
.extracting(Expression::typeV2)
.isInstanceOf(ModuleType.class)
Expand Down Expand Up @@ -458,6 +458,62 @@ class A:
.isEqualTo(PythonType.UNKNOWN);
}

@Test
void staticFieldsInInheritedClasses() {
Expression exprWithInheritance = lastExpression("""
class A:
test = "hi"
class B(A):
pass
B.test
""");
assertThat(exprWithInheritance.typeV2())
.isInstanceOf(ObjectType.class)
.extracting(PythonType::unwrappedType)
.isEqualTo(STR_TYPE);

Expression exprWithInheritance2 = lastExpression("""
class A:
test = True
class B(A):
test = "hi"
class C(B):
pass
C.test
""");
assertThat(exprWithInheritance2.typeV2())
.isInstanceOf(ObjectType.class)
.extracting(PythonType::unwrappedType)
.isEqualTo(STR_TYPE);

Expression exprWithMultiInheritance = lastExpression("""
class A:
test = "hi"
class B: pass
class C(A, B):
pass
C.test
""");
assertThat(exprWithMultiInheritance.typeV2())
.isInstanceOf(ObjectType.class)
.extracting(PythonType::unwrappedType)
.isEqualTo(STR_TYPE);

Expression exprWithMultiInheritance2 = lastExpression("""
class A:
pass
class B:
test = "hi"
class C(A, B):
pass
C.test
""");
assertThat(exprWithMultiInheritance2.typeV2())
.isInstanceOf(ObjectType.class)
.extracting(PythonType::unwrappedType)
.isEqualTo(STR_TYPE);
}

@Test
void inferTypeForBuiltins() {
FileInput root = inferTypes("""
Expand Down Expand Up @@ -717,7 +773,7 @@ def foo(param: int | str):
var functionDef = (FunctionDef) root.statements().statements().get(0);
var lastExpressionStatement = (ExpressionStatement) functionDef.body().statements().get(functionDef.body().statements().size() -1);
var type = (UnionType) lastExpressionStatement.expressions().get(0).typeV2();

Assertions.assertThat(type.candidates())
.extracting(PythonType::unwrappedType)
.containsOnly(INT_TYPE, STR_TYPE);
Expand Down

0 comments on commit 3e383e9

Please sign in to comment.