2
// CreateEventInvocator.cs
5
// Mike Krüger <mkrueger@novell.com>
7
// Copyright (c) 2011 Mike Krüger <mkrueger@novell.com>
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:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
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
28
using System.Collections.Generic;
29
using ICSharpCode.NRefactory.TypeSystem;
31
namespace ICSharpCode.NRefactory.CSharp.Refactoring
33
[ContextAction("Create event invocator", Description = "Creates a standard OnXXX event method.")]
34
public class CreateEventInvocatorAction : ICodeActionProvider
37
/// If <c>true</c> an explicit type will be used for the handler variable; otherwise, 'var' will be used as type.
38
/// Default value is <c>false</c>
40
public bool UseExplictType {
45
public static MethodDeclaration CreateEventInvocator (RefactoringContext context, TypeDeclaration declaringType, EventDeclaration eventDeclaration, VariableInitializer initializer, IMethod invokeMethod, bool useExplictType)
47
bool hasSenderParam = false;
48
IEnumerable<IParameter> pars = invokeMethod.Parameters;
49
if (invokeMethod.Parameters.Any()) {
50
var first = invokeMethod.Parameters [0];
51
if (first.Name == "sender" /*&& first.Type == "System.Object"*/) {
52
hasSenderParam = true;
53
pars = invokeMethod.Parameters.Skip(1);
56
const string handlerName = "handler";
58
var arguments = new List<Expression>();
60
arguments.Add(eventDeclaration.HasModifier (Modifiers.Static) ? (Expression)new PrimitiveExpression (null) : new ThisReferenceExpression());
61
bool useThisMemberReference = false;
62
foreach (var par in pars) {
63
arguments.Add(new IdentifierExpression(par.Name));
64
useThisMemberReference |= par.Name == initializer.Name;
66
var proposedHandlerName = GetNameProposal(initializer);
67
var modifiers = eventDeclaration.HasModifier(Modifiers.Static) ? Modifiers.Static : Modifiers.Protected | Modifiers.Virtual;
68
if (declaringType.HasModifier (Modifiers.Sealed)) {
69
modifiers = Modifiers.None;
71
var methodDeclaration = new MethodDeclaration {
72
Name = proposedHandlerName,
73
ReturnType = new PrimitiveType ("void"),
74
Modifiers = modifiers,
75
Body = new BlockStatement {
76
new VariableDeclarationStatement (
77
useExplictType ? eventDeclaration.ReturnType.Clone () : new PrimitiveType ("var"), handlerName,
78
useThisMemberReference ?
79
(Expression)new MemberReferenceExpression (new ThisReferenceExpression (), initializer.Name)
80
: new IdentifierExpression (initializer.Name)
83
Condition = new BinaryOperatorExpression (new IdentifierExpression (handlerName), BinaryOperatorType.InEquality, new PrimitiveExpression (null)),
84
TrueStatement = new ExpressionStatement (new InvocationExpression (new IdentifierExpression (handlerName), arguments))
89
foreach (var par in pars) {
90
var typeName = context.CreateShortType(par.Type);
91
var decl = new ParameterDeclaration(typeName, par.Name);
92
methodDeclaration.Parameters.Add(decl);
94
return methodDeclaration;
97
static string GetNameProposal(VariableInitializer initializer)
99
return "On" + char.ToUpper(initializer.Name[0]) + initializer.Name.Substring(1);
102
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
104
VariableInitializer initializer;
105
var eventDeclaration = GetEventDeclaration(context, out initializer);
106
if (eventDeclaration == null) {
109
var type = (TypeDeclaration)eventDeclaration.Parent;
110
var proposedHandlerName = GetNameProposal(initializer);
111
if (type.Members.Any(m => m is MethodDeclaration && m.Name == proposedHandlerName)) {
114
var resolvedType = context.Resolve(eventDeclaration.ReturnType).Type;
115
if (resolvedType.Kind == TypeKind.Unknown) {
118
var invokeMethod = resolvedType.GetDelegateInvokeMethod();
119
if (invokeMethod == null) {
122
yield return new CodeAction(context.TranslateString("Create event invocator"), script => {
123
var methodDeclaration = CreateEventInvocator (context, type, eventDeclaration, initializer, invokeMethod, UseExplictType);
124
script.InsertWithCursor(
125
context.TranslateString("Create event invocator"),
126
Script.InsertPosition.After,
132
static EventDeclaration GetEventDeclaration (RefactoringContext context, out VariableInitializer initializer)
134
var result = context.GetNode<EventDeclaration> ();
135
if (result == null) {
139
initializer = result.Variables.FirstOrDefault (v => v.NameToken.Contains (context.Location));
140
return initializer != null ? result : null;