SymbolUtils { public static int firstParameterOffset(FunctionSymbol functionSymbol, boolean isStaticCall) { List<FunctionSymbol.Parameter> parameters = functionSymbol.parameters(); if (parameters.isEmpty()) { return 0; } String firstParamName = parameters.get(0).name(); if (firstParamName == null) { return -1; } List<String> decoratorNames = functionSymbol.decorators(); if (decoratorNames.size() > 1) { return -1; } if (!decoratorNames.isEmpty() && !decoratorNames.get(0).endsWith("classmethod") && !decoratorNames.get(0).endsWith("staticmethod")) { return -1; } if (functionSymbol.isInstanceMethod() && !isStaticCall) { return 1; } if (decoratorNames.size() == 1 && decoratorNames.get(0).endsWith("classmethod")) { return 1; } return 0; } private  SymbolUtils(); static String getModuleFileName(String fileName); static String fullyQualifiedModuleName(String packageName, String fileName); static List<Expression> assignmentsLhs(AssignmentStatement assignmentStatement); static String pythonPackageName(File file, File projectBaseDir); @CheckForNull static Path pathOf(PythonFile pythonFile); static boolean isTypeShedFile(PythonFile pythonFile); static int firstParameterOffset(FunctionSymbol functionSymbol, boolean isStaticCall); static Optional<FunctionSymbol> getOverriddenMethod(FunctionSymbol functionSymbol);  }
@Test public void first_parameter_offset() { FunctionSymbol functionSymbol = functionSymbol("class A:\n def method(self, *args): pass"); assertThat(SymbolUtils.firstParameterOffset(functionSymbol, true)).isEqualTo(0); assertThat(SymbolUtils.firstParameterOffset(functionSymbol, false)).isEqualTo(1); functionSymbol = functionSymbol("class A:\n @staticmethod\n def method(a, b): pass"); assertThat(SymbolUtils.firstParameterOffset(functionSymbol, true)).isEqualTo(0); assertThat(SymbolUtils.firstParameterOffset(functionSymbol, false)).isEqualTo(0); functionSymbol = functionSymbol("class A:\n @classmethod\n def method(a, b): pass"); assertThat(SymbolUtils.firstParameterOffset(functionSymbol, true)).isEqualTo(1); assertThat(SymbolUtils.firstParameterOffset(functionSymbol, false)).isEqualTo(1); functionSymbol = functionSymbol("class A:\n @staticmethod\n @another_decorator\n def method(a, b): pass"); assertThat(SymbolUtils.firstParameterOffset(functionSymbol, true)).isEqualTo(-1); assertThat(SymbolUtils.firstParameterOffset(functionSymbol, false)).isEqualTo(-1); functionSymbol = functionSymbol("class A:\n @unknown_decorator\n def method(self, *args): pass"); assertThat(SymbolUtils.firstParameterOffset(functionSymbol, false)).isEqualTo(-1); assertThat(SymbolUtils.firstParameterOffset(functionSymbol, true)).isEqualTo(-1); functionSymbol = functionSymbol("class A:\n def method((a, b), c): pass"); assertThat(SymbolUtils.firstParameterOffset(functionSymbol, false)).isEqualTo(-1); assertThat(SymbolUtils.firstParameterOffset(functionSymbol, true)).isEqualTo(-1); functionSymbol = functionSymbol("def function(): pass"); assertThat(SymbolUtils.firstParameterOffset(functionSymbol, true)).isEqualTo(0); }