Free cookie consent management tool by TermsFeed Policy Generator

source: branches/CodeEditor/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Formatter/FormattingVisitor_Statements.cs @ 11700

Last change on this file since 11700 was 11700, checked in by jkarder, 9 years ago

#2077: created branch and added first version

File size: 17.7 KB
Line 
1//
2// AstFormattingVisitor_Statements.cs
3//
4// Author:
5//       Mike KrÃŒger <mkrueger@xamarin.com>
6//
7// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
8//
9// Permission is hereby granted, free of charge, to any person obtaining a copy
10// of this software and associated documentation files (the "Software"), to deal
11// in the Software without restriction, including without limitation the rights
12// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13// copies of the Software, and to permit persons to whom the Software is
14// furnished to do so, subject to the following conditions:
15//
16// The above copyright notice and this permission notice shall be included in
17// all copies or substantial portions of the Software.
18//
19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25// THE SOFTWARE.
26using System;
27using System.Linq;
28using ICSharpCode.NRefactory.Editor;
29
30namespace ICSharpCode.NRefactory.CSharp
31{
32  partial class FormattingVisitor : DepthFirstAstVisitor
33  {
34    public override void VisitExpressionStatement(ExpressionStatement expressionStatement)
35    {
36      base.VisitExpressionStatement(expressionStatement);
37      FixSemicolon(expressionStatement.SemicolonToken);
38    }
39
40    void VisitBlockWithoutFixingBraces(BlockStatement blockStatement, bool indent)
41    {
42      if (indent) {
43        curIndent.Push(IndentType.Block);
44      }
45
46      VisitChildrenToFormat (blockStatement, child => {
47        if (child.Role == Roles.LBrace || child.Role == Roles.RBrace) {
48          return;
49        }
50
51        if (child is Statement) {
52          FixStatementIndentation(child.StartLocation);
53          child.AcceptVisitor(this);
54        } else if (child is Comment) {
55          child.AcceptVisitor(this);
56        } else if (child is NewLineNode) {
57          // ignore
58        } else {
59          // pre processor directives at line start, if they are there.
60          if (child.StartLocation.Column > 1)
61            FixStatementIndentation(child.StartLocation);
62        }
63      });
64
65      if (indent) {
66        curIndent.Pop ();
67      }
68    }
69
70    public override void VisitBlockStatement(BlockStatement blockStatement)
71    {
72      FixIndentation(blockStatement);
73      VisitBlockWithoutFixingBraces(blockStatement, policy.IndentBlocks);
74      FixIndentation(blockStatement.RBraceToken);
75    }
76
77    public override void VisitBreakStatement(BreakStatement breakStatement)
78    {
79      FixSemicolon(breakStatement.SemicolonToken);
80    }
81
82    public override void VisitCheckedStatement(CheckedStatement checkedStatement)
83    {
84      FixEmbeddedStatment(policy.StatementBraceStyle, checkedStatement.Body);
85    }
86
87    public override void VisitContinueStatement(ContinueStatement continueStatement)
88    {
89      FixSemicolon(continueStatement.SemicolonToken);
90    }
91
92    public override void VisitEmptyStatement(EmptyStatement emptyStatement)
93    {
94      // Empty
95    }
96
97    public override void VisitFixedStatement(FixedStatement fixedStatement)
98    {
99      FixEmbeddedStatment(policy.StatementBraceStyle, fixedStatement.EmbeddedStatement);
100    }
101
102    public override void VisitForeachStatement(ForeachStatement foreachStatement)
103    {
104      ForceSpacesBeforeRemoveNewLines(foreachStatement.LParToken, policy.SpaceBeforeForeachParentheses);
105
106      ForceSpacesAfter(foreachStatement.LParToken, policy.SpacesWithinForeachParentheses);
107      ForceSpacesBeforeRemoveNewLines(foreachStatement.RParToken, policy.SpacesWithinForeachParentheses);
108     
109      FixEmbeddedStatment(policy.StatementBraceStyle, foreachStatement.EmbeddedStatement);
110    }
111
112    void FixEmbeddedStatment(BraceStyle braceStyle, AstNode node)
113    {
114      FixEmbeddedStatment(braceStyle, null, false, node);
115    }
116
117    void FixEmbeddedStatment(BraceStyle braceStyle, CSharpTokenNode token, bool allowInLine, AstNode node, bool statementAlreadyIndented = false)
118    {
119      if (node == null)
120        return;
121      bool isBlock = node is BlockStatement;
122      FormattingChanges.TextReplaceAction beginBraceAction = null;
123      FormattingChanges.TextReplaceAction endBraceAction = null;
124      BlockStatement closeBlockToBeFixed = null;
125      if (isBlock) {
126        BlockStatement block = node as BlockStatement;
127        if (allowInLine && block.StartLocation.Line == block.EndLocation.Line && block.Statements.Count() <= 1) {
128          if (block.Statements.Count() == 1)
129            nextStatementIndent = " ";
130        } else {
131          if (!statementAlreadyIndented)
132            FixOpenBrace(braceStyle, block.LBraceToken);
133          closeBlockToBeFixed = block;
134        }
135
136        if (braceStyle == BraceStyle.NextLineShifted2)
137          curIndent.Push(IndentType.Block);
138      } else {
139        if (allowInLine && token.StartLocation.Line == node.EndLocation.Line) {
140          nextStatementIndent = " ";
141        }
142      }
143      bool pushed = false;
144
145      if (policy.IndentBlocks && !(
146        policy.AlignEmbeddedStatements && node is IfElseStatement && node.Parent is IfElseStatement ||
147        policy.AlignEmbeddedStatements && node is UsingStatement && node.Parent is UsingStatement ||
148        policy.AlignEmbeddedStatements && node is LockStatement && node.Parent is LockStatement)) {
149        curIndent.Push(IndentType.Block);
150        pushed = true;
151      }
152      if (isBlock) {
153        VisitBlockWithoutFixingBraces((BlockStatement)node, false);
154      } else {
155        if (!statementAlreadyIndented) {
156          PlaceOnNewLine(policy.EmbeddedStatementPlacement, node);
157          nextStatementIndent = null;
158        }
159        node.AcceptVisitor(this);
160      }
161      nextStatementIndent = null;
162      if (pushed)
163        curIndent.Pop();
164      if (beginBraceAction != null && endBraceAction != null) {
165        beginBraceAction.DependsOn = endBraceAction;
166        endBraceAction.DependsOn = beginBraceAction;
167      }
168
169      if (isBlock && braceStyle == BraceStyle.NextLineShifted2)
170        curIndent.Pop();
171      if (closeBlockToBeFixed != null) {
172        FixClosingBrace(braceStyle, closeBlockToBeFixed.RBraceToken);
173      }
174
175    }
176
177    public bool IsLineIsEmptyUpToEol(TextLocation startLocation)
178    {
179      return IsLineIsEmptyUpToEol(document.GetOffset(startLocation) - 1);
180    }
181
182    bool IsLineIsEmptyUpToEol(int startOffset)
183    {
184      for (int offset = startOffset - 1; offset >= 0; offset--) {
185        char ch = document.GetCharAt(offset);
186        if (ch != ' ' && ch != '\t') {
187          return NewLine.IsNewLine (ch);
188        }
189      }
190      return true;
191    }
192
193    int SearchWhitespaceStart(int startOffset)
194    {
195      if (startOffset < 0) {
196        throw new ArgumentOutOfRangeException ("startoffset", "value : " + startOffset);
197      }
198      for (int offset = startOffset - 1; offset >= 0; offset--) {
199        char ch = document.GetCharAt(offset);
200        if (!Char.IsWhiteSpace(ch)) {
201          return offset + 1;
202        }
203      }
204      return 0;
205    }
206
207    int SearchWhitespaceEnd(int startOffset)
208    {
209      if (startOffset > document.TextLength) {
210        throw new ArgumentOutOfRangeException ("startoffset", "value : " + startOffset);
211      }
212      for (int offset = startOffset + 1; offset < document.TextLength; offset++) {
213        char ch = document.GetCharAt(offset);
214        if (!Char.IsWhiteSpace(ch)) {
215          return offset + 1;
216        }
217      }
218      return document.TextLength - 1;
219    }
220
221    int SearchWhitespaceLineStart(int startOffset)
222    {
223      if (startOffset < 0) {
224        throw new ArgumentOutOfRangeException ("startoffset", "value : " + startOffset);
225      }
226      for (int offset = startOffset - 1; offset >= 0; offset--) {
227        char ch = document.GetCharAt(offset);
228        if (ch != ' ' && ch != '\t') {
229          return offset + 1;
230        }
231      }
232      return 0;
233    }
234
235    public override void VisitForStatement(ForStatement forStatement)
236    {
237      foreach (AstNode node in forStatement.Children) {
238        if (node.Role == Roles.Semicolon) {
239          if (node.GetNextSibling(NoWhitespacePredicate) is CSharpTokenNode || node.GetNextSibling(NoWhitespacePredicate) is EmptyStatement) {
240            continue;
241          }
242          ForceSpacesBefore(node, policy.SpaceBeforeForSemicolon);
243          ForceSpacesAfter(node, policy.SpaceAfterForSemicolon);
244        } else if (node.Role == Roles.LPar) {
245          ForceSpacesBeforeRemoveNewLines(node, policy.SpaceBeforeForParentheses);
246          ForceSpacesAfter(node, policy.SpacesWithinForParentheses);
247        } else if (node.Role == Roles.RPar) {
248          ForceSpacesBeforeRemoveNewLines(node, policy.SpacesWithinForParentheses);
249        } else if (node.Role == Roles.EmbeddedStatement) {
250          FixEmbeddedStatment(policy.StatementBraceStyle, node);
251        } else {
252          node.AcceptVisitor(this);
253        }
254      }
255    }
256
257    public override void VisitGotoStatement(GotoStatement gotoStatement)
258    {
259      VisitChildren(gotoStatement);
260      FixSemicolon(gotoStatement.SemicolonToken);
261    }
262
263    public override void VisitIfElseStatement(IfElseStatement ifElseStatement)
264    {
265      ForceSpacesBeforeRemoveNewLines(ifElseStatement.LParToken, policy.SpaceBeforeIfParentheses);
266      Align(ifElseStatement.LParToken, ifElseStatement.Condition, policy.SpacesWithinIfParentheses);
267      ForceSpacesBeforeRemoveNewLines(ifElseStatement.RParToken, policy.SpacesWithinIfParentheses);
268
269
270      if (!ifElseStatement.TrueStatement.IsNull) {
271        FixEmbeddedStatment(policy.StatementBraceStyle, ifElseStatement.IfToken, policy.AllowIfBlockInline, ifElseStatement.TrueStatement);
272      }
273
274      if (!ifElseStatement.FalseStatement.IsNull) {
275        var placeElseOnNewLine = policy.ElseNewLinePlacement;
276        if (!(ifElseStatement.TrueStatement is BlockStatement)) {
277          placeElseOnNewLine = NewLinePlacement.NewLine;
278        }
279        PlaceOnNewLine(placeElseOnNewLine, ifElseStatement.ElseToken);
280        if (ifElseStatement.FalseStatement is IfElseStatement) {
281          PlaceOnNewLine(policy.ElseIfNewLinePlacement, ((IfElseStatement)ifElseStatement.FalseStatement).IfToken);
282        }
283        FixEmbeddedStatment(policy.StatementBraceStyle, ifElseStatement.ElseToken, policy.AllowIfBlockInline, ifElseStatement.FalseStatement, ifElseStatement.FalseStatement is IfElseStatement);
284      }
285    }
286
287    public override void VisitLabelStatement(LabelStatement labelStatement)
288    {
289      // TODO
290      VisitChildren(labelStatement);
291    }
292
293    public override void VisitLockStatement(LockStatement lockStatement)
294    {
295      ForceSpacesBeforeRemoveNewLines(lockStatement.LParToken, policy.SpaceBeforeLockParentheses);
296
297      ForceSpacesAfter(lockStatement.LParToken, policy.SpacesWithinLockParentheses);
298      ForceSpacesBeforeRemoveNewLines(lockStatement.RParToken, policy.SpacesWithinLockParentheses);
299
300      FixEmbeddedStatment(policy.StatementBraceStyle, lockStatement.EmbeddedStatement);
301    }
302
303    public override void VisitReturnStatement(ReturnStatement returnStatement)
304    {
305      VisitChildren(returnStatement);
306      FixSemicolon(returnStatement.SemicolonToken);
307    }
308
309    public override void VisitSwitchStatement(SwitchStatement switchStatement)
310    {
311      ForceSpacesBeforeRemoveNewLines(switchStatement.LParToken, policy.SpaceBeforeSwitchParentheses);
312
313      ForceSpacesAfter(switchStatement.LParToken, policy.SpacesWithinSwitchParentheses);
314      ForceSpacesBeforeRemoveNewLines(switchStatement.RParToken, policy.SpacesWithinSwitchParentheses);
315
316      FixOpenBrace(policy.StatementBraceStyle, switchStatement.LBraceToken);
317      VisitChildren(switchStatement);
318      FixClosingBrace(policy.StatementBraceStyle, switchStatement.RBraceToken);
319    }
320
321    public override void VisitSwitchSection(SwitchSection switchSection)
322    {
323      if (policy.IndentSwitchBody) {
324        curIndent.Push(IndentType.Block);
325      }
326
327      foreach (CaseLabel label in switchSection.CaseLabels) {
328        FixStatementIndentation(label.StartLocation);
329        label.AcceptVisitor(this);
330      }
331      if (policy.IndentCaseBody) {
332        curIndent.Push(IndentType.Block);
333      }
334
335      foreach (var stmt in switchSection.Statements) {
336        if (stmt is BreakStatement && !policy.IndentBreakStatements && policy.IndentCaseBody) {
337          curIndent.Pop();
338          FixStatementIndentation(stmt.StartLocation);
339          stmt.AcceptVisitor(this);
340          curIndent.Push(IndentType.Block);
341          continue;
342        }
343        FixStatementIndentation(stmt.StartLocation);
344        stmt.AcceptVisitor(this);
345      }
346      if (policy.IndentCaseBody) {
347        curIndent.Pop ();
348      }
349
350      if (policy.IndentSwitchBody) {
351        curIndent.Pop ();
352      }
353    }
354
355    public override void VisitCaseLabel(CaseLabel caseLabel)
356    {
357      ForceSpacesBefore(caseLabel.ColonToken, false);
358    }
359
360    public override void VisitThrowStatement(ThrowStatement throwStatement)
361    {
362      VisitChildren(throwStatement);
363      FixSemicolon(throwStatement.SemicolonToken);
364    }
365
366    public override void VisitTryCatchStatement(TryCatchStatement tryCatchStatement)
367    {
368      if (!tryCatchStatement.TryBlock.IsNull) {
369        FixEmbeddedStatment(policy.StatementBraceStyle, tryCatchStatement.TryBlock);
370      }
371
372      foreach (CatchClause clause in tryCatchStatement.CatchClauses) {
373        PlaceOnNewLine(policy.CatchNewLinePlacement, clause.CatchToken);
374        if (!clause.LParToken.IsNull) {
375          ForceSpacesBeforeRemoveNewLines(clause.LParToken, policy.SpaceBeforeCatchParentheses);
376
377          ForceSpacesAfter(clause.LParToken, policy.SpacesWithinCatchParentheses);
378          ForceSpacesBeforeRemoveNewLines(clause.RParToken, policy.SpacesWithinCatchParentheses);
379        }
380        FixEmbeddedStatment(policy.StatementBraceStyle, clause.Body);
381      }
382
383      if (!tryCatchStatement.FinallyBlock.IsNull) {
384        PlaceOnNewLine(policy.FinallyNewLinePlacement, tryCatchStatement.FinallyToken);
385
386        FixEmbeddedStatment(policy.StatementBraceStyle, tryCatchStatement.FinallyBlock);
387      }
388
389    }
390
391    public override void VisitCatchClause(CatchClause catchClause)
392    {
393      // Handled in TryCatchStatement
394    }
395
396    public override void VisitUncheckedStatement(UncheckedStatement uncheckedStatement)
397    {
398      FixEmbeddedStatment(policy.StatementBraceStyle, uncheckedStatement.Body);
399    }
400
401    public override void VisitUnsafeStatement(UnsafeStatement unsafeStatement)
402    {
403      FixEmbeddedStatment(policy.StatementBraceStyle, unsafeStatement.Body);
404    }
405
406    public override void VisitUsingStatement(UsingStatement usingStatement)
407    {
408      ForceSpacesBeforeRemoveNewLines(usingStatement.LParToken, policy.SpaceBeforeUsingParentheses);
409
410      Align(usingStatement.LParToken, usingStatement.ResourceAcquisition, policy.SpacesWithinUsingParentheses);
411
412      ForceSpacesBeforeRemoveNewLines(usingStatement.RParToken, policy.SpacesWithinUsingParentheses);
413
414      FixEmbeddedStatment(policy.StatementBraceStyle, usingStatement.EmbeddedStatement);
415    }
416
417    public override void VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement)
418    {
419      var returnType = variableDeclarationStatement.Type;
420      returnType.AcceptVisitor(this);
421      if ((variableDeclarationStatement.Modifiers & Modifiers.Const) == Modifiers.Const) {
422        ForceSpacesAround(returnType, true);
423      } else {
424        ForceSpacesAfter(returnType, true);
425      }
426      var lastLoc = variableDeclarationStatement.StartLocation;
427      foreach (var initializer in variableDeclarationStatement.Variables) {
428        if (lastLoc.Line != initializer.StartLocation.Line) {
429          FixStatementIndentation(initializer.StartLocation);
430          lastLoc = initializer.StartLocation;
431        }
432        initializer.AcceptVisitor(this);
433      }
434
435      FormatCommas(variableDeclarationStatement, policy.SpaceBeforeLocalVariableDeclarationComma, policy.SpaceAfterLocalVariableDeclarationComma);
436      FixSemicolon(variableDeclarationStatement.SemicolonToken);
437    }
438
439    public override void VisitDoWhileStatement(DoWhileStatement doWhileStatement)
440    {
441      FixEmbeddedStatment(policy.StatementBraceStyle, doWhileStatement.EmbeddedStatement);
442      PlaceOnNewLine(doWhileStatement.EmbeddedStatement is BlockStatement ? policy.WhileNewLinePlacement : NewLinePlacement.NewLine, doWhileStatement.WhileToken);
443
444      Align(doWhileStatement.LParToken, doWhileStatement.Condition, policy.SpacesWithinWhileParentheses);
445      ForceSpacesBeforeRemoveNewLines(doWhileStatement.RParToken, policy.SpacesWithinWhileParentheses);
446    }
447
448    void Align(AstNode lPar, AstNode alignNode, bool space)
449    {
450      int extraSpaces = 0;
451      var useExtraSpaces = lPar.StartLocation.Line == alignNode.StartLocation.Line;
452      if (useExtraSpaces) {
453        extraSpaces = Math.Max(0, lPar.StartLocation.Column + (space ? 1 : 0) - curIndent.IndentString.Length);
454        curIndent.ExtraSpaces += extraSpaces;
455        ForceSpacesAfter(lPar, space);
456      } else {
457        curIndent.Push(IndentType.Continuation);
458        FixIndentation(alignNode);
459      }
460      alignNode.AcceptVisitor(this);
461
462      if (useExtraSpaces) {
463        curIndent.ExtraSpaces -= extraSpaces;
464      } else {
465        curIndent.Pop();
466      }
467
468    }
469
470    public override void VisitWhileStatement(WhileStatement whileStatement)
471    {
472      ForceSpacesBeforeRemoveNewLines(whileStatement.LParToken, policy.SpaceBeforeWhileParentheses);
473      Align(whileStatement.LParToken, whileStatement.Condition, policy.SpacesWithinWhileParentheses);
474      ForceSpacesBeforeRemoveNewLines(whileStatement.RParToken, policy.SpacesWithinWhileParentheses);
475
476      FixEmbeddedStatment(policy.StatementBraceStyle, whileStatement.EmbeddedStatement);
477    }
478
479    public override void VisitYieldBreakStatement(YieldBreakStatement yieldBreakStatement)
480    {
481      FixSemicolon(yieldBreakStatement.SemicolonToken);
482    }
483
484    public override void VisitYieldReturnStatement(YieldReturnStatement yieldStatement)
485    {
486      yieldStatement.Expression.AcceptVisitor(this);
487      FixSemicolon(yieldStatement.SemicolonToken);
488    }
489
490    public override void VisitVariableInitializer(VariableInitializer variableInitializer)
491    {
492      if (!variableInitializer.AssignToken.IsNull) {
493        ForceSpacesAround(variableInitializer.AssignToken, policy.SpaceAroundAssignment);
494      }
495      if (!variableInitializer.Initializer.IsNull) {
496        int extraSpaces = 0;
497        var useExtraSpaces = variableInitializer.AssignToken.StartLocation.Line == variableInitializer.Initializer.StartLocation.Line;
498        if (useExtraSpaces) {
499          extraSpaces = Math.Max(0, variableInitializer.AssignToken.StartLocation.Column + 1 - curIndent.IndentString.Length);
500          curIndent.ExtraSpaces += extraSpaces;
501        } else {
502          curIndent.Push(IndentType.Continuation);
503          FixIndentation(variableInitializer.Initializer);
504        }
505        variableInitializer.Initializer.AcceptVisitor(this);
506
507        if (useExtraSpaces) {
508          curIndent.ExtraSpaces -= extraSpaces;
509        } else {
510          curIndent.Pop();
511        }
512      }
513
514    }
515  }
516}
517
Note: See TracBrowser for help on using the repository browser.