void (@NotNull Project project, @NotNull ProblemDescriptor descriptor) { try { // there can be no name clash, else the name would have resolved, and it hasn't. final PsiElement problemElement = descriptor.getPsiElement(); final PyClassType type = getClassType(problemElement); if (type == null) return; final PyClass cls = type.getPyClass(); boolean callByClass = type.isDefinition(); PyStatementList clsStmtList = cls.getStatementList(); sure(FileModificationService.getInstance().preparePsiElementForWrite(clsStmtList)); // try to at least match parameter count // TODO: get parameter style from code style PyFunctionBuilder builder = new PyFunctionBuilder(myIdentifier, cls); PsiElement pe = problemElement.getParent(); String decoratorName = null; // set to non-null to add a decorator PyExpression[] args = PyExpression.EMPTY_ARRAY; if (pe instanceof PyCallExpression) { PyArgumentList arglist = ((PyCallExpression)pe).getArgumentList(); if (arglist == null) return; args = arglist.getArguments(); } boolean madeInstance = false; if (callByClass) { if (args.length > 0) { final TypeEvalContext context = TypeEvalContext.userInitiated(cls.getProject(), cls.getContainingFile()); final PyType firstArgType = context.getType(args[0]); if (firstArgType instanceof PyClassType && ((PyClassType)firstArgType).getPyClass().isSubclass(cls, context)) { // class, first arg ok: instance method builder.parameter("self"); // NOTE: might use a name other than 'self', according to code style. madeInstance = true; } } if (!madeInstance) { // class, first arg absent or of different type: classmethod builder.parameter("cls"); // NOTE: might use a name other than 'cls', according to code style. decoratorName = PyNames.CLASSMETHOD; } } else { // instance method builder.parameter("self"); // NOTE: might use a name other than 'self', according to code style. } boolean skipFirst = callByClass && madeInstance; // ClassFoo.meth(foo_instance) for (PyExpression arg : args) { if (skipFirst) { skipFirst = false; continue; } if (arg instanceof PyKeywordArgument) { // foo(bar) -> def foo(self, bar_1) builder.parameter(((PyKeywordArgument)arg).getKeyword()); } else if (arg instanceof PyReferenceExpression refex) { builder.parameter(refex.getReferencedName()); } else { // use a boring name builder.parameter("param"); } } PyFunction method = builder.buildFunction(); if (decoratorName != null) { PyElementGenerator generator = PyElementGenerator.getInstance(project); PyDecoratorList decoratorList = generator .createFromText(LanguageLevel.getDefault(), PyDecoratorList.class, "@" + decoratorName + "\ndef foo(): pass", new int[]{0, 0}); method.addBefore(decoratorList, method.getFirstChild()); // in the very beginning } method = (PyFunction)PyPsiRefactoringUtil.addElementToStatementList(method, clsStmtList, PyNames.INIT.equals(method.getName())); if (myReplaceUsage) { showTemplateBuilder(method); } } catch (IncorrectOperationException ignored) { // we failed. tell about this PythonUiService.getInstance().showBalloonError(project, PyPsiBundle.message("QFIX.failed.to.add.method")); } }