diff --git a/python-frontend/src/main/java/org/sonar/python/semantic/v2/converter/FunctionDescriptorToPythonTypeConverter.java b/python-frontend/src/main/java/org/sonar/python/semantic/v2/converter/FunctionDescriptorToPythonTypeConverter.java index b14d1d7711..289c26bee3 100644 --- a/python-frontend/src/main/java/org/sonar/python/semantic/v2/converter/FunctionDescriptorToPythonTypeConverter.java +++ b/python-frontend/src/main/java/org/sonar/python/semantic/v2/converter/FunctionDescriptorToPythonTypeConverter.java @@ -55,9 +55,6 @@ public PythonType convert(ConversionContext ctx, FunctionDescriptor from) { var decorators = from.decorators() .stream() - .map(decoratorName -> Stream.of(ctx.moduleFqn(), decoratorName) - .filter(Predicate.not(String::isEmpty)) - .collect(Collectors.joining("."))) .map(ctx.lazyTypesContext()::getOrCreateLazyType) .map(TypeWrapper::of) .toList(); diff --git a/python-frontend/src/main/java/org/sonar/python/semantic/v2/converter/PythonTypeToDescriptorConverter.java b/python-frontend/src/main/java/org/sonar/python/semantic/v2/converter/PythonTypeToDescriptorConverter.java index 451cbc038a..b14ffc8c75 100644 --- a/python-frontend/src/main/java/org/sonar/python/semantic/v2/converter/PythonTypeToDescriptorConverter.java +++ b/python-frontend/src/main/java/org/sonar/python/semantic/v2/converter/PythonTypeToDescriptorConverter.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -36,6 +37,7 @@ import org.sonar.python.types.v2.FunctionType; import org.sonar.python.types.v2.ParameterV2; import org.sonar.python.types.v2.PythonType; +import org.sonar.python.types.v2.TypeWrapper; import org.sonar.python.types.v2.UnionType; import org.sonar.python.types.v2.UnknownType; @@ -87,11 +89,18 @@ private static Descriptor convert(String moduleFqn, String parentFqn, String sym .map(parameter -> convert(moduleFqn, parameter)) .toList(); + var decorators = type.decorators() + .stream() + .map(TypeWrapper::type) + .map(decorator -> typeFqn(moduleFqn, decorator)) + .filter(Objects::nonNull) + .toList(); + return new FunctionDescriptor(symbolName, symbolFqn(parentFqn, symbolName), parameters, type.isAsynchronous(), type.isInstanceMethod(), - List.of(), + decorators, type.hasDecorators(), type.definitionLocation().orElse(null), null, @@ -165,8 +174,8 @@ private static FunctionDescriptor.Parameter convert(String moduleFqn, ParameterV private static String typeFqn(String moduleFqn, PythonType type) { if (type instanceof UnknownType.UnresolvedImportType importType) { return importType.importPath(); - } else if (type instanceof ClassType classType) { - return moduleFqn + "." + classType.name(); + } else if (type instanceof ClassType || type instanceof FunctionType) { + return moduleFqn + "." + type.name(); } return null; } diff --git a/python-frontend/src/test/java/org/sonar/python/semantic/v2/ProjectLevelTypeTableTest.java b/python-frontend/src/test/java/org/sonar/python/semantic/v2/ProjectLevelTypeTableTest.java index 0297aa43ea..e46d53f732 100644 --- a/python-frontend/src/test/java/org/sonar/python/semantic/v2/ProjectLevelTypeTableTest.java +++ b/python-frontend/src/test/java/org/sonar/python/semantic/v2/ProjectLevelTypeTableTest.java @@ -267,7 +267,6 @@ void resolveStubsWithImportedModuleVariableDescriptor() { } @Test - @Disabled("SONARPY-2290") void importFunctionWithDecorators() { var projectLevelSymbolTable = new ProjectLevelSymbolTable(); var libTree = parseWithoutSymbols( @@ -294,7 +293,6 @@ def foo(): ... } @Test - @Disabled("SONARPY-2290") void importFunctionWithImportedDecorators() { var projectLevelSymbolTable = new ProjectLevelSymbolTable(); var libTree = parseWithoutSymbols( @@ -305,9 +303,9 @@ def lib_decorator(): ... projectLevelSymbolTable.addModule(libTree, "", pythonFile("lib.py")); var lib2Tree = parseWithoutSymbols( """ - import lib + import lib as l - @lib.lib_decorator + @l.lib_decorator def foo(): ... """ ); @@ -322,7 +320,7 @@ def foo(): ... ); var fooType = (FunctionType) ((ExpressionStatement) fileInput.statements().statements().get(1)).expressions().get(0).typeV2(); var typeWrapper = (LazyTypeWrapper) fooType.decorators().get(0); - assertThat(typeWrapper.hasImportPath("lib2.lib.lib_decorator")).isTrue(); + assertThat(typeWrapper.hasImportPath("lib.lib_decorator")).isTrue(); } @Test diff --git a/python-frontend/src/test/java/org/sonar/python/types/v2/FunctionTypeTest.java b/python-frontend/src/test/java/org/sonar/python/types/v2/FunctionTypeTest.java index 652a428d0e..959cfb25d7 100644 --- a/python-frontend/src/test/java/org/sonar/python/types/v2/FunctionTypeTest.java +++ b/python-frontend/src/test/java/org/sonar/python/types/v2/FunctionTypeTest.java @@ -159,7 +159,6 @@ void declared_return_type() { @Test void decorators() { - // TODO: SONARPY-1772 Handle decorators FunctionType functionType = functionType("@something\ndef fn(p1, *args): pass"); assertThat(functionType.hasDecorators()).isTrue();