private static ClassOrInterface findClassContainer(Tree.CompilationUnit cu, Node node) {
   FindContainerVisitor fcv = new FindContainerVisitor(node);
   fcv.visit(cu);
   Tree.Declaration declaration = fcv.getDeclaration();
   if (declaration == null || declaration == node) return null;
   if (declaration instanceof Tree.ClassOrInterface)
     return (ClassOrInterface) declaration.getDeclarationModel();
   if (declaration instanceof Tree.MethodDefinition)
     return findClassContainer(declaration.getDeclarationModel());
   if (declaration instanceof Tree.ObjectDefinition)
     return findClassContainer(declaration.getDeclarationModel());
   return null;
 }
  private void extractStatementsInFile(TextChange tfc) throws CoreException {
    tfc.setEdit(new MultiTextEdit());
    IDocument doc = tfc.getCurrentDocument(null);

    Tree.Body body = (Tree.Body) node;

    Integer start = statements.get(0).getStartIndex();
    int length = statements.get(statements.size() - 1).getStopIndex() - start + 1;
    FindContainerVisitor fsv = new FindContainerVisitor(body);
    rootNode.visit(fsv);
    Tree.Declaration decNode = fsv.getDeclaration();
    /*if (decNode instanceof Tree.Declaration) {
        Tree.AnnotationList anns = ((Tree.Declaration) decNode).getAnnotationList();
        if (anns!=null && !anns.getAnnotations().isEmpty()) {
            decNode = anns.getAnnotations().get(0);
        }
    }*/
    Declaration dec = decNode.getDeclarationModel();
    FindLocalReferencesVisitor flrv = new FindLocalReferencesVisitor(dec);
    for (Statement s : statements) {
      s.visit(flrv);
    }
    List<TypeDeclaration> localTypes = new ArrayList<TypeDeclaration>();
    List<Tree.BaseMemberExpression> localRefs = new ArrayList<Tree.BaseMemberExpression>();
    for (Tree.BaseMemberExpression bme : flrv.getLocalReferences()) {
      if (result == null || !bme.getDeclaration().equals(result.getDeclarationModel())) {
        FindOuterReferencesVisitor v = new FindOuterReferencesVisitor(bme.getDeclaration());
        for (Statement s : body.getStatements()) {
          if (!statements.contains(s)) {
            s.visit(v);
          }
        }
        if (v.refs > 0) {
          addLocalType(dec, bme.getTypeModel(), localTypes, new ArrayList<ProducedType>());
          localRefs.add(bme);
        }
      }
    }

    String params = "";
    String args = "";
    Set<Declaration> done = new HashSet<Declaration>();
    boolean nonempty = false;
    for (Tree.BaseMemberExpression bme : localRefs) {
      if (done.add(bme.getDeclaration())) {
        params +=
            bme.getTypeModel().getProducedTypeName() + " " + bme.getIdentifier().getText() + ", ";
        args += bme.getIdentifier().getText() + ", ";
        nonempty = true;
      }
    }
    if (nonempty) {
      params = params.substring(0, params.length() - 2);
      args = args.substring(0, args.length() - 2);
    }

    String indent = "\n" + getIndent(decNode, doc);
    String extraIndent = indent + getDefaultIndent();

    String typeParams = "";
    String constraints = "";
    if (!localTypes.isEmpty()) {
      for (TypeDeclaration t : localTypes) {
        typeParams += t.getName() + ", ";
        if (!t.getSatisfiedTypes().isEmpty()) {
          constraints += extraIndent + getDefaultIndent() + "given " + t.getName() + " satisfies ";
          for (ProducedType pt : t.getSatisfiedTypes()) {
            constraints += pt.getProducedTypeName() + "&";
          }
          constraints = constraints.substring(0, constraints.length() - 1);
        }
      }
      typeParams = "<" + typeParams.substring(0, typeParams.length() - 2) + ">";
    }

    String content =
        result == null ? "void" : result.getDeclarationModel().getType().getProducedTypeName();
    content += " " + newName + typeParams + "(" + params + ")" + constraints + " {";
    for (Statement s : statements) {
      content += extraIndent + toString(s);
    }
    if (result != null) {
      content += extraIndent + "return " + result.getDeclarationModel().getName() + ";";
    }
    content += indent + "}" + indent + indent;

    String invocation = newName + "(" + args + ");";
    if (result != null) {
      String modifs;
      if (result.getDeclarationModel().isShared()) {
        modifs = "shared " + result.getDeclarationModel().getType().getProducedTypeName() + " ";
      } else {
        modifs = "value ";
      }
      invocation = modifs + result.getDeclarationModel().getName() + "=" + invocation;
    }

    tfc.addEdit(new InsertEdit(decNode.getStartIndex(), content));
    tfc.addEdit(new ReplaceEdit(start, length, invocation));
  }
  private void extractExpressionInFile(TextChange tfc) throws CoreException {
    tfc.setEdit(new MultiTextEdit());
    IDocument doc = tfc.getCurrentDocument(null);

    Tree.Term term = (Tree.Term) node;
    Integer start = term.getStartIndex();
    int length = term.getStopIndex() - start + 1;
    String exp = toString(term);
    FindContainerVisitor fsv = new FindContainerVisitor(term);
    rootNode.visit(fsv);
    Tree.Declaration decNode = fsv.getDeclaration();
    /*if (decNode instanceof Tree.Declaration) {
    	Tree.AnnotationList anns = ((Tree.Declaration) decNode).getAnnotationList();
    	if (anns!=null && !anns.getAnnotations().isEmpty()) {
    		decNode = anns.getAnnotations().get(0);
    	}
    }*/
    Declaration dec = decNode.getDeclarationModel();
    FindLocalReferencesVisitor flrv = new FindLocalReferencesVisitor(dec);
    term.visit(flrv);
    List<TypeDeclaration> localTypes = new ArrayList<TypeDeclaration>();
    for (Tree.BaseMemberExpression bme : flrv.getLocalReferences()) {
      addLocalType(dec, bme.getTypeModel(), localTypes, new ArrayList<ProducedType>());
    }

    String params = "";
    String args = "";
    if (!flrv.getLocalReferences().isEmpty()) {
      for (Tree.BaseMemberExpression bme : flrv.getLocalReferences()) {
        params +=
            bme.getTypeModel().getProducedTypeName() + " " + bme.getIdentifier().getText() + ", ";
        args += bme.getIdentifier().getText() + ", ";
      }
      params = params.substring(0, params.length() - 2);
      args = args.substring(0, args.length() - 2);
    }

    String indent = "\n" + getIndent(decNode, doc);
    String extraIndent = indent + getDefaultIndent();

    String typeParams = "";
    String constraints = "";
    if (!localTypes.isEmpty()) {
      for (TypeDeclaration t : localTypes) {
        typeParams += t.getName() + ", ";
        if (!t.getSatisfiedTypes().isEmpty()) {
          constraints += extraIndent + getDefaultIndent() + "given " + t.getName() + " satisfies ";
          for (ProducedType pt : t.getSatisfiedTypes()) {
            constraints += pt.getProducedTypeName() + "&";
          }
          constraints = constraints.substring(0, constraints.length() - 1);
        }
      }
      typeParams = "<" + typeParams.substring(0, typeParams.length() - 2) + ">";
    }

    String type;
    String ending;
    if ("Void".equals(term.getTypeModel().getProducedTypeName())) {
      type = "void";
      ending = "";
    } else {
      type =
          explicitType || dec.isToplevel() ? term.getTypeModel().getProducedTypeName() : "function";
      ending = "return ";
    }

    tfc.addEdit(
        new InsertEdit(
            decNode.getStartIndex(),
            type
                + " "
                + newName
                + typeParams
                + "("
                + params
                + ")"
                + constraints
                + " {"
                + extraIndent
                + ending
                + exp
                + ";"
                + indent
                + "}"
                + indent
                + indent));
    tfc.addEdit(new ReplaceEdit(start, length, newName + "(" + args + ")"));
  }