@Override
  public boolean isAsyncAllowed() {
    final LanguageLevel languageLevel = LanguageLevel.forElement(this);
    final String functionName = getName();

    return languageLevel.isAtLeast(LanguageLevel.PYTHON35)
        && (functionName == null
            || ArrayUtil.contains(
                functionName, PyNames.AITER, PyNames.ANEXT, PyNames.AENTER, PyNames.AEXIT)
            || !PyNames.getBuiltinMethods(languageLevel).containsKey(functionName));
  }
 @Nullable
 @Override
 public PyType getReturnType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) {
   for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
     final PyType returnType = typeProvider.getReturnType(this, context);
     if (returnType != null) {
       returnType.assertValid(typeProvider.toString());
       return returnType;
     }
   }
   if (context.maySwitchToAST(this)
       && LanguageLevel.forElement(this).isAtLeast(LanguageLevel.PYTHON30)) {
     PyAnnotation anno = getAnnotation();
     if (anno != null) {
       PyClass pyClass = anno.resolveToClass();
       if (pyClass != null) {
         return new PyClassTypeImpl(pyClass, false);
       }
     }
   }
   final PyType docStringType = getReturnTypeFromDocString();
   if (docStringType != null) {
     docStringType.assertValid("from docstring");
     return docStringType;
   }
   if (context.allowReturnTypes(this)) {
     final Ref<? extends PyType> yieldTypeRef = getYieldStatementType(context);
     if (yieldTypeRef != null) {
       return yieldTypeRef.get();
     }
     return getReturnStatementType(context);
   }
   return null;
 }
 @Nullable
 private PyType getGenericReturnType(
     @NotNull TypeEvalContext typeEvalContext, @Nullable PyQualifiedExpression callSite) {
   if (typeEvalContext.maySwitchToAST(this)
       && LanguageLevel.forElement(this).isAtLeast(LanguageLevel.PYTHON30)) {
     PyAnnotation anno = getAnnotation();
     if (anno != null) {
       PyClass pyClass = anno.resolveToClass();
       if (pyClass != null) {
         return new PyClassTypeImpl(pyClass, false);
       }
     }
   }
   for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
     final PyType returnType = typeProvider.getReturnType(this, callSite, typeEvalContext);
     if (returnType != null) {
       returnType.assertValid(typeProvider.toString());
       return returnType;
     }
   }
   final PyType docStringType = getReturnTypeFromDocString();
   if (docStringType != null) {
     docStringType.assertValid("from docstring");
     return docStringType;
   }
   if (typeEvalContext.allowReturnTypes(this)) {
     final PyType yieldType = getYieldStatementType(typeEvalContext);
     if (yieldType != null) {
       return yieldType;
     }
     return getReturnStatementType(typeEvalContext);
   }
   return null;
 }
  /**
   * Creates abstract version of each method in each class (does not touch method itself as opposite
   * to {@link #moveMethods(com.jetbrains.python.psi.PyClass, java.util.Collection,
   * com.jetbrains.python.psi.PyClass...)})
   *
   * @param currentFunctions functions to make them abstract
   * @param to classes where abstract method should be created
   */
  private static void makeMethodsAbstract(
      final Collection<PyFunction> currentFunctions, final PyClass... to) {
    final Set<PsiFile> filesToCheckImport = new HashSet<PsiFile>();
    final Set<PyClass> classesToAddMetaAbc = new HashSet<PyClass>();

    for (final PyFunction function : currentFunctions) {
      for (final PyClass destClass : to) {
        final PyFunctionBuilder functionBuilder =
            PyFunctionBuilder.copySignature(function, DECORATORS_MAY_BE_COPIED_TO_ABSTRACT);
        functionBuilder.decorate(PyNames.ABSTRACTMETHOD);
        final LanguageLevel level = LanguageLevel.forElement(destClass);
        PyClassRefactoringUtil.addMethods(
            destClass, false, functionBuilder.buildFunction(destClass.getProject(), level));
        classesToAddMetaAbc.add(destClass);
      }
    }

    // Add ABCMeta to new classes if needed
    for (final PyClass aClass : classesToAddMetaAbc) {
      if (addMetaAbcIfNeeded(aClass)) {
        filesToCheckImport.add(aClass.getContainingFile());
      }
    }

    // Add imports for ABC if needed
    for (final PsiFile file : filesToCheckImport) {
      addImportFromAbc(file, PyNames.ABSTRACTMETHOD);
      addImportFromAbc(file, ABC_META_CLASS);
      PyClassRefactoringUtil.optimizeImports(file); // To remove redundant imports
    }
  }
    @Nullable
    private ParseResult parseBuiltinType(@NotNull Token<PyElementType> token) {
      final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(myAnchor);
      final String name = token.getText().toString();
      final TextRange range = token.getRange();

      if (PyNames.UNKNOWN_TYPE.equals(name)) {
        return EMPTY_RESULT;
      } else if (PyNames.NONE.equals(name)) {
        return new ParseResult(null, PyNoneType.INSTANCE, range);
      } else if ("integer".equals(name)
          || ("long".equals(name) && LanguageLevel.forElement(myAnchor).isPy3K())) {
        final PyClassType type = builtinCache.getIntType();
        return type != null ? new ParseResult(null, type, range) : EMPTY_RESULT;
      } else if ("string".equals(name)) {
        final PyType type = builtinCache.getStringType(LanguageLevel.forElement(myAnchor));
        return type != null ? new ParseResult(null, type, range) : EMPTY_RESULT;
      } else if ("bytestring".equals(name)) {
        final PyType type = builtinCache.getByteStringType(LanguageLevel.forElement(myAnchor));
        return type != null ? new ParseResult(null, type, range) : EMPTY_RESULT;
      } else if ("bytes".equals(name)) {
        final PyClassType type = builtinCache.getBytesType(LanguageLevel.forElement(myAnchor));
        return type != null ? new ParseResult(null, type, range) : EMPTY_RESULT;
      } else if ("unicode".equals(name)) {
        final PyClassType type = builtinCache.getUnicodeType(LanguageLevel.forElement(myAnchor));
        return type != null ? new ParseResult(null, type, range) : EMPTY_RESULT;
      } else if ("boolean".equals(name)) {
        final PyClassType type = builtinCache.getBoolType();
        return type != null ? new ParseResult(null, type, range) : EMPTY_RESULT;
      } else if ("dictionary".equals(name)) {
        final PyClassType type = builtinCache.getDictType();
        return type != null ? new ParseResult(null, type, range) : EMPTY_RESULT;
      }

      final PyType builtinType = builtinCache.getObjectType(name);
      if (builtinType != null) {
        return new ParseResult(null, builtinType, range);
      }

      return null;
    }
  /**
   * @return if method could be made abstract? (that means "create abstract version if method in
   *     parent class")
   */
  private static boolean couldBeAbstract(@NotNull final PyFunction function) {
    if (PyUtil.isInit(function)) {
      return false; // Who wants to make __init__ abstract?!
    }
    final PyUtil.MethodFlags flags = PyUtil.MethodFlags.of(function);
    assert flags != null : "Function should be called on method!";

    final boolean py3K = LanguageLevel.forElement(function).isPy3K();

    // TODO: use strategy because we already has the same check in #addMetaAbcIfNeeded
    return flags.isInstanceMethod() || py3K; // Any method could be made abstract in py3
  }
 // TODO: Copy/Paste with PyClass.getMeta..
 private static boolean addMetaAbcIfNeeded(@NotNull final PyClass aClass) {
   final PsiFile file = aClass.getContainingFile();
   final PyType type = aClass.getMetaClassType(TypeEvalContext.userInitiated(file));
   if (type != null) {
     return false; // User already has metaclass. He probably knows about metaclasses, so we should
                   // not add ABCMeta
   }
   final LanguageLevel languageLevel = LanguageLevel.forElement(aClass);
   if (languageLevel
       .isPy3K()) { // TODO: Copy/paste, use strategy because we already has the same check in
                    // #couldBeAbstract
     // Add (metaclass= for Py3K
     PyClassRefactoringUtil.addSuperClassExpressions(
         aClass.getProject(),
         aClass,
         null,
         Collections.singletonList(Pair.create(PyNames.METACLASS, ABC_META_CLASS)));
   } else {
     // Add __metaclass__ for Py2
     PyClassRefactoringUtil.addClassAttributeIfNotExist(
         aClass, PyNames.DUNDER_METACLASS, ABC_META_CLASS);
   }
   return true;
 }
 protected PyExpression createExpression(Project project, String name, PsiElement declaration) {
   return PyElementGenerator.getInstance(project)
       .createExpressionFromText(LanguageLevel.forElement(declaration), name);
 }