private static void addCreateProposal(
     Collection<ICompletionProposal> proposals,
     boolean local,
     DefinitionGenerator dg,
     PhasedUnit unit,
     Tree.Statement statement) {
   IFile file = getFile(unit);
   TextFileChange change = new TextFileChange(local ? "Create Local" : "Create Toplevel", file);
   change.setEdit(new MultiTextEdit());
   IDocument doc = EditorUtil.getDocument(change);
   String indent = getIndent(statement, doc);
   int offset = statement.getStartIndex();
   String delim = getDefaultLineDelimiter(doc);
   Tree.CompilationUnit cu = unit.getCompilationUnit();
   int il = applyImports(change, dg.getImports(), cu, doc);
   String def = dg.generate(indent, delim) + delim + indent;
   if (!local) def += delim;
   change.addEdit(new InsertEdit(offset, def));
   String desc = (local ? "Create local " : "Create toplevel ") + dg.getDescription();
   final Scope scope = local ? statement.getScope() : cu.getUnit().getPackage();
   int exitPos = dg.getNode().getStopIndex() + 1;
   proposals.add(
       new CreateProposal(
           def,
           desc,
           scope,
           cu.getUnit(),
           dg.getReturnType(),
           dg.getImage(),
           offset + il,
           change,
           exitPos,
           dg instanceof ObjectClassDefinitionGenerator));
 }
 private List<Statement> getStatements(Tree.Body body, ITextSelection selection) {
   List<Statement> statements = new ArrayList<Statement>();
   for (Tree.Statement s : body.getStatements()) {
     if (s.getStartIndex() >= selection.getOffset()
         && s.getStopIndex() <= selection.getOffset() + selection.getLength()) {
       statements.add(s);
     }
   }
   return statements;
 }
 static void addCreateProposal(
     Collection<ICompletionProposal> proposals,
     String def,
     boolean local,
     String desc,
     Image image,
     PhasedUnit unit,
     Tree.Statement statement,
     ProducedType t) {
   IFile file = CeylonBuilder.getFile(unit);
   TextFileChange change = new TextFileChange(local ? "Create Local" : "Create Toplevel", file);
   change.setEdit(new MultiTextEdit());
   IDocument doc = CreateProposal.getDocument(change);
   String indent = CeylonQuickFixAssistant.getIndent(statement, doc);
   int offset = statement.getStartIndex();
   def = def.replace("$indent", indent);
   int il = importType(change, t, unit.getCompilationUnit());
   change.addEdit(new InsertEdit(offset, def + "\n" + indent));
   proposals.add(
       new CreateProposal(
           def,
           (local ? "Create local " : "Create toplevel ") + desc,
           image,
           0,
           offset + il,
           file,
           change));
 }
 static void addCreateParameterAndAttributeProposal(
     Collection<ICompletionProposal> proposals,
     String pdef,
     String adef,
     String desc,
     Image image,
     Declaration dec,
     PhasedUnit unit,
     Tree.Declaration decNode,
     Tree.ParameterList paramList,
     Tree.Body body,
     ProducedType t) {
   IFile file = CeylonBuilder.getFile(unit);
   TextFileChange change = new TextFileChange("Add Attribute", file);
   change.setEdit(new MultiTextEdit());
   int offset = paramList.getStopIndex();
   IDocument doc = CreateProposal.getDocument(change);
   String indent;
   String indentAfter;
   int offset2;
   List<Tree.Statement> statements = body.getStatements();
   if (statements.isEmpty()) {
     indentAfter = "\n" + CeylonQuickFixAssistant.getIndent(decNode, doc);
     indent = indentAfter + getDefaultIndent();
     offset2 = body.getStartIndex() + 1;
   } else {
     Tree.Statement statement = statements.get(statements.size() - 1);
     indent = "\n" + CeylonQuickFixAssistant.getIndent(statement, doc);
     offset2 = statement.getStopIndex() + 1;
     indentAfter = "";
   }
   int il = importType(change, t, unit.getCompilationUnit());
   change.addEdit(new InsertEdit(offset, pdef));
   change.addEdit(new InsertEdit(offset2, indent + adef + indentAfter));
   proposals.add(
       new CreateProposal(
           pdef,
           "Add " + desc + " to '" + dec.getName() + "'",
           image,
           0,
           offset + il,
           file,
           change));
 }
 @Override
 public void visit(Tree.Body that) {
   if (hasParameter && that.getScope() == declaration.getContainer()) {
     hasParameter = false;
   }
   for (Tree.Statement st : that.getStatements()) {
     if (st instanceof Tree.AttributeDeclaration) {
       Tree.AttributeDeclaration ad = (Tree.AttributeDeclaration) st;
       withinAttributeInitializer =
           ad.getDeclarationModel() == declaration
               && !(ad.getSpecifierOrInitializerExpression()
                   instanceof Tree.LazySpecifierExpression);
     } else {
       withinAttributeInitializer = false;
     }
     st.visit(this);
     withinAttributeInitializer = false;
   }
 }
 @Override
 public void visit(Tree.Statement d) {
   if (annotationConstructor != null) {
     if (!(annotationConstructor instanceof Tree.MethodDefinition && d instanceof Tree.Return)
         && d != annotationConstructor) {
       d.addError("compiler bug: annotation constructors may only contain a return statement");
     }
   }
   super.visit(d);
 }
 static void addCreateEnumProposal(
     Collection<ICompletionProposal> proposals,
     String def,
     String desc,
     Image image,
     PhasedUnit unit,
     Tree.Statement statement) {
   IFile file = CeylonBuilder.getFile(unit);
   TextFileChange change = new TextFileChange("Create Enumerated", file);
   IDocument doc = CreateProposal.getDocument(change);
   String indent = CeylonQuickFixAssistant.getIndent(statement, doc);
   String s = indent + def + "\n";
   int offset = statement.getStopIndex() + 2;
   if (offset > doc.getLength()) {
     offset = doc.getLength();
     s = "\n" + s;
   }
   // def = def.replace("$indent", indent);
   change.setEdit(new InsertEdit(offset, s));
   proposals.add(
       new CreateProposal(def, "Create enumerated " + desc, image, 0, offset, file, change));
 }
  @Override
  public void visit(Tree.Block that) {
    Scope scope = that.getScope();
    if (scope instanceof Constructor) {
      if (definitelyInitedBy.contains(delegatedConstructor)) {
        specified.definitely = true;
      }
      if (possiblyInitedBy.contains(delegatedConstructor)) {
        specified.possibly = true;
      }
      delegatedConstructor = null;
    }

    boolean oe = endsInBreakReturnThrow;
    Tree.Continue olc = lastContinue;
    Tree.Statement olcs = lastContinueStatement;
    // rather nasty way of detecting that the continue
    // occurs in another conditional branch of the
    // statement containing this block, even though we
    // did not find it in _this_ branch
    boolean continueInSomeBranchOfCurrentConditional =
        lastContinue != null && lastContinueStatement == null;
    boolean blockEndsInBreakReturnThrow = blockEndsInBreakReturnThrow(that);
    endsInBreakReturnThrow = endsInBreakReturnThrow || blockEndsInBreakReturnThrow;
    Tree.Continue last = null;
    Tree.Statement lastStatement = null;
    for (Tree.Statement st : that.getStatements()) {
      ContinueVisitor cv = new ContinueVisitor(olc);
      st.visit(cv);
      if (cv.node != null) {
        last = cv.node;
        lastStatement = st;
      }
      if (cv.found) {
        olc = null;
        olcs = null;
      }
    }
    if (blockEndsInBreakReturnThrow || continueInSomeBranchOfCurrentConditional) {
      lastContinue = last;
      lastContinueStatement = lastStatement;
    }
    super.visit(that);
    endsInBreakReturnThrow = oe;
    lastContinue = olc;
    lastContinueStatement = olcs;

    if (scope instanceof Constructor) {
      Constructor c = (Constructor) scope;
      if (specified.definitely) {
        definitelyInitedBy.add(c);
      }
      if (specified.possibly) {
        possiblyInitedBy.add(c);
      }
    }
    if (isNonPartialConstructor(scope) && declaration.getContainer() == scope.getContainer()) {
      if (!specified.definitely) {
        initedByEveryConstructor = false;
      }
    }
  }
  @Deprecated
  // replaced by RefineFormalMembersQuickFix.ceylon
  private void refineFormalMembers(IDocument document) throws ExecutionException {
    if (rootNode == null) return;
    TextChange change = new DocumentChange("Refine Members", document);
    change.setEdit(new MultiTextEdit());
    // TODO: copy/pasted from CeylonQuickFixAssistant
    Tree.Body body;
    int offset;
    if (node instanceof Tree.ClassDefinition) {
      ClassDefinition classDefinition = (Tree.ClassDefinition) node;
      body = classDefinition.getClassBody();
      offset = -1;
    } else if (node instanceof Tree.InterfaceDefinition) {
      Tree.InterfaceDefinition interfaceDefinition = (Tree.InterfaceDefinition) node;
      body = interfaceDefinition.getInterfaceBody();
      offset = -1;
    } else if (node instanceof Tree.ObjectDefinition) {
      Tree.ObjectDefinition objectDefinition = (Tree.ObjectDefinition) node;
      body = objectDefinition.getClassBody();
      offset = -1;
    } else if (node instanceof Tree.ObjectExpression) {
      Tree.ObjectExpression objectExpression = (Tree.ObjectExpression) node;
      body = objectExpression.getClassBody();
      offset = -1;
    } else if (node instanceof Tree.ClassBody || node instanceof Tree.InterfaceBody) {
      body = (Tree.Body) node;
      IEditorPart editor = getCurrentEditor();
      if (editor instanceof CeylonEditor) {
        CeylonEditor ce = (CeylonEditor) editor;
        offset = ce.getSelection().getOffset();
      } else {
        offset = -1;
      }
    } else {
      return;
    }
    if (body == null) {
      return;
    }
    boolean isInterface = body instanceof Tree.InterfaceBody;
    List<Tree.Statement> statements = body.getStatements();
    String indent;
    //        String bodyIndent = getIndent(body, document);
    String bodyIndent = utilJ2C().indents().getIndent(node, document);
    String delim = utilJ2C().indents().getDefaultLineDelimiter(document);
    if (statements.isEmpty()) {
      indent = delim + bodyIndent + utilJ2C().indents().getDefaultIndent();
      if (offset < 0) {
        offset = body.getStartIndex() + 1;
      }
    } else {
      Tree.Statement statement = statements.get(statements.size() - 1);
      indent = delim + utilJ2C().indents().getIndent(statement, document);
      if (offset < 0) {
        offset = statement.getEndIndex();
      }
    }
    StringBuilder result = new StringBuilder();
    Set<Declaration> already = new HashSet<Declaration>();
    ClassOrInterface ci = (ClassOrInterface) node.getScope();
    Unit unit = node.getUnit();
    Set<String> ambiguousNames = new HashSet<String>();
    // TODO: does not return unrefined overloaded
    //      versions of a method with one overlaad
    //      already refined
    Collection<DeclarationWithProximity> proposals =
        ci.getMatchingMemberDeclarations(unit, ci, "", 0).values();
    for (DeclarationWithProximity dwp : proposals) {
      Declaration dec = dwp.getDeclaration();
      for (Declaration d : overloads(dec)) {
        try {
          if (d.isFormal() && ci.isInheritedFromSupertype(d)) {
            appendRefinementText(isInterface, indent, result, ci, unit, d);
            importProposals().importSignatureTypes(d, rootNode, already);
            ambiguousNames.add(d.getName());
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }
    for (TypeDeclaration superType : ci.getSupertypeDeclarations()) {
      for (Declaration m : superType.getMembers()) {
        try {
          if (m.getName() != null && m.isShared()) {
            Declaration r = ci.getMember(m.getName(), null, false);
            if ((r == null || !r.refines(m) && !r.getContainer().equals(ci))
                && ambiguousNames.add(m.getName())) {
              appendRefinementText(isInterface, indent, result, ci, unit, m);
              importProposals().importSignatureTypes(m, rootNode, already);
            }
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }

    try {
      if (document.getChar(offset) == '}' && result.length() > 0) {
        result.append(delim).append(bodyIndent);
      }
    } catch (BadLocationException e) {
      e.printStackTrace();
    }
    importProposals().applyImports(change, already, rootNode, document);
    change.addEdit(new InsertEdit(offset, result.toString()));
    change.initializeValidationData(null);
    try {
      getWorkspace().run(new PerformChangeOperation(change), new NullProgressMonitor());
    } catch (CoreException ce) {
      ce.printStackTrace();
    }
  }
 static void addCreateMemberProposal(
     Collection<ICompletionProposal> proposals,
     DefinitionGenerator dg,
     Declaration typeDec,
     PhasedUnit unit,
     Tree.Declaration decNode,
     Tree.Body body,
     Tree.Statement statement) {
   IFile file = getFile(unit);
   TextFileChange change = new TextFileChange("Create Member", file);
   change.setEdit(new MultiTextEdit());
   IDocument doc = EditorUtil.getDocument(change);
   String indentBefore;
   String indentAfter;
   String indent;
   int offset;
   List<Tree.Statement> statements = body.getStatements();
   String delim = getDefaultLineDelimiter(doc);
   if (statements.isEmpty()) {
     String bodyIndent = getIndent(decNode, doc);
     indent = bodyIndent + getDefaultIndent();
     indentBefore = delim + indent;
     try {
       boolean singleLineBody =
           doc.getLineOfOffset(body.getStartIndex()) == doc.getLineOfOffset(body.getStopIndex());
       if (singleLineBody) {
         indentAfter = delim + bodyIndent;
       } else {
         indentAfter = "";
       }
     } catch (BadLocationException e) {
       e.printStackTrace();
       indentAfter = delim;
     }
     offset = body.getStartIndex() + 1;
   } else {
     Tree.Statement st;
     if (statement != null
         && statement.getUnit().equals(body.getUnit())
         && statement.getStartIndex() >= body.getStartIndex()
         && statement.getStopIndex() <= body.getStopIndex()) {
       st = statements.get(0);
       for (Tree.Statement s : statements) {
         if (statement.getStartIndex() >= s.getStartIndex()
             && statement.getStopIndex() <= s.getStopIndex()) {
           st = s;
         }
       }
       indent = getIndent(st, doc);
       indentBefore = "";
       indentAfter = delim + indent;
       offset = st.getStartIndex();
     } else {
       st = statements.get(statements.size() - 1);
       indent = getIndent(st, doc);
       indentBefore = delim + indent;
       indentAfter = "";
       offset = st.getStopIndex() + 1;
     }
   }
   String generated =
       typeDec instanceof Interface
           ? dg.generateSharedFormal(indent, delim)
           : dg.generateShared(indent, delim);
   String def = indentBefore + generated + indentAfter;
   int il = applyImports(change, dg.getImports(), unit.getCompilationUnit(), doc);
   change.addEdit(new InsertEdit(offset, def));
   String desc = "Create " + memberKind(dg) + " in '" + typeDec.getName() + "'";
   int exitPos = dg.getNode().getStopIndex() + 1;
   proposals.add(
       new CreateProposal(
           def,
           desc,
           body.getScope(),
           body.getUnit(),
           dg.getReturnType(),
           dg.getImage(),
           offset + il,
           change,
           exitPos,
           dg instanceof ObjectClassDefinitionGenerator));
 }