Browse Source
aa289c2 Fix potential NullReferenceException in OperatorIsCanBeUsedIssue. 9db72dc Fix icsharpcode/NRefactory#377 - NullReferenceException in NullAnalysisVisitor db2c7b6 Add IAstVisitor.VisitNullNode(). 95141c8 Fix ICompilation.Import(ISymbol) for namespaces in extern alias. c05dbd0 Handle errors if the XML file changes between the XmlDocumentationProvider ctor call and the GetDocumentation call. e763376 Fixed bug in FunctionNeverReturnsIssue. 168b76f Formatting options change: blank lines are now >minimum< blank lines. TODO: Add options for maximum blank lines to preserve. fde2a06 Fixed bug in 'XmlDocIssue'. 1403af7 Added 'CS1105ExtensionMethodMustBeDeclaredStaticAction'. acca096 Merge pull request icsharpcode/NRefactory#381 from mono-soc-2013/MateY-IndentEngine 505c974 Issue with preprocessor directives. 4730eca Added some indenting unit tests. 412b324 Fixed possible parser bug. 989abdd Fixed completion bug. 3582f57 Fixed bug in StaticEventSubscriptionIssue bbe2d12 Merge pull request icsharpcode/NRefactory#380 from Therzok/patch-2 43b42c5 Merge pull request icsharpcode/NRefactory#379 from Therzok/patch-1 02278d8 Fix typo in documentation f08bcdb Add StaticEventSubscription static check test 084d2de StaticEventSubscriptionIssue - Check if static b7ab0b1 Implemented StaticEventSubscriptionIssue aa291c5 Fixed construct fixer tests. dd6db96 Fixed unit test bug. 6899688 Fixed constructfixer tests on windows. 3d42715 Improved display location for 'RedundantBoolCompareIssue'. c1b8ab5 Removed IndentStateFactory. (Creating the classes direcly is a magnitude faster) e7b490e Optimized IsNewLine method. d95fdc2 Added some optimizations to the indent engine. 313235e Speed up indentation engine 540af30 Fixed indentation bug. 7db77a4 Added some more construct fix cases. Unfortunately the parser error recovery isn't good enough for implementing that feature. bd6d6f1 Added c# ConstructFixer.pull/375/head
62 changed files with 2549 additions and 514 deletions
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// CS1105ExtensionMethodMustBeDeclaredStaticAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Threading; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Extension methods must be declared static")] |
||||
public class CS1105ExtensionMethodMustBeDeclaredStaticAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var method = context.GetNode<MethodDeclaration>(); |
||||
if (method == null || !method.NameToken.Contains(context.Location)) |
||||
yield break; |
||||
|
||||
if (method.HasModifier(Modifiers.Static)) |
||||
yield break; |
||||
var param = method.Parameters.FirstOrDefault(); |
||||
if (param == null || param.ParameterModifier != ParameterModifier.This) |
||||
yield break; |
||||
yield return new CodeAction( |
||||
context.TranslateString("Convert method to static"), |
||||
script => script.ChangeModifier(method, method.Modifiers | Modifiers.Static), |
||||
method) { |
||||
Severity = ICSharpCode.NRefactory.Refactoring.Severity.Error |
||||
}; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,147 @@
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// StaticEventSubscriptionIssue.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.PatternMatching; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using ICSharpCode.NRefactory.Refactoring; |
||||
using Mono.CSharp; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[IssueDescription("Static event removal check", |
||||
Description = "Checks if static events are removed", |
||||
Category = IssueCategories.CodeQualityIssues, |
||||
Severity = Severity.Warning)] |
||||
public class StaticEventSubscriptionIssue : GatherVisitorCodeIssueProvider |
||||
{ |
||||
protected override IGatherVisitor CreateVisitor(BaseRefactoringContext context) |
||||
{ |
||||
return new GatherVisitor(context); |
||||
} |
||||
|
||||
class GatherVisitor : GatherVisitorBase<StaticEventSubscriptionIssue> |
||||
{ |
||||
public GatherVisitor (BaseRefactoringContext ctx) : base (ctx) |
||||
{ |
||||
} |
||||
|
||||
public override void VisitSyntaxTree(SyntaxTree syntaxTree) |
||||
{ |
||||
base.VisitSyntaxTree(syntaxTree); |
||||
|
||||
foreach (var assignedEvent in assignedEvents) { |
||||
addedEvents.Remove(assignedEvent); |
||||
} |
||||
|
||||
foreach (var hs in removedEvents) { |
||||
HashSet<Tuple<IMember, AssignmentExpression>> h; |
||||
if (!addedEvents.TryGetValue(hs.Key, out h)) |
||||
continue; |
||||
foreach (var evt in hs.Value) { |
||||
restart: |
||||
foreach (var m in h) { |
||||
if (m.Item1 == evt) { |
||||
h.Remove(m); |
||||
goto restart; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
foreach (var added in addedEvents) { |
||||
foreach (var usage in added.Value) { |
||||
AddIssue(new CodeIssue(usage.Item2.OperatorToken, |
||||
ctx.TranslateString("Subscription to static events without unsubscription may cause memory leaks."))); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) |
||||
{ |
||||
if (methodDeclaration.HasModifier(Modifiers.Static)) |
||||
return; |
||||
|
||||
base.VisitMethodDeclaration(methodDeclaration); |
||||
} |
||||
|
||||
public override void VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration) |
||||
{ |
||||
if (constructorDeclaration.HasModifier(Modifiers.Static)) |
||||
return; |
||||
base.VisitConstructorDeclaration(constructorDeclaration); |
||||
} |
||||
readonly Dictionary<IMember, HashSet<Tuple<IMember, AssignmentExpression>>> addedEvents = new Dictionary<IMember, HashSet<Tuple<IMember, AssignmentExpression>>>(); |
||||
readonly Dictionary<IMember, HashSet<IMember>> removedEvents = new Dictionary<IMember, HashSet<IMember>>(); |
||||
readonly HashSet<IMember> assignedEvents = new HashSet<IMember> (); |
||||
|
||||
public override void VisitAssignmentExpression(AssignmentExpression assignmentExpression) |
||||
{ |
||||
base.VisitAssignmentExpression(assignmentExpression); |
||||
|
||||
if (assignmentExpression.Operator == AssignmentOperatorType.Add) { |
||||
var left = ctx.Resolve(assignmentExpression.Left) as MemberResolveResult; |
||||
if (left == null || left.Member.SymbolKind != SymbolKind.Event || !left.Member.IsStatic) |
||||
return; |
||||
|
||||
if (assignmentExpression.Right is AnonymousMethodExpression || assignmentExpression.Right is LambdaExpression) { |
||||
AddIssue(new CodeIssue(assignmentExpression.OperatorToken, |
||||
ctx.TranslateString("Subscription to static events with an anonymous method may cause memory leaks."))); |
||||
} |
||||
|
||||
|
||||
var right = ctx.Resolve(assignmentExpression.Right) as MethodGroupResolveResult; |
||||
if (right == null || right.Methods.Count() != 1) |
||||
return; |
||||
HashSet<Tuple<IMember, AssignmentExpression>> hs; |
||||
if (!addedEvents.TryGetValue(left.Member, out hs)) |
||||
addedEvents[left.Member] = hs = new HashSet<Tuple<IMember, AssignmentExpression>>(); |
||||
hs.Add(Tuple.Create((IMember)right.Methods.First(), assignmentExpression)); |
||||
} else if (assignmentExpression.Operator == AssignmentOperatorType.Subtract) { |
||||
var left = ctx.Resolve(assignmentExpression.Left) as MemberResolveResult; |
||||
if (left == null || left.Member.SymbolKind != SymbolKind.Event || !left.Member.IsStatic) |
||||
return; |
||||
var right = ctx.Resolve(assignmentExpression.Right) as MethodGroupResolveResult; |
||||
if (right == null || right.Methods.Count() != 1) |
||||
return; |
||||
HashSet<IMember> hs; |
||||
if (!removedEvents.TryGetValue(left.Member, out hs)) |
||||
removedEvents[left.Member] = hs = new HashSet<IMember>(); |
||||
hs.Add(right.Methods.First()); |
||||
} else if (assignmentExpression.Operator == AssignmentOperatorType.Assign) { |
||||
var left = ctx.Resolve(assignmentExpression.Left) as MemberResolveResult; |
||||
if (left == null || left.Member.SymbolKind != SymbolKind.Event || !left.Member.IsStatic) |
||||
return; |
||||
assignedEvents.Add(left.Member); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,514 @@
@@ -0,0 +1,514 @@
|
||||
//
|
||||
// ConstructFixer.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.Editor; |
||||
using System.Text; |
||||
using System.Reflection; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp |
||||
{ |
||||
abstract class ConstructCompleter |
||||
{ |
||||
public abstract bool TryFix (ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset); |
||||
|
||||
protected AstNode GetLastNonErrorChild (AstNode node) |
||||
{ |
||||
var lastNode = node.LastChild; |
||||
|
||||
while (lastNode is ErrorNode) { |
||||
lastNode = lastNode.GetPrevNode(FormattingVisitor.NoWhitespacePredicate); |
||||
} |
||||
return lastNode; |
||||
} |
||||
} |
||||
|
||||
class TypeDeclarationCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var typeDeclaration = syntaxTree.GetNodeAt<TypeDeclaration>(location); |
||||
if (typeDeclaration != null) { |
||||
if (typeDeclaration.LBraceToken.IsNull && typeDeclaration.RBraceToken.IsNull) { |
||||
if (typeDeclaration.Members.Any()) |
||||
return false; |
||||
var lastNode = GetLastNonErrorChild (typeDeclaration); |
||||
if (lastNode == null) |
||||
return false; |
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (typeDeclaration, fixer.Options.ClassBraceStyle, false, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class DelegateDeclarationCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var typeDeclaration = syntaxTree.GetNodeAt<DelegateDeclaration>(location); |
||||
if (typeDeclaration != null) { |
||||
if (typeDeclaration.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (typeDeclaration); |
||||
if (lastNode == null) |
||||
return false; |
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, ");\n"); |
||||
newOffset += ");\n".Length; |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class MethodDeclarationCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var methodDeclaration = syntaxTree.GetNodeAt<MethodDeclaration>(location); |
||||
if (methodDeclaration != null) { |
||||
if (!methodDeclaration.LParToken.IsNull && methodDeclaration.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (methodDeclaration); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, ")\n\t{\t\t\n\t}"); |
||||
newOffset += ")\n\t{\t\t".Length; |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class IfStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var ifStatement = syntaxTree.GetNodeAt<IfElseStatement>(location); |
||||
if (ifStatement != null) { |
||||
if (!ifStatement.LParToken.IsNull && ifStatement.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (ifStatement); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (ifStatement, fixer.Options.StatementBraceStyle, true, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class ForeachStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var ifStatement = syntaxTree.GetNodeAt<ForeachStatement>(location); |
||||
if (ifStatement != null) { |
||||
if (!ifStatement.LParToken.IsNull && ifStatement.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (ifStatement); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (ifStatement, fixer.Options.StatementBraceStyle, true, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class WhileStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var ifStatement = syntaxTree.GetNodeAt<WhileStatement>(location); |
||||
if (ifStatement != null) { |
||||
if (!ifStatement.LParToken.IsNull && ifStatement.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (ifStatement); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (ifStatement, fixer.Options.StatementBraceStyle, true, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class DoWhileStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<DoWhileStatement>(location); |
||||
if (stmt != null) { |
||||
if (!stmt.LParToken.IsNull && stmt.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (stmt); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, ");"); |
||||
newOffset = insertionOffset + 2; |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class FixedStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<FixedStatement>(location); |
||||
if (stmt != null) { |
||||
if (!stmt.LParToken.IsNull && stmt.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (stmt); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (stmt, fixer.Options.StatementBraceStyle, true, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class SwitchStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var switchStatement = syntaxTree.GetNodeAt<SwitchStatement>(location); |
||||
if (switchStatement != null) { |
||||
if (!switchStatement.LParToken.IsNull && switchStatement.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (switchStatement); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (switchStatement, fixer.Options.StatementBraceStyle, true, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class InvocationCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var invocationExpression = syntaxTree.GetNodeAt<InvocationExpression>(location); |
||||
|
||||
if (invocationExpression != null) { |
||||
if (!invocationExpression.LParToken.IsNull && invocationExpression.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (invocationExpression); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
|
||||
newOffset = insertionOffset; |
||||
|
||||
|
||||
var text = ")"; |
||||
newOffset++; |
||||
var expressionStatement = invocationExpression.Parent as ExpressionStatement; |
||||
if (expressionStatement != null) { |
||||
if (expressionStatement.SemicolonToken.IsNull) |
||||
text = ");"; |
||||
newOffset ++; |
||||
} |
||||
document.Insert(insertionOffset, text); |
||||
|
||||
|
||||
return true; |
||||
} |
||||
|
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class BreakStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<BreakStatement>(location); |
||||
|
||||
if (stmt != null && stmt.SemicolonToken.IsNull) { |
||||
// TODO !!!!
|
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class CheckedStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<CheckedExpression>(location); |
||||
|
||||
if (stmt != null && stmt.Parent is ExpressionStatement) { |
||||
var insertionOffset = document.GetOffset(stmt.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (stmt, fixer.Options.StatementBraceStyle, false, ref newOffset)); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class UncheckedStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<UncheckedExpression>(location); |
||||
|
||||
if (stmt != null && stmt.Parent is ExpressionStatement) { |
||||
var insertionOffset = document.GetOffset(stmt.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (stmt, fixer.Options.StatementBraceStyle, false, ref newOffset)); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class ExpressionStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var expressionStatement = syntaxTree.GetNodeAt<ExpressionStatement>(location); |
||||
|
||||
if (expressionStatement != null) { |
||||
int offset = document.GetOffset(expressionStatement.Expression.EndLocation); |
||||
if (expressionStatement.SemicolonToken.IsNull) { |
||||
document.Insert(offset, ";"); |
||||
newOffset = offset + 1; |
||||
} |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class LockStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<LockStatement>(location); |
||||
if (stmt != null) { |
||||
if (!stmt.LParToken.IsNull && stmt.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (stmt); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (stmt, fixer.Options.StatementBraceStyle, true, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class ReturnStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<ReturnStatement>(location); |
||||
|
||||
if (stmt != null && stmt.SemicolonToken.IsNull) { |
||||
var insertionOffset = document.GetOffset(stmt.EndLocation); |
||||
document.Insert(insertionOffset, ";"); |
||||
newOffset = insertionOffset + 1; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class YieldReturnStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<YieldReturnStatement>(location); |
||||
|
||||
if (stmt != null && stmt.SemicolonToken.IsNull) { |
||||
var insertionOffset = document.GetOffset(stmt.EndLocation); |
||||
document.Insert(insertionOffset, ";"); |
||||
newOffset = insertionOffset + 1; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class ThrowStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<ThrowStatement>(location); |
||||
|
||||
if (stmt != null && stmt.SemicolonToken.IsNull) { |
||||
var insertionOffset = document.GetOffset(stmt.EndLocation); |
||||
document.Insert(insertionOffset, ";"); |
||||
newOffset = insertionOffset + 1; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
|
||||
public class ConstructFixer |
||||
{ |
||||
static readonly ConstructCompleter[] completer = { |
||||
new TypeDeclarationCompleter(), |
||||
new DelegateDeclarationCompleter (), |
||||
new MethodDeclarationCompleter (), |
||||
new IfStatementCompleter (), |
||||
new ForeachStatementCompleter (), |
||||
new WhileStatementCompleter (), |
||||
new LockStatementCompleter (), |
||||
new FixedStatementCompleter (), |
||||
new DoWhileStatementCompleter (), |
||||
new SwitchStatementCompleter (), |
||||
new BreakStatementCompleter (), |
||||
new ThrowStatementCompleter (), |
||||
new ReturnStatementCompleter (), |
||||
new YieldReturnStatementCompleter (), |
||||
new CheckedStatementCompleter (), |
||||
new UncheckedStatementCompleter (), |
||||
|
||||
new InvocationCompleter (), |
||||
new ExpressionStatementCompleter () |
||||
}; |
||||
|
||||
readonly CSharpFormattingOptions options; |
||||
readonly TextEditorOptions textEditorOptions; |
||||
|
||||
public CSharpFormattingOptions Options { |
||||
get { |
||||
return options; |
||||
} |
||||
} |
||||
|
||||
public ConstructFixer(CSharpFormattingOptions options, TextEditorOptions textEditorOptions) |
||||
{ |
||||
this.options = options; |
||||
this.textEditorOptions = textEditorOptions; |
||||
} |
||||
|
||||
|
||||
string GetIndent(AstNode node) |
||||
{ |
||||
if (node == null || node is SyntaxTree) |
||||
return ""; |
||||
if (node is BlockStatement || node is TypeDeclaration || node is NamespaceDeclaration) |
||||
return "\t" + GetIndent(node.Parent); |
||||
return GetIndent(node.Parent); |
||||
} |
||||
|
||||
internal string GenerateBody(AstNode node, BraceStyle braceStyle, bool addClosingBracket, ref int newOffset) |
||||
{ |
||||
StringBuilder result = new StringBuilder(); |
||||
if (addClosingBracket) |
||||
result.Append(")"); |
||||
var nodeIndent = GetIndent(node.Parent); |
||||
switch (braceStyle) { |
||||
case BraceStyle.DoNotChange: |
||||
case BraceStyle.BannerStyle: |
||||
case BraceStyle.EndOfLine: |
||||
result.Append(" "); |
||||
result.Append("{"); |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t"); |
||||
break; |
||||
case BraceStyle.EndOfLineWithoutSpace: |
||||
result.Append("{"); |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t"); |
||||
break; |
||||
case BraceStyle.NextLine: |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent); |
||||
result.Append("{"); |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t"); |
||||
break; |
||||
case BraceStyle.NextLineShifted: |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t"); |
||||
result.Append("{"); |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t"); |
||||
break; |
||||
case BraceStyle.NextLineShifted2: |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t"); |
||||
result.Append("{"); |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t" + "\t"); |
||||
break; |
||||
} |
||||
|
||||
newOffset += result.Length; |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent); |
||||
result.Append("}"); |
||||
|
||||
return result.ToString(); |
||||
} |
||||
|
||||
public bool TryFix (IDocument document, int offset, out int newOffset) |
||||
{ |
||||
newOffset = offset; |
||||
|
||||
var syntaxTree = SyntaxTree.Parse(document, "a.cs"); |
||||
var location = document.GetLocation(offset - 1); |
||||
foreach (var c in completer) { |
||||
if (c.TryFix(this, syntaxTree, document, location, ref newOffset)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,201 @@
@@ -0,0 +1,201 @@
|
||||
//
|
||||
// CloneableStack.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Collections; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp |
||||
{ |
||||
class CloneableStack<T> : IEnumerable<T>, ICollection<T>, ICloneable, IEquatable<CloneableStack<T>> |
||||
{ |
||||
int count; |
||||
StackItem top; |
||||
|
||||
#region IEnumerable[T] implementation
|
||||
public IEnumerator<T> GetEnumerator () |
||||
{ |
||||
return new StackItemEnumerator (top); |
||||
} |
||||
|
||||
IEnumerator IEnumerable.GetEnumerator () |
||||
{ |
||||
return new StackItemEnumerator (top); |
||||
} |
||||
#endregion
|
||||
|
||||
#region ICloneable implementation
|
||||
public CloneableStack<T> Clone () |
||||
{ |
||||
CloneableStack<T> result = new CloneableStack<T> (); |
||||
result.count = count; |
||||
result.top = top; |
||||
return result; |
||||
} |
||||
|
||||
object ICloneable.Clone () |
||||
{ |
||||
return Clone(); |
||||
} |
||||
#endregion
|
||||
|
||||
public void Clear () |
||||
{ |
||||
top = null; |
||||
count = 0; |
||||
} |
||||
|
||||
public void Push (T item) |
||||
{ |
||||
top = new StackItem (top, item); |
||||
count++; |
||||
} |
||||
|
||||
public T Peek () |
||||
{ |
||||
return top.Item; |
||||
} |
||||
|
||||
public T Pop () |
||||
{ |
||||
T result = top.Item; |
||||
top = top.Parent; |
||||
count--; |
||||
return result; |
||||
} |
||||
|
||||
#region IEquatable[T] implementation
|
||||
public bool Equals (CloneableStack<T> other) |
||||
{ |
||||
return ReferenceEquals (top, other.top); |
||||
} |
||||
#endregion
|
||||
|
||||
#region ICollection[T] implementation
|
||||
void ICollection<T>.Add (T item) |
||||
{ |
||||
Push (item); |
||||
} |
||||
|
||||
void ICollection<T>.Clear () |
||||
{ |
||||
top = null; |
||||
count = 0; |
||||
} |
||||
|
||||
bool ICollection<T>.Contains (T item) |
||||
{ |
||||
foreach (T t in this) { |
||||
if (t.Equals (item)) |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
void ICollection<T>.CopyTo (T[] array, int arrayIndex) |
||||
{ |
||||
int idx = arrayIndex; |
||||
foreach (T t in this) { |
||||
array[idx++] = t; |
||||
} |
||||
} |
||||
|
||||
bool ICollection<T>.Remove (T item) |
||||
{ |
||||
throw new NotImplementedException (); |
||||
} |
||||
|
||||
public int Count { |
||||
get { |
||||
return count; |
||||
} |
||||
} |
||||
|
||||
bool ICollection<T>.IsReadOnly { |
||||
get { |
||||
return false; |
||||
} |
||||
} |
||||
#endregion
|
||||
|
||||
class StackItem |
||||
{ |
||||
public readonly StackItem Parent; |
||||
public readonly T Item; |
||||
|
||||
public StackItem (StackItem parent, T item) |
||||
{ |
||||
Parent = parent; |
||||
Item = item; |
||||
} |
||||
} |
||||
|
||||
class StackItemEnumerator : IEnumerator<T> |
||||
{ |
||||
StackItem cur, first; |
||||
|
||||
public StackItemEnumerator (StackItem cur) |
||||
{ |
||||
this.cur = first = new StackItem (cur, default(T)); |
||||
} |
||||
|
||||
#region IDisposable implementation
|
||||
void IDisposable.Dispose () |
||||
{ |
||||
cur = first = null; |
||||
} |
||||
#endregion
|
||||
|
||||
#region IEnumerator implementation
|
||||
bool IEnumerator.MoveNext () |
||||
{ |
||||
if (cur == null) |
||||
return false; |
||||
cur = cur.Parent; |
||||
return cur != null; |
||||
} |
||||
|
||||
void IEnumerator.Reset () |
||||
{ |
||||
cur = first; |
||||
} |
||||
|
||||
object IEnumerator.Current { |
||||
get { |
||||
return cur.Item; |
||||
} |
||||
} |
||||
#endregion
|
||||
|
||||
#region IEnumerator[T] implementation
|
||||
T IEnumerator<T>.Current { |
||||
get { |
||||
return cur.Item; |
||||
} |
||||
} |
||||
#endregion
|
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// CS1105ExtensionMethodMustBeDeclaredStaticActionTests.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using NUnit.Framework; |
||||
using ICSharpCode.NRefactory.CSharp.Refactoring; |
||||
using ICSharpCode.NRefactory.CSharp.CodeActions; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.CodeIssues |
||||
{ |
||||
[TestFixture] |
||||
public class CS1105ExtensionMethodMustBeDeclaredStaticActionTests : ContextActionTestBase |
||||
{ |
||||
[Test] |
||||
public void TestMethod() |
||||
{ |
||||
Test<CS1105ExtensionMethodMustBeDeclaredStaticAction> ( |
||||
@"static class Foo
|
||||
{ |
||||
public void $FooBar (this string foo) |
||||
{ |
||||
|
||||
} |
||||
}",
|
||||
@"static class Foo
|
||||
{ |
||||
public static void FooBar (this string foo) |
||||
{ |
||||
|
||||
} |
||||
}", 0, true);
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestWrongContext1() |
||||
{ |
||||
TestWrongContext<CS1105ExtensionMethodMustBeDeclaredStaticAction> ( |
||||
@"static class Foo
|
||||
{ |
||||
public static void $FooBar (this string foo) |
||||
{ |
||||
|
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestWrongContext2() |
||||
{ |
||||
TestWrongContext<CS1105ExtensionMethodMustBeDeclaredStaticAction> ( |
||||
@"class Foo
|
||||
{ |
||||
public void $FooBar (string foo) |
||||
{ |
||||
|
||||
} |
||||
}");
|
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,173 @@
@@ -0,0 +1,173 @@
|
||||
//
|
||||
// StaticEventSubscriptionIssueTests.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.CSharp.CodeActions; |
||||
using ICSharpCode.NRefactory.CSharp.Refactoring; |
||||
using NUnit.Framework; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.CodeIssues |
||||
{ |
||||
[TestFixture] |
||||
public class StaticEventSubscriptionIssueTests: InspectionActionTestBase |
||||
{ |
||||
[Test] |
||||
public void TestAnonymousMethodSubscription() |
||||
{ |
||||
TestIssue<StaticEventSubscriptionIssue>(@"
|
||||
using System; |
||||
|
||||
class Foo |
||||
{ |
||||
public static event EventHandler FooBar; |
||||
|
||||
public void Test () |
||||
{ |
||||
FooBar += delegate { |
||||
Console.WriteLine (""Hello World!""); |
||||
}; |
||||
} |
||||
} |
||||
");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestAnonymousMethodSubscription_ValidCase() |
||||
{ |
||||
TestWrongContext<StaticEventSubscriptionIssue>(@"
|
||||
using System; |
||||
|
||||
class Foo |
||||
{ |
||||
public static event EventHandler FooBar; |
||||
|
||||
public static void Test () |
||||
{ |
||||
FooBar += delegate { |
||||
Console.WriteLine (""Hello World!""); |
||||
}; |
||||
} |
||||
} |
||||
");
|
||||
} |
||||
|
||||
|
||||
[Test] |
||||
public void TestIssue() |
||||
{ |
||||
TestIssue<StaticEventSubscriptionIssue>(@"
|
||||
using System; |
||||
|
||||
class Foo |
||||
{ |
||||
public static event EventHandler FooBar; |
||||
|
||||
public void Test () |
||||
{ |
||||
FooBar += MyMethod; |
||||
} |
||||
void MyMethod (object sender, EventArgs args) |
||||
{ |
||||
} |
||||
} |
||||
");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestNoIssue() |
||||
{ |
||||
TestWrongContext<StaticEventSubscriptionIssue>(@"
|
||||
using System; |
||||
|
||||
class Foo |
||||
{ |
||||
public static event EventHandler FooBar; |
||||
|
||||
public void Test () |
||||
{ |
||||
FooBar += MyMethod; |
||||
} |
||||
|
||||
public void Unsubscribe () |
||||
{ |
||||
FooBar -= MyMethod; |
||||
} |
||||
void MyMethod (object sender, EventArgs args) |
||||
{ |
||||
} |
||||
} |
||||
");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestNonStatic() |
||||
{ |
||||
TestWrongContext<StaticEventSubscriptionIssue>(@"
|
||||
using System; |
||||
|
||||
class Foo |
||||
{ |
||||
public event EventHandler FooBar; |
||||
|
||||
public void Test () |
||||
{ |
||||
FooBar += MyMethod; |
||||
} |
||||
|
||||
void MyMethod (object sender, EventArgs args) |
||||
{ |
||||
} |
||||
} |
||||
");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestNullAssignment() |
||||
{ |
||||
TestWrongContext<StaticEventSubscriptionIssue>(@"
|
||||
using System; |
||||
|
||||
class Foo |
||||
{ |
||||
public static event EventHandler FooBar; |
||||
|
||||
public void Test () |
||||
{ |
||||
FooBar += MyMethod; |
||||
} |
||||
|
||||
public void Unsubscribe () |
||||
{ |
||||
FooBar = null; |
||||
} |
||||
void MyMethod (object sender, EventArgs args) |
||||
{ |
||||
} |
||||
} |
||||
");
|
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,665 @@
@@ -0,0 +1,665 @@
|
||||
//
|
||||
// ConstructFixerTests.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
using NUnit.Framework; |
||||
using ICSharpCode.NRefactory.CSharp; |
||||
using ICSharpCode.NRefactory.Editor; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.FormattingTests |
||||
{ |
||||
[TestFixture] |
||||
public class ConstructFixerTests |
||||
{ |
||||
static void Test (string input, string expectedOutput) |
||||
{ |
||||
input = input.Replace("\r\n", "\n"); |
||||
expectedOutput = expectedOutput.Replace("\r\n", "\n"); |
||||
int caretPositon = input.IndexOf('$'); |
||||
if (caretPositon > 0) |
||||
input = input.Substring(0, caretPositon) + input.Substring(caretPositon + 1); |
||||
|
||||
var document1 = new StringBuilderDocument(input); |
||||
|
||||
int expectedCaretPosition = expectedOutput.IndexOf('$'); |
||||
if (expectedCaretPosition > 0) |
||||
expectedOutput = expectedOutput.Substring(0, expectedCaretPosition) + expectedOutput.Substring(expectedCaretPosition + 1); |
||||
|
||||
var fixer = new ConstructFixer(FormattingOptionsFactory.CreateMono (), new TextEditorOptions { EolMarker = "\n" }); |
||||
int newCaretPosition; |
||||
Assert.IsTrue(fixer.TryFix(document1, caretPositon, out newCaretPosition)); |
||||
var isEqual = expectedOutput == document1.Text.Replace("\r\n", "\n"); |
||||
if (!isEqual) { |
||||
System.Console.WriteLine("expected:"); |
||||
System.Console.WriteLine(expectedOutput); |
||||
System.Console.WriteLine("was:"); |
||||
System.Console.WriteLine(document1.Text); |
||||
} |
||||
Assert.IsTrue(isEqual); |
||||
Assert.AreEqual(expectedCaretPosition, newCaretPosition); |
||||
} |
||||
|
||||
[Test] |
||||
public void TestMethodCallCase1() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar (int i) |
||||
{ |
||||
Bar (42$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar (int i) |
||||
{ |
||||
Bar (42);$ |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestMethodCallCase2() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
Bar$ (; |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
Bar ();$ |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestMethodCallCase3() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
Bar ($) |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
Bar ();$ |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestClassDeclaration() |
||||
{ |
||||
Test(@"class Foo$", @"class Foo
|
||||
{ |
||||
$ |
||||
}");
|
||||
} |
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestClassDeclaration_TestErrorRecovery() |
||||
{ |
||||
Test(@"class Foo$
|
||||
// Foo
|
||||
", @"class Foo |
||||
{ |
||||
$ |
||||
} |
||||
|
||||
// Foo");
|
||||
} |
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestDelegateDeclaration() |
||||
{ |
||||
Test( |
||||
@"delegate void FooHandler (object foo$", |
||||
@"delegate void FooHandler (object foo);
|
||||
$");
|
||||
} |
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestMethodDeclaration() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar (int i$ |
||||
} |
||||
", @" |
||||
class Foo |
||||
{ |
||||
void Bar (int i) |
||||
{ |
||||
$ |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestFieldDeclaration() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
int f$ |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
inf f; |
||||
}");
|
||||
} |
||||
|
||||
|
||||
[Test] |
||||
public void TestIfStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar (int i) |
||||
{ |
||||
if (true$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar (int i) |
||||
{ |
||||
if (true) { |
||||
$ |
||||
} |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestFixedStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
unsafe class Foo |
||||
{ |
||||
void Bar (int i) |
||||
{ |
||||
fixed (int* ptr = &i$ |
||||
} |
||||
}", @" |
||||
unsafe class Foo |
||||
{ |
||||
void Bar (int i) |
||||
{ |
||||
fixed (int* ptr = &i) { |
||||
$ |
||||
} |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestUsingStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
using (var foo = new Foo()$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
using (var foo = new Foo()) { |
||||
$ |
||||
} |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestLockStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
lock (foo$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
lock (foo) { |
||||
$ |
||||
} |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestForeachStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar (string s) |
||||
{ |
||||
foreach (var c in s$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar (string s) |
||||
{ |
||||
foreach (var c in s) { |
||||
$ |
||||
} |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestWhileStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
while (true$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
while (true) { |
||||
$ |
||||
} |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
|
||||
[Test] |
||||
public void TestSwitch() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar (int i) |
||||
{ |
||||
switch (i$ |
||||
} |
||||
} |
||||
", @" |
||||
class Foo |
||||
{ |
||||
void Bar (int i) |
||||
{ |
||||
switch (i) { |
||||
$ |
||||
} |
||||
} |
||||
} |
||||
");
|
||||
} |
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestCase() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar (int i) |
||||
{ |
||||
switch (i) { |
||||
case 1$ |
||||
} |
||||
} |
||||
} |
||||
", @" |
||||
class Foo |
||||
{ |
||||
void Bar (int i) |
||||
{ |
||||
switch (i) { |
||||
case 1: |
||||
$ |
||||
} |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestBreakStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
break$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
break; |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestGotoStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
goto foo$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
goto foo; |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestReturnStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
int Bar () |
||||
{ |
||||
return 5$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
int Bar () |
||||
{ |
||||
return 5;$ |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestYieldBreakStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
int Bar () |
||||
{ |
||||
yield break$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
int Bar () |
||||
{ |
||||
yield break;$ |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestYieldReturnStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
int Bar () |
||||
{ |
||||
yield return 5$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
int Bar () |
||||
{ |
||||
yield return 5;$ |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestThrowStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
int Bar () |
||||
{ |
||||
throw new Exception()$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
int Bar () |
||||
{ |
||||
throw new Exception();$ |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
|
||||
[Test] |
||||
public void TestCheckedStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
checked$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
checked { |
||||
$ |
||||
} |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Test] |
||||
public void TestUncheckedStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
unchecked$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
unchecked { |
||||
$ |
||||
} |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestUnsafeStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
unsafe$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
unsafe { |
||||
$ |
||||
} |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestContinueStatement() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
continue$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
continue; |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
|
||||
[Test] |
||||
public void TestDoWhile() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
do { |
||||
} while (true$ |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
void Bar () |
||||
{ |
||||
do { |
||||
} while (true);$ |
||||
} |
||||
}");
|
||||
} |
||||
|
||||
[Ignore("Fixme - parser error")] |
||||
[Test] |
||||
public void TestComplexCase() |
||||
{ |
||||
Test( |
||||
@"
|
||||
class Foo |
||||
{ |
||||
bool Bar (int i) |
||||
{ |
||||
if$ (Bar (1 |
||||
} |
||||
}", @" |
||||
class Foo |
||||
{ |
||||
bool Bar (int i) |
||||
{ |
||||
if (Bar ((((Bar((1))))))) { |
||||
$ |
||||
} |
||||
} |
||||
}");
|
||||
} |
||||
} |
||||
} |
||||
|
||||
Loading…
Reference in new issue