Skip to content

Commit

Permalink
SONARPY-1515 Support function and class type parameters for Symbol ta…
Browse files Browse the repository at this point in the history
…ble (#1605)
  • Loading branch information
maksim-grebeniuk-sonarsource authored Oct 16, 2023
1 parent 1460356 commit 48f9a13
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ enum Kind {
EXCEPTION_INSTANCE,
WITH_INSTANCE,
GLOBAL_DECLARATION,
PATTERN_DECLARATION
PATTERN_DECLARATION,
TYPE_PARAM_DECLARATION
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
Expand Down Expand Up @@ -74,6 +75,7 @@
import org.sonar.plugins.python.api.tree.Tree.Kind;
import org.sonar.plugins.python.api.tree.TupleParameter;
import org.sonar.plugins.python.api.tree.TypeAnnotation;
import org.sonar.plugins.python.api.tree.TypeParams;
import org.sonar.plugins.python.api.tree.WithItem;
import org.sonar.python.tree.ClassDefImpl;
import org.sonar.python.tree.ComprehensionExpressionImpl;
Expand Down Expand Up @@ -326,18 +328,28 @@ public void visitFunctionDef(FunctionDef pyFunctionDefTree) {
currentScope().addFunctionSymbol(pyFunctionDefTree, fullyQualifiedName);
createScope(pyFunctionDefTree, currentScope());
enterScope(pyFunctionDefTree);
createTypeParameters(pyFunctionDefTree.typeParams());
createParameters(pyFunctionDefTree);
super.visitFunctionDef(pyFunctionDefTree);
leaveScope();
}

private void createTypeParameters(@Nullable TypeParams typeParams) {
Optional.ofNullable(typeParams)
.map(TypeParams::typeParamsList)
.stream()
.flatMap(Collection::stream)
.forEach(typeParam -> addBindingUsage(typeParam.name(), Usage.Kind.TYPE_PARAM_DECLARATION));
}

@Override
public void visitClassDef(ClassDef pyClassDefTree) {
String className = pyClassDefTree.name().name();
String fullyQualifiedName = getFullyQualifiedName(className);
currentScope().addClassSymbol(pyClassDefTree, fullyQualifiedName);
createScope(pyClassDefTree, currentScope());
enterScope(pyClassDefTree);
createTypeParameters(pyClassDefTree.typeParams());
super.visitClassDef(pyClassDefTree);
leaveScope();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ void global_variable() {
"function_with_lambdas", "var_with_usages_in_decorator", "fn_inside_comprehension_same_name", "with_instance", "exception_instance", "unpacking",
"using_builtin_symbol", "keyword_usage", "comprehension_vars", "parameter_default_value", "assignment_expression", "importing_stdlib", "importing_submodule",
"importing_submodule_as", "importing_submodule_after_parent", "importing_submodule_after_parent_nested", "importing_parent_after_submodule",
"importing_parent_after_submodule_2", "importing_submodule_twice", "importing_unknown_submodule");
"importing_parent_after_submodule_2", "importing_submodule_twice", "importing_unknown_submodule", "type_params");

List<String> globalSymbols = new ArrayList<>(topLevelFunctions);
globalSymbols.addAll(Arrays.asList("a", "global_x", "global_var"));
Expand Down Expand Up @@ -607,6 +607,15 @@ void assignment_expression() {
assertThat(b.usages()).extracting(Usage::kind).containsExactly(Usage.Kind.ASSIGNMENT_LHS, Usage.Kind.OTHER);
}

@Test
void type_params() {
FunctionDef functionDef = functionTreesByName.get("type_params");
Map<String, Symbol> symbolByName = getSymbolByName(functionDef);
assertThat(symbolByName).hasSize(2).containsKey("T");
assertThat(symbolByName.get("T").usages()).hasSize(2);
assertThat(symbolByName.get("T").usages().get(0).kind()).isEqualTo(Usage.Kind.TYPE_PARAM_DECLARATION);
}

private static class TestVisitor extends BaseTreeVisitor {
@Override
public void visitFunctionDef(FunctionDef pyFunctionDefTree) {
Expand Down
4 changes: 4 additions & 0 deletions python-frontend/src/test/resources/semantic/symbols2.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,7 @@ def importing_unknown_submodule():
import werkzeug.datastructures.unknown
import werkzeug.datastructures.unknown
werkzeug.datastructures.Headers()

def type_params[T: str]():
a : T = "abc"
return a

0 comments on commit 48f9a13

Please sign in to comment.