private static boolean isAbstractMethodForClass(
     @NotNull PyFunction method, @NotNull PyClass cls) {
   final String methodName = method.getName();
   if (methodName == null
       || cls.findMethodByName(methodName, false) != null
       || cls.findClassAttribute(methodName, false) != null) {
     return false;
   }
   return PyUtil.isDecoratedAsAbstract(method)
       || PyOverrideImplementUtil.raisesNotImplementedError(method);
 }
 private static boolean inConstructor(@NotNull PsiElement expression) {
   final PsiElement expr = expression instanceof PyClass ? expression : expression.getParent();
   PyClass clazz = PyUtil.getContainingClassOrSelf(expr);
   final ScopeOwner current = ScopeUtil.getScopeOwner(expression);
   if (clazz != null && current != null && current instanceof PyFunction) {
     PyFunction init = clazz.findMethodByName(PyNames.INIT, false, null);
     if (current == init) {
       return true;
     }
   }
   return false;
 }
 @Nullable
 private static Boolean isOverrides(final PyFunction pyFunction) {
   final PyClass clazz = PyUtil.getContainingClassOrSelf(pyFunction);
   assert clazz != null : "Refactoring called on function, not method: " + pyFunction;
   for (final PyClass parentClass : clazz.getSuperClasses()) {
     final PyFunction parentMethod = parentClass.findMethodByName(pyFunction.getName(), true);
     if (parentMethod != null) {
       return true;
     }
   }
   return null;
 }
 @Nullable
 private static PsiElement addFieldToSetUp(
     PyClass clazz, final Function<String, PyStatement> callback) {
   final PyFunction init =
       clazz.findMethodByName(PythonUnitTestUtil.TESTCASE_SETUP_NAME, false, null);
   if (init != null) {
     return AddFieldQuickFix.appendToMethod(init, callback);
   }
   final PyFunctionBuilder builder =
       new PyFunctionBuilder(PythonUnitTestUtil.TESTCASE_SETUP_NAME, clazz);
   builder.parameter(PyNames.CANONICAL_SELF);
   PyFunction setUp = builder.buildFunction(clazz.getProject(), LanguageLevel.getDefault());
   final PyStatementList statements = clazz.getStatementList();
   final PsiElement anchor = statements.getFirstChild();
   setUp = (PyFunction) statements.addBefore(setUp, anchor);
   return AddFieldQuickFix.appendToMethod(setUp, callback);
 }
 private void addPredefinedMethodDoc(PyFunction fun, String mothodName) {
   PyClassType objectType =
       PyBuiltinCache.getInstance(fun)
           .getObjectType(); // old- and new-style classes share the __xxx__ stuff
   if (objectType != null) {
     PyClass objectClass = objectType.getPyClass();
     PyFunction predefinedMethod = objectClass.findMethodByName(mothodName, false);
     if (predefinedMethod != null) {
       PyStringLiteralExpression predefinedDocstring = predefinedMethod.getDocStringExpression();
       String predefinedDoc =
           predefinedDocstring != null ? predefinedDocstring.getStringValue() : null;
       if (predefinedDoc != null
           && predefinedDoc.length() > 1) { // only a real-looking doc string counts
         addFormattedDocString(fun, predefinedDoc, myBody, myBody);
         myEpilog.addItem(BR).addItem(BR).addItem(PyBundle.message("QDOC.copied.from.builtin"));
       }
     }
   }
 }
  private void addInheritedDocString(
      @NotNull final PyFunction pyFunction, @Nullable final PyClass pyClass) {
    boolean notFound = true;
    final String methodName = pyFunction.getName();
    if (pyClass == null || methodName == null) {
      return;
    }
    final boolean isConstructor = PyNames.INIT.equals(methodName);
    Iterable<PyClass> classes = pyClass.getAncestorClasses(null);
    if (isConstructor) {
      // look at our own class again and maybe inherit class's doc
      classes = new ChainIterable<PyClass>(pyClass).add(classes);
    }
    for (PyClass ancestor : classes) {
      PyStringLiteralExpression docstringElement = null;
      PyFunction inherited = null;
      boolean isFromClass = false;
      if (isConstructor) docstringElement = pyClass.getDocStringExpression();
      if (docstringElement != null) {
        isFromClass = true;
      } else {
        inherited = ancestor.findMethodByName(methodName, false);
      }
      if (inherited != null) {
        docstringElement = inherited.getDocStringExpression();
      }
      if (docstringElement != null) {
        final String inheritedDoc = docstringElement.getStringValue();
        if (inheritedDoc.length() > 1) {
          myEpilog.addItem(BR).addItem(BR);
          String ancestor_name = ancestor.getName();
          String marker =
              (pyClass == ancestor)
                  ? PythonDocumentationProvider.LINK_TYPE_CLASS
                  : PythonDocumentationProvider.LINK_TYPE_PARENT;
          final String ancestor_link =
              $().addWith(new LinkWrapper(marker + ancestor_name), $(ancestor_name)).toString();
          if (isFromClass) {
            myEpilog.addItem(PyBundle.message("QDOC.copied.from.class.$0", ancestor_link));
          } else {
            myEpilog.addItem(PyBundle.message("QDOC.copied.from.$0.$1", ancestor_link, methodName));
          }
          myEpilog.addItem(BR).addItem(BR);
          ChainIterable<String> formatted = new ChainIterable<String>();
          ChainIterable<String> unformatted = new ChainIterable<String>();
          addFormattedDocString(pyFunction, inheritedDoc, formatted, unformatted);
          myEpilog.addWith(TagCode, formatted).add(unformatted);
          notFound = false;
          break;
        }
      }
    }

    if (notFound) {
      // above could have not worked because inheritance is not searched down to 'object'.
      // for well-known methods, copy built-in doc string.
      // TODO: also handle predefined __xxx__ that are not part of 'object'.
      if (PyNames.UnderscoredAttributes.contains(methodName)) {
        addPredefinedMethodDoc(pyFunction, methodName);
      }
    }
  }