private static void checkFunctionCall(AnnotationHolder holder, XPathFunctionCall call, @NotNull ContextProvider contextProvider) {
    final ASTNode node = call.getNode().findChildByType(XPathTokenTypes.FUNCTION_NAME);
    if (node == null) {
      return;
    }

    final QName name = contextProvider.getQName(call);
    final XPathFunction function = call.resolve();
    final Function functionDecl = function != null ? function.getDeclaration() : null;
    if (functionDecl == null) {
      final PrefixedNameImpl qName = (PrefixedNameImpl)call.getQName();

      // need special check for extension functions
      if (call.getQName().getPrefix() != null && contextProvider.getFunctionContext().allowsExtensions()) {
        final PsiReference[] references = call.getReferences();
        if (references.length > 1 && references[1].resolve() == null) {
          holder.newAnnotation(HighlightSeverity.ERROR,
                               XPathBundle.message("annotator.error.extension.namespace.prefix.has.not.been.declared", qName.getPrefix()))
            .range(qName.getPrefixNode())
          .highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL).create();
        } else if (name != null){
          final String extNS = name.getNamespaceURI();
          if (!StringUtil.isEmpty(extNS)) {
            final Set<Pair<QName,Integer>> pairs = contextProvider.getFunctionContext().getFunctions().keySet();
            for (Pair<QName, Integer> pair : pairs) {
              // extension namespace is known
              final String uri = pair.first.getNamespaceURI();
              if (uri != null && uri.equals(extNS)) {
                holder.newAnnotation(HighlightSeverity.WARNING, XPathBundle.message("annotator.warning.unknown.function", name)).range(node).create();
              }
            }
          }
        }
      } else {
        if (name != null) {
          holder.newAnnotation(HighlightSeverity.WARNING, XPathBundle.message("annotator.warning.unknown.function", name)).range(node).create();
        } else if (qName.getPrefixNode() != null) {
          holder.newAnnotation(HighlightSeverity.ERROR,
                               XPathBundle.message("annotator.error.extension.namespace.prefix.has.not.been.declared", qName.getPrefix()))
            .range(qName.getPrefixNode())
          .highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL).create();
        }
      }
    } else {
      final XPathExpression[] arguments = call.getArgumentList();
      for (int i = 0; i < arguments.length; i++) {
        checkArgument(holder, arguments[i], i, functionDecl.getParameters());
      }
      if (arguments.length < functionDecl.getMinArity()) {
        if (functionDecl.getMinArity() == 1) {
          holder.newAnnotation(HighlightSeverity.ERROR,
                               XPathBundle.message("annotator.error.missing.argument.for.function", name)).range(node).create();
        } else {
          final Parameter last = functionDecl.getParameters()[functionDecl.getParameters().length - 1];
          holder.newAnnotation(HighlightSeverity.ERROR,
                               XPathBundle.message("annotator.error.function.requires.choice.at.least.arguments", name,
                                                   last.kind == Parameter.Kind.OPTIONAL || last.kind == Parameter.Kind.VARARG ? 0 : 1,
                                                   functionDecl.getMinArity())).range(node).create();
        }
      }
    }
  }
private static void checkFunctionCall(AnnotationHolder holder, XPathFunctionCall call, @NotNull ContextProvider contextProvider)