TreeUtils { public static List<Parameter> positionalParameters(FunctionDef functionDef) { ParameterList parameterList = functionDef.parameters(); if (parameterList == null) { return Collections.emptyList(); } List<Parameter> result = new ArrayList<>(); for (AnyParameter anyParameter : parameterList.all()) { if (anyParameter instanceof Parameter) { Parameter parameter = (Parameter) anyParameter; Token starToken = parameter.starToken(); if (parameter.name() == null && starToken != null) { if ("*".equals(starToken.value())) { return result; } } else { result.add(parameter); } } } return result; } private  TreeUtils(); @CheckForNull static Tree firstAncestor(Tree tree, Predicate<Tree> predicate); @CheckForNull static Tree firstAncestorOfKind(Tree tree, Kind... kinds); static List<Token> tokens(Tree tree); static List<Token> nonWhitespaceTokens(Tree tree); static boolean hasDescendant(Tree tree, Predicate<Tree> predicate); static Stream<Expression> flattenTuples(Expression expression); static Optional<Symbol> getSymbolFromTree(@Nullable Tree tree); @CheckForNull static ClassSymbol getClassSymbolFromDef(@Nullable ClassDef classDef); @CheckForNull static FunctionSymbol getFunctionSymbolFromDef(@Nullable FunctionDef functionDef); static List<Parameter> nonTupleParameters(FunctionDef functionDef); static List<Parameter> positionalParameters(FunctionDef functionDef); static List<FunctionDef> topLevelFunctionDefs(ClassDef classDef); @CheckForNull static RegularArgument argumentByKeyword(String keyword, List<Argument> arguments); @CheckForNull static RegularArgument nthArgumentOrKeyword(int argPosition, String keyword, List<Argument> arguments); static boolean isBooleanLiteral(Tree tree); static String nameFromExpression(Expression expression); @CheckForNull static LocationInFile locationInFile(Tree tree, @Nullable String fileId);  }
@Test public void positionalParameters() { FileInput fileInput = PythonTestUtils.parse("def foo(): pass"); FunctionDef functionDef = PythonTestUtils.getLastDescendant(fileInput, t -> t.is(Kind.FUNCDEF)); assertThat(TreeUtils.positionalParameters(functionDef)).isEmpty(); fileInput = PythonTestUtils.parse("def foo(param1, param2): pass"); functionDef = PythonTestUtils.getLastDescendant(fileInput, t -> t.is(Kind.FUNCDEF)); assertThat(TreeUtils.positionalParameters(functionDef)).isEqualTo(functionDef.parameters().all()); fileInput = PythonTestUtils.parse("def foo(param1, *param2): pass"); functionDef = PythonTestUtils.getLastDescendant(fileInput, t -> t.is(Kind.FUNCDEF)); assertThat(TreeUtils.positionalParameters(functionDef)).isEqualTo(functionDef.parameters().all()); fileInput = PythonTestUtils.parse("def foo(param1, param2, *, kw1, kw2): pass"); functionDef = PythonTestUtils.getLastDescendant(fileInput, t -> t.is(Kind.FUNCDEF)); assertThat(TreeUtils.positionalParameters(functionDef)).isEqualTo(functionDef.parameters().all().subList(0, 2)); fileInput = PythonTestUtils.parse("def foo((param1, param2), *, kw1, kw2): pass"); functionDef = PythonTestUtils.getLastDescendant(fileInput, t -> t.is(Kind.FUNCDEF)); assertThat(TreeUtils.positionalParameters(functionDef)).isEmpty(); fileInput = PythonTestUtils.parse("def foo(param1, /, param2, *, kw1, kw2): pass"); functionDef = PythonTestUtils.getLastDescendant(fileInput, t -> t.is(Kind.FUNCDEF)); List<AnyParameter> parameters = functionDef.parameters().all(); assertThat(TreeUtils.positionalParameters(functionDef)).isEqualTo( Arrays.asList(parameters.get(0), parameters.get(2) )); }