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

SONARPY-2331 Implement setting metaclassFQN field for ClassType to ClassDescriptor conversion #2153

Merged
merged 2 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ class ImportedWithoutMetaClassInherited(ImportedParentWithoutMetaClass):
def imported_inherited_foo(self) -> Any: # Noncompliant
...
class ImportedWithMetaClassInherited(ImportedParentWithMetaClass):
def imported_inherited_foo(self) -> Any: # FN SONARPY-2331
def imported_inherited_foo(self) -> Any: # Noncompliant
...
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.plugins.python.api.LocationInFile;

Expand Down Expand Up @@ -94,6 +95,7 @@ public boolean hasMetaClass() {
return hasMetaClass;
}

@CheckForNull
public String metaclassFQN() {
return metaclassFQN;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,20 @@ private static Descriptor convert(String moduleFqn, String parentFqn, String sym
}
}

var metaclassFQN = type.metaClasses()
.stream()
.map(metaClass -> typeFqn(moduleFqn, metaClass))
.findFirst()
.orElse(null);

return new ClassDescriptor(symbolName, symbolFqn,
superClasses,
memberDescriptors,
type.hasDecorators(),
type.definitionLocation().orElse(null),
hasSuperClassWithoutDescriptor,
type.hasMetaClass(),
null,
metaclassFQN,

Choose a reason for hiding this comment

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

Not strictly related to the PR, but I see the metaclassFQN method is not annotated as CheckForNull which is probably misleading.

Also, I'm a bit concerned that we're going to cement the usage of the metaclassFQN somewhat inconsistently (because importType.importPath() does not produce a fully qualified name according to our definition). I think it's okay for now, but we should keep in mind that this probably need to change eventually (like for decorators).

false
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,44 @@ class Field(MetaField): ...
assertThat(symbol.hasUnresolvedTypeHierarchy()).isTrue();
}

@Test
void class_wth_imported_metaclass() {
var code = """
from abc import ABCMeta
class WithMetaclass(metaclass=ABCMeta): ...
""";

var projectSymbolTable = new ProjectLevelSymbolTable();
projectSymbolTable.addModule(parseWithoutSymbols(code), "", pythonFile("mod.py"));
var symbol = (ClassSymbolImpl) projectSymbolTable.getSymbol("mod.WithMetaclass");
assertThat(symbol.metaclassFQN()).isEqualTo("abc.ABCMeta");
}

@Test
void class_wth_locally_defined_metaclass() {
var code = """
class LocalMetaClass: ...
class WithMetaclass(metaclass=LocalMetaClass): ...
""";

var projectSymbolTable = new ProjectLevelSymbolTable();
projectSymbolTable.addModule(parseWithoutSymbols(code), "", pythonFile("mod.py"));
var symbol = (ClassSymbolImpl) projectSymbolTable.getSymbol("mod.WithMetaclass");
assertThat(symbol.metaclassFQN()).isEqualTo("mod.LocalMetaClass");
}

@Test
void class_wth_unresolved_import_metaclass() {
var code = """
from unknown import UnresolvedMetaClass
class WithMetaclass(metaclass=UnresolvedMetaClass): ...
""";

var projectSymbolTable = new ProjectLevelSymbolTable();
projectSymbolTable.addModule(parseWithoutSymbols(code), "", pythonFile("mod.py"));
var symbol = (ClassSymbolImpl) projectSymbolTable.getSymbol("mod.WithMetaclass");
assertThat(symbol.metaclassFQN()).isEqualTo("unknown.UnresolvedMetaClass");
}

@Test
void projectPackages() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,7 @@ void testConvertClassType() {

// SONARPY-2307 support for superClass is missing in ClassType
assertThat(classDescriptor.hasSuperClassWithoutDescriptor()).isFalse();
// SONARPY-2307 support for metaclassFQN is missing in ClassType
assertThat(classDescriptor.metaclassFQN()).isNull();
assertThat(classDescriptor.metaclassFQN()).isEqualTo("int");
// SONARPY-2307 support for generics is missing in ClassType
assertThat(classDescriptor.supportsGenerics()).isFalse();
}
Expand Down