From c57a8cdfc5469563acb4659554dc34f1a3a99799 Mon Sep 17 00:00:00 2001 From: Guillaume Dequenne Date: Fri, 13 Dec 2024 15:38:58 +0100 Subject: [PATCH] SONARPY-2467 Fix performance bottleneck of GlobalSymbolComputation due to DjangoViewsVisitor --- .../semantic/ProjectLevelSymbolTable.java | 19 ++++++++++++++++--- .../semantic/ProjectLevelSymbolTableTest.java | 2 +- .../plugins/python/PythonSensorTest.java | 2 +- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/python-frontend/src/main/java/org/sonar/python/semantic/ProjectLevelSymbolTable.java b/python-frontend/src/main/java/org/sonar/python/semantic/ProjectLevelSymbolTable.java index 22225626e0..79fba85250 100644 --- a/python-frontend/src/main/java/org/sonar/python/semantic/ProjectLevelSymbolTable.java +++ b/python-frontend/src/main/java/org/sonar/python/semantic/ProjectLevelSymbolTable.java @@ -31,7 +31,10 @@ import org.sonar.plugins.python.api.symbols.Symbol; import org.sonar.plugins.python.api.tree.BaseTreeVisitor; import org.sonar.plugins.python.api.tree.CallExpression; +import org.sonar.plugins.python.api.tree.Expression; import org.sonar.plugins.python.api.tree.FileInput; +import org.sonar.plugins.python.api.tree.Name; +import org.sonar.plugins.python.api.tree.QualifiedExpression; import org.sonar.plugins.python.api.tree.RegularArgument; import org.sonar.python.index.AmbiguousDescriptor; import org.sonar.python.index.Descriptor; @@ -46,6 +49,7 @@ import org.sonar.python.types.v2.FunctionType; import org.sonar.python.types.v2.PythonType; import org.sonar.python.types.v2.TriBool; +import org.sonar.python.types.v2.TypeCheckBuilder; import org.sonar.python.types.v2.TypeChecker; import org.sonar.python.types.v2.UnknownType; @@ -223,11 +227,21 @@ public Collection stubFilesSymbols() { private class DjangoViewsVisitor extends BaseTreeVisitor { String fullyQualifiedModuleName; + private TypeCheckBuilder confPathCall = null; + private TypeCheckBuilder pathCall = null; public DjangoViewsVisitor(String fullyQualifiedModuleName) { this.fullyQualifiedModuleName = fullyQualifiedModuleName; } + @Override + public void visitFileInput(FileInput fileInput) { + TypeChecker typeChecker = new TypeChecker(new BasicTypeTable(new ProjectLevelTypeTable(ProjectLevelSymbolTable.this))); + confPathCall = typeChecker.typeCheckBuilder().isTypeWithName("django.urls.conf.path"); + pathCall = typeChecker.typeCheckBuilder().isTypeWithName("django.urls.path"); + super.visitFileInput(fileInput); + } + @Override public void visitCallExpression(CallExpression callExpression) { super.visitCallExpression(callExpression); @@ -246,9 +260,8 @@ public void visitCallExpression(CallExpression callExpression) { } private boolean isCallRegisteringDjangoView(CallExpression callExpression) { - TypeChecker typeChecker = new TypeChecker(new BasicTypeTable(new ProjectLevelTypeTable(ProjectLevelSymbolTable.this))); - TriBool isConfPathCall = typeChecker.typeCheckBuilder().isTypeWithName("django.urls.conf.path").check(callExpression.callee().typeV2()); - TriBool isPathCall = typeChecker.typeCheckBuilder().isTypeWithName("django.urls.path").check(callExpression.callee().typeV2()); + TriBool isConfPathCall = confPathCall.check(callExpression.callee().typeV2()); + TriBool isPathCall = pathCall.check(callExpression.callee().typeV2()); return isConfPathCall.equals(TriBool.TRUE) || isPathCall.equals(TriBool.TRUE); } } diff --git a/python-frontend/src/test/java/org/sonar/python/semantic/ProjectLevelSymbolTableTest.java b/python-frontend/src/test/java/org/sonar/python/semantic/ProjectLevelSymbolTableTest.java index dd6aaa7655..0dadb082c9 100644 --- a/python-frontend/src/test/java/org/sonar/python/semantic/ProjectLevelSymbolTableTest.java +++ b/python-frontend/src/test/java/org/sonar/python/semantic/ProjectLevelSymbolTableTest.java @@ -521,7 +521,7 @@ void importedStubModules() { """); ProjectLevelSymbolTable projectLevelSymbolTable = ProjectLevelSymbolTable.empty(); projectLevelSymbolTable.addModule(tree, "my_package", pythonFile("mod.py")); - assertThat(projectLevelSymbolTable.typeShedDescriptorsProvider().stubModules()).containsExactlyInAnyOrder("math", "os"); + assertThat(projectLevelSymbolTable.typeShedDescriptorsProvider().stubModules()).containsExactlyInAnyOrder("math", "os", "django", "django.urls.conf", "django.urls"); } @Test diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonSensorTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonSensorTest.java index 84c30ee8cf..06406c22af 100644 --- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonSensorTest.java +++ b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonSensorTest.java @@ -1113,7 +1113,7 @@ void write_cpd_tokens_to_cache() throws IOException { assertThat(writeCache.getData().keySet()).containsExactlyInAnyOrder( "python:cache_version", "python:files", "python:descriptors:moduleKey:pass.py", "python:imports:moduleKey:pass.py", - "python:cpd:data:moduleKey:pass.py", "python:cpd:stringTable:moduleKey:pass.py", "python:content_hashes:moduleKey:pass.py"); + "python:cpd:data:moduleKey:pass.py", "python:cpd:stringTable:moduleKey:pass.py", "python:content_hashes:moduleKey:pass.py", "python:typeshed_modules"); byte[] tokenData = writeCache.getData().get("python:cpd:data:moduleKey:pass.py"); byte[] stringTable = writeCache.getData().get("python:cpd:stringTable:moduleKey:pass.py");