5 changed files with 130 additions and 18 deletions
			
			
		@ -0,0 +1,89 @@
				@@ -0,0 +1,89 @@
					 | 
				
			||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
 | 
				
			||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
 | 
				
			||||
 | 
				
			||||
using System; | 
				
			||||
using System.Collections.Generic; | 
				
			||||
using System.Linq; | 
				
			||||
using System.Threading; | 
				
			||||
using System.Threading.Tasks; | 
				
			||||
using ICSharpCode.NRefactory.CSharp; | 
				
			||||
using ICSharpCode.NRefactory.CSharp.Refactoring; | 
				
			||||
using ICSharpCode.NRefactory.TypeSystem; | 
				
			||||
using ICSharpCode.SharpDevelop.Refactoring; | 
				
			||||
using CSharpBinding.Parser; | 
				
			||||
 | 
				
			||||
namespace CSharpBinding.Refactoring | 
				
			||||
{ | 
				
			||||
	[ContextAction("Add range check for parameter", Description = "Adds a parameter range check.")] | 
				
			||||
	public class ParamRangeCheckContextAction : ContextAction | 
				
			||||
	{ | 
				
			||||
		public override async Task<bool> IsAvailableAsync(EditorRefactoringContext context, System.Threading.CancellationToken cancellationToken) | 
				
			||||
		{ | 
				
			||||
			SyntaxTree st = await context.GetSyntaxTreeAsync().ConfigureAwait(false); | 
				
			||||
			Identifier identifier = (Identifier) st.GetNodeAt(context.CaretLocation, node => node.Role == Roles.Identifier); | 
				
			||||
			if (identifier == null) | 
				
			||||
				return false; | 
				
			||||
			ParameterDeclaration parameterDeclaration = identifier.Parent as ParameterDeclaration; | 
				
			||||
			if (parameterDeclaration == null) | 
				
			||||
				return false; | 
				
			||||
			ICompilation compilation = await context.GetCompilationAsync().ConfigureAwait(false); | 
				
			||||
			ITypeReference typeRef = parameterDeclaration.Type.ToTypeReference(); | 
				
			||||
			if (typeRef == null) | 
				
			||||
				return false; | 
				
			||||
			IType type = typeRef.Resolve(compilation); | 
				
			||||
			if (type == null) | 
				
			||||
				return false; | 
				
			||||
			return type.HasRange(); | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		public override void Execute(EditorRefactoringContext context) | 
				
			||||
		{ | 
				
			||||
			CSharpFullParseInformation parseInformation = context.GetParseInformation() as CSharpFullParseInformation; | 
				
			||||
			if (parseInformation != null) { | 
				
			||||
				SyntaxTree st = parseInformation.SyntaxTree; | 
				
			||||
				Identifier identifier = (Identifier) st.GetNodeAt(context.CaretLocation, node => node.Role == Roles.Identifier); | 
				
			||||
				if (identifier == null) | 
				
			||||
					return; | 
				
			||||
				ParameterDeclaration parameterDeclaration = identifier.Parent as ParameterDeclaration; | 
				
			||||
				if (parameterDeclaration == null) | 
				
			||||
					return; | 
				
			||||
				 | 
				
			||||
				AstNode grandparent = identifier.Parent.Parent; | 
				
			||||
				if ((grandparent is MethodDeclaration) || (grandparent is ConstructorDeclaration)) { | 
				
			||||
					// Range check condition
 | 
				
			||||
					var rangeCheck = new IfElseStatement( | 
				
			||||
						new BinaryOperatorExpression( | 
				
			||||
							new BinaryOperatorExpression(new IdentifierExpression(identifier.Name), BinaryOperatorType.LessThan, new IdentifierExpression("lower")), | 
				
			||||
							BinaryOperatorType.ConditionalOr, | 
				
			||||
							new BinaryOperatorExpression(new IdentifierExpression(identifier.Name), BinaryOperatorType.GreaterThan, new IdentifierExpression("upper")) | 
				
			||||
						), | 
				
			||||
						new ThrowStatement( | 
				
			||||
							new ObjectCreateExpression( | 
				
			||||
								new SimpleType("ArgumentOutOfRangeException"), | 
				
			||||
								new List<Expression>() { new PrimitiveExpression(identifier.Name, '"' + identifier.Name + '"'), new IdentifierExpression(identifier.Name), new BinaryOperatorExpression(new PrimitiveExpression("Value must be between "), BinaryOperatorType.Add, new BinaryOperatorExpression(new IdentifierExpression("lower"), BinaryOperatorType.Add, new BinaryOperatorExpression(new PrimitiveExpression(" and "), BinaryOperatorType.Add, new IdentifierExpression("upper")))) } | 
				
			||||
							) | 
				
			||||
						) | 
				
			||||
					); | 
				
			||||
					 | 
				
			||||
					// Add range check as first statement in method's/constructor's body
 | 
				
			||||
					var refactoringContext = SDRefactoringContext.Create(context.Editor, CancellationToken.None); | 
				
			||||
					using (Script script = refactoringContext.StartScript()) { | 
				
			||||
						if (grandparent is MethodDeclaration) { | 
				
			||||
							var methodDeclaration = (MethodDeclaration) grandparent; | 
				
			||||
							script.AddTo(methodDeclaration.Body, rangeCheck); | 
				
			||||
						} else if (grandparent is ConstructorDeclaration) { | 
				
			||||
							var ctorDeclaration = (ConstructorDeclaration) grandparent; | 
				
			||||
							script.AddTo(ctorDeclaration.Body, rangeCheck); | 
				
			||||
						} | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		public override string DisplayName { | 
				
			||||
			get { | 
				
			||||
				return "Add range check for parameter"; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue