Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Formatter/ConstructFixer.cs @ 17800

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

#2077: created branch and added first version

File size: 16.5 KB
Line 
1//
2// ConstructFixer.cs
3//
4// Author:
5//       Mike Krüger <mkrueger@xamarin.com>
6//
7// Copyright (c) 2014 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 ICSharpCode.NRefactory.Editor;
28using System.Text;
29using System.Reflection;
30using System.Linq;
31
32namespace ICSharpCode.NRefactory.CSharp
33{
34  abstract class ConstructCompleter
35  {
36    public abstract bool TryFix (ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset);
37
38    protected AstNode GetLastNonErrorChild (AstNode node)
39    {
40      var lastNode = node.LastChild;
41
42      while (lastNode is ErrorNode) {
43        lastNode = lastNode.GetPrevNode(FormattingVisitor.NoWhitespacePredicate);
44      }
45      return lastNode;
46    }
47  }
48
49  class TypeDeclarationCompleter : ConstructCompleter
50  {
51    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
52    {
53      var typeDeclaration = syntaxTree.GetNodeAt<TypeDeclaration>(location);
54      if (typeDeclaration != null) {
55        if (typeDeclaration.LBraceToken.IsNull && typeDeclaration.RBraceToken.IsNull) {
56          if (typeDeclaration.Members.Any())
57            return false;
58          var lastNode = GetLastNonErrorChild (typeDeclaration);
59          if (lastNode == null)
60            return false;
61          var insertionOffset = document.GetOffset(lastNode.EndLocation);
62          document.Insert(insertionOffset, fixer.GenerateBody (typeDeclaration, fixer.Options.ClassBraceStyle, false, ref newOffset));
63          return true;
64        }
65      }
66      return false;
67    }
68  }
69
70  class DelegateDeclarationCompleter : ConstructCompleter
71  {
72    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
73    {
74      var typeDeclaration = syntaxTree.GetNodeAt<DelegateDeclaration>(location);
75      if (typeDeclaration != null) {
76        if (typeDeclaration.RParToken.IsNull) {
77          var lastNode = GetLastNonErrorChild (typeDeclaration);
78          if (lastNode == null)
79            return false;
80          var insertionOffset = document.GetOffset(lastNode.EndLocation);
81          document.Insert(insertionOffset, ");\n");
82          newOffset += ");\n".Length;
83          return true;
84        }
85      }
86      return false;
87    }
88  }
89
90  class MethodDeclarationCompleter : ConstructCompleter
91  {
92    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
93    {
94      var methodDeclaration = syntaxTree.GetNodeAt<MethodDeclaration>(location);
95      if (methodDeclaration != null) {
96        if (!methodDeclaration.LParToken.IsNull && methodDeclaration.RParToken.IsNull) {
97          var lastNode = GetLastNonErrorChild (methodDeclaration);
98          if (lastNode == null)
99            return false;
100
101          var insertionOffset = document.GetOffset(lastNode.EndLocation);
102          document.Insert(insertionOffset, ")\n\t{\t\t\n\t}");
103          newOffset += ")\n\t{\t\t".Length;
104          return true;
105        }
106      }
107      return false;
108    }
109  }
110
111  class IfStatementCompleter : ConstructCompleter
112  {
113    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
114    {
115      var ifStatement = syntaxTree.GetNodeAt<IfElseStatement>(location);
116      if (ifStatement != null) {
117        if (!ifStatement.LParToken.IsNull && ifStatement.RParToken.IsNull) {
118          var lastNode = GetLastNonErrorChild (ifStatement);
119          if (lastNode == null)
120            return false;
121
122          var insertionOffset = document.GetOffset(lastNode.EndLocation);
123          document.Insert(insertionOffset, fixer.GenerateBody (ifStatement, fixer.Options.StatementBraceStyle, true, ref newOffset));
124          return true;
125        }
126      }
127      return false;
128    }
129  }
130
131  class ForeachStatementCompleter : ConstructCompleter
132  {
133    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
134    {
135      var ifStatement = syntaxTree.GetNodeAt<ForeachStatement>(location);
136      if (ifStatement != null) {
137        if (!ifStatement.LParToken.IsNull && ifStatement.RParToken.IsNull) {
138          var lastNode = GetLastNonErrorChild (ifStatement);
139          if (lastNode == null)
140            return false;
141
142          var insertionOffset = document.GetOffset(lastNode.EndLocation);
143          document.Insert(insertionOffset, fixer.GenerateBody (ifStatement, fixer.Options.StatementBraceStyle, true, ref newOffset));
144          return true;
145        }
146      }
147      return false;
148    }
149  }
150
151  class WhileStatementCompleter : ConstructCompleter
152  {
153    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
154    {
155      var ifStatement = syntaxTree.GetNodeAt<WhileStatement>(location);
156      if (ifStatement != null) {
157        if (!ifStatement.LParToken.IsNull && ifStatement.RParToken.IsNull) {
158          var lastNode = GetLastNonErrorChild (ifStatement);
159          if (lastNode == null)
160            return false;
161
162          var insertionOffset = document.GetOffset(lastNode.EndLocation);
163          document.Insert(insertionOffset, fixer.GenerateBody (ifStatement, fixer.Options.StatementBraceStyle, true, ref newOffset));
164          return true;
165        }
166      }
167      return false;
168    }
169  }
170
171  class DoWhileStatementCompleter : ConstructCompleter
172  {
173    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
174    {
175      var stmt = syntaxTree.GetNodeAt<DoWhileStatement>(location);
176      if (stmt != null) {
177        if (!stmt.LParToken.IsNull && stmt.RParToken.IsNull) {
178          var lastNode = GetLastNonErrorChild (stmt);
179          if (lastNode == null)
180            return false;
181
182          var insertionOffset = document.GetOffset(lastNode.EndLocation);
183          document.Insert(insertionOffset, ");");
184          newOffset = insertionOffset + 2;
185          return true;
186        }
187      }
188      return false;
189    }
190  }
191
192  class FixedStatementCompleter : ConstructCompleter
193  {
194    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
195    {
196      var stmt = syntaxTree.GetNodeAt<FixedStatement>(location);
197      if (stmt != null) {
198        if (!stmt.LParToken.IsNull && stmt.RParToken.IsNull) {
199          var lastNode = GetLastNonErrorChild (stmt);
200          if (lastNode == null)
201            return false;
202
203          var insertionOffset = document.GetOffset(lastNode.EndLocation);
204          document.Insert(insertionOffset, fixer.GenerateBody (stmt, fixer.Options.StatementBraceStyle, true, ref newOffset));
205          return true;
206        }
207      }
208      return false;
209    }
210  }
211
212  class SwitchStatementCompleter : ConstructCompleter
213  {
214    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
215    {
216      var switchStatement = syntaxTree.GetNodeAt<SwitchStatement>(location);
217      if (switchStatement != null) {
218        if (!switchStatement.LParToken.IsNull && switchStatement.RParToken.IsNull) {
219          var lastNode = GetLastNonErrorChild (switchStatement);
220          if (lastNode == null)
221            return false;
222
223          var insertionOffset = document.GetOffset(lastNode.EndLocation);
224          document.Insert(insertionOffset, fixer.GenerateBody (switchStatement, fixer.Options.StatementBraceStyle, true, ref newOffset));
225          return true;
226        }
227      }
228      return false;
229    }
230  }
231
232  class InvocationCompleter : ConstructCompleter
233  {
234    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
235    {
236      var invocationExpression = syntaxTree.GetNodeAt<InvocationExpression>(location);
237
238      if (invocationExpression != null) {
239        if (!invocationExpression.LParToken.IsNull && invocationExpression.RParToken.IsNull) {
240          var lastNode = GetLastNonErrorChild (invocationExpression);
241          if (lastNode == null)
242            return false;
243
244          var insertionOffset = document.GetOffset(lastNode.EndLocation);
245
246          newOffset = insertionOffset;
247
248
249          var text = ")";
250          newOffset++;
251          var expressionStatement = invocationExpression.Parent as ExpressionStatement;
252          if (expressionStatement != null) {
253            if (expressionStatement.SemicolonToken.IsNull)
254              text = ");";
255            newOffset ++;
256          }
257          document.Insert(insertionOffset, text);
258
259
260          return true;
261        }
262
263      }
264      return false;
265    }
266  }
267
268  class BreakStatementCompleter : ConstructCompleter
269  {
270    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
271    {
272      var stmt = syntaxTree.GetNodeAt<BreakStatement>(location);
273
274      if (stmt != null && stmt.SemicolonToken.IsNull) {
275        // TODO !!!!
276        return true;
277      }
278      return false;
279    }
280  }
281
282  class CheckedStatementCompleter : ConstructCompleter
283  {
284    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
285    {
286      var stmt = syntaxTree.GetNodeAt<CheckedExpression>(location);
287
288      if (stmt != null && stmt.Parent is ExpressionStatement) {
289        var insertionOffset = document.GetOffset(stmt.EndLocation);
290        document.Insert(insertionOffset, fixer.GenerateBody (stmt, fixer.Options.StatementBraceStyle, false, ref newOffset));
291        return true;
292      }
293      return false;
294    }
295  }
296
297  class UncheckedStatementCompleter : ConstructCompleter
298  {
299    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
300    {
301      var stmt = syntaxTree.GetNodeAt<UncheckedExpression>(location);
302
303      if (stmt != null && stmt.Parent is ExpressionStatement) {
304        var insertionOffset = document.GetOffset(stmt.EndLocation);
305        document.Insert(insertionOffset, fixer.GenerateBody (stmt, fixer.Options.StatementBraceStyle, false, ref newOffset));
306        return true;
307      }
308      return false;
309    }
310  }
311
312  class ExpressionStatementCompleter : ConstructCompleter
313  {
314    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
315    {
316      var expressionStatement = syntaxTree.GetNodeAt<ExpressionStatement>(location);
317
318      if (expressionStatement != null) {
319        int offset = document.GetOffset(expressionStatement.Expression.EndLocation);
320        if (expressionStatement.SemicolonToken.IsNull) {
321          document.Insert(offset, ";");
322          newOffset = offset + 1;
323        }
324        return true;
325      }
326      return false;
327    }
328  }
329
330  class LockStatementCompleter : ConstructCompleter
331  {
332    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
333    {
334      var stmt = syntaxTree.GetNodeAt<LockStatement>(location);
335      if (stmt != null) {
336        if (!stmt.LParToken.IsNull && stmt.RParToken.IsNull) {
337          var lastNode = GetLastNonErrorChild (stmt);
338          if (lastNode == null)
339            return false;
340
341          var insertionOffset = document.GetOffset(lastNode.EndLocation);
342          document.Insert(insertionOffset, fixer.GenerateBody (stmt, fixer.Options.StatementBraceStyle, true, ref newOffset));
343          return true;
344        }
345      }
346      return false;
347    }
348  }
349
350  class ReturnStatementCompleter : ConstructCompleter
351  {
352    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
353    {
354      var stmt = syntaxTree.GetNodeAt<ReturnStatement>(location);
355
356      if (stmt != null && stmt.SemicolonToken.IsNull) {
357        var insertionOffset = document.GetOffset(stmt.EndLocation);
358        document.Insert(insertionOffset, ";");
359        newOffset = insertionOffset + 1;
360        return true;
361      }
362      return false;
363    }
364  }
365
366  class YieldReturnStatementCompleter : ConstructCompleter
367  {
368    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
369    {
370      var stmt = syntaxTree.GetNodeAt<YieldReturnStatement>(location);
371
372      if (stmt != null && stmt.SemicolonToken.IsNull) {
373        var insertionOffset = document.GetOffset(stmt.EndLocation);
374        document.Insert(insertionOffset, ";");
375        newOffset = insertionOffset + 1;
376        return true;
377      }
378      return false;
379    }
380  }
381
382  class ThrowStatementCompleter : ConstructCompleter
383  {
384    public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset)
385    {
386      var stmt = syntaxTree.GetNodeAt<ThrowStatement>(location);
387
388      if (stmt != null && stmt.SemicolonToken.IsNull) {
389        var insertionOffset = document.GetOffset(stmt.EndLocation);
390        document.Insert(insertionOffset, ";");
391        newOffset = insertionOffset + 1;
392        return true;
393      }
394      return false;
395    }
396  }
397
398
399  public class ConstructFixer
400  {
401    static readonly ConstructCompleter[] completer = {
402      new TypeDeclarationCompleter(),
403      new DelegateDeclarationCompleter (),
404      new MethodDeclarationCompleter (),
405      new IfStatementCompleter (),
406      new ForeachStatementCompleter (),
407      new WhileStatementCompleter (),
408      new LockStatementCompleter (),
409      new FixedStatementCompleter (),
410      new DoWhileStatementCompleter (),
411      new SwitchStatementCompleter (),
412      new BreakStatementCompleter (),
413      new ThrowStatementCompleter (),
414      new ReturnStatementCompleter (),
415      new YieldReturnStatementCompleter (),
416      new CheckedStatementCompleter (),
417      new UncheckedStatementCompleter (),
418
419      new InvocationCompleter (),
420      new ExpressionStatementCompleter ()
421    };
422
423    readonly CSharpFormattingOptions options;
424    readonly TextEditorOptions textEditorOptions;
425
426    public CSharpFormattingOptions Options {
427      get {
428        return options;
429      }
430    }
431
432    public ConstructFixer(CSharpFormattingOptions options, TextEditorOptions textEditorOptions)
433    {
434      this.options = options;
435      this.textEditorOptions = textEditorOptions;
436    }
437   
438
439    string GetIndent(AstNode node)
440    {
441      if (node == null || node is SyntaxTree)
442        return "";
443      if (node is BlockStatement || node is TypeDeclaration || node is NamespaceDeclaration)
444        return "\t" + GetIndent(node.Parent);
445      return GetIndent(node.Parent);
446    }
447
448    internal string GenerateBody(AstNode node, BraceStyle braceStyle, bool addClosingBracket, ref int newOffset)
449    {
450      StringBuilder result = new StringBuilder();
451      if (addClosingBracket)
452        result.Append(")");
453      var nodeIndent = GetIndent(node.Parent);
454      switch (braceStyle) {
455        case BraceStyle.DoNotChange:
456        case BraceStyle.BannerStyle:
457        case BraceStyle.EndOfLine:
458          result.Append(" ");
459          result.Append("{");
460          result.Append(textEditorOptions.EolMarker);
461          result.Append(nodeIndent + "\t");
462          break;
463        case BraceStyle.EndOfLineWithoutSpace:
464          result.Append("{");
465          result.Append(textEditorOptions.EolMarker);
466          result.Append(nodeIndent + "\t");
467          break;
468        case BraceStyle.NextLine:
469          result.Append(textEditorOptions.EolMarker);
470          result.Append(nodeIndent);
471          result.Append("{");
472          result.Append(textEditorOptions.EolMarker);
473          result.Append(nodeIndent + "\t");
474          break;
475        case BraceStyle.NextLineShifted:
476          result.Append(textEditorOptions.EolMarker);
477          result.Append(nodeIndent + "\t");
478          result.Append("{");
479          result.Append(textEditorOptions.EolMarker);
480          result.Append(nodeIndent + "\t");
481          break;
482        case BraceStyle.NextLineShifted2:
483          result.Append(textEditorOptions.EolMarker);
484          result.Append(nodeIndent + "\t");
485          result.Append("{");
486          result.Append(textEditorOptions.EolMarker);
487          result.Append(nodeIndent + "\t" + "\t");
488          break;
489      }
490
491      newOffset += result.Length;
492      result.Append(textEditorOptions.EolMarker);
493      result.Append(nodeIndent);
494      result.Append("}");
495
496      return result.ToString();
497    }
498
499    public bool TryFix (IDocument document, int offset, out int newOffset)
500    {
501      newOffset = offset;
502
503      var syntaxTree = SyntaxTree.Parse(document, "a.cs");
504      var location = document.GetLocation(offset - 1);
505      foreach (var c in completer) {
506        if (c.TryFix(this, syntaxTree, document, location, ref newOffset)) {
507          return true;
508        }
509      }
510      return false;
511    }
512  }
513}
514
Note: See TracBrowser for help on using the repository browser.