/**
   * Internal helper method to find the {@link AbstractMethodDeclaration} for a given {@link
   * MethodBinding} by searching a given set of statements.
   *
   * @param methodBinding {@link MethodBinding} to find the {@link AbstractMethodDeclaration} for
   * @param originalStatements statements to search for the {@link AbstractMethodDeclaration} in
   * @return {@link AbstractMethodDeclaration} for the given {@link MethodBinding} found in the
   *     given {@link ProgramElement}s, or <code>null</code> if it could not be found
   */
  private static AbstractMethodDeclaration declarationOf(
      MethodBinding methodBinding, ProgramElement[] originalStatements) {
    if (methodBinding != null && originalStatements != null) {
      List statements = new ArrayList(originalStatements.length);
      statements.addAll(Arrays.asList(originalStatements));

      for (int i = 0; i < statements.size(); i++) {
        IProgramElement statement = (IProgramElement) statements.get(i);
        if (statement instanceof MessageSend) {
          MessageSend msgSend = (MessageSend) statement;

          // search arguments of message send
          if (msgSend.arguments != null) {
            statements.addAll(Arrays.asList(msgSend.arguments));
          }

          /* add anonymous function message send
           *
           * function() { foo = "test" }(); */
          if (msgSend.receiver instanceof IFunctionExpression) {
            statements.add(msgSend.receiver);
          }

          continue;
        } else if (statement instanceof ObjectLiteral) {
          ObjectLiteral objLit = (ObjectLiteral) statement;
          if (objLit.fields != null) {
            statements.addAll(Arrays.asList(objLit.fields));
          }
          continue;
        } else if (statement instanceof ObjectLiteralField) {
          ObjectLiteralField objLitField = (ObjectLiteralField) statement;
          if (objLitField.initializer != null
              && (objLitField.initializer instanceof ObjectLiteral
                  || objLitField.initializer instanceof FunctionExpression)) {
            statements.add(objLitField.initializer);
            continue;
          }
        }

        AbstractMethodDeclaration methodDecl =
            AbstractMethodDeclaration.findMethodDeclaration(statement);

        // check statements inside of method declarations as well
        if (methodDecl != null && methodDecl.statements != null) {
          statements.addAll(Arrays.asList(methodDecl.statements));
        }

        // check if the found method declaration is the one that is being searched for
        if (methodDecl != null
            && (methodDecl.getBinding() == methodBinding
                || methodDecl.getBinding() == methodBinding.original())) {
          return methodDecl;
        }
      }
    }
    return null;
  }