~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to contrib/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
ļ»æ// 
2
 
// CreateField.cs
3
 
//  
4
 
// Author:
5
 
//       Mike KrĆ¼ger <mkrueger@novell.com>
6
 
// 
7
 
// Copyright (c) 2011 Novell, Inc (http://www.novell.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.
26
 
 
27
 
using System;
28
 
using ICSharpCode.NRefactory.PatternMatching;
29
 
using System.Linq;
30
 
using ICSharpCode.NRefactory.TypeSystem;
31
 
using System.Threading;
32
 
using System.Collections.Generic;
33
 
using ICSharpCode.NRefactory.CSharp.Resolver;
34
 
using ICSharpCode.NRefactory.Semantics;
35
 
 
36
 
namespace ICSharpCode.NRefactory.CSharp.Refactoring
37
 
{
38
 
        [ContextAction("Create field", Description = "Creates a field for a undefined variable.")]
39
 
        public class CreateFieldAction : ICodeActionProvider
40
 
        {
41
 
                internal static bool IsInvocationTarget(AstNode node)
42
 
                {
43
 
                        var invoke = node.Parent as InvocationExpression;
44
 
                        return invoke != null && invoke.Target == node;
45
 
                }
46
 
 
47
 
                public IEnumerable<CodeAction> GetActions(RefactoringContext context)
48
 
                {
49
 
                        var identifier = context.GetNode<IdentifierExpression>();
50
 
                        if (identifier == null)
51
 
                                yield break;
52
 
                        if (IsInvocationTarget(identifier))
53
 
                                yield break;
54
 
                        var statement = identifier.GetParent<Statement>();
55
 
                        if (statement == null)
56
 
                                yield break;
57
 
                        if (!(context.Resolve(identifier).IsError))
58
 
                                yield break;
59
 
                        var guessedType = CreateFieldAction.GuessAstType(context, identifier);
60
 
                        if (guessedType == null)
61
 
                                yield break;
62
 
                        var state = context.GetResolverStateBefore(identifier);
63
 
                        if (state.CurrentMember == null || state.CurrentTypeDefinition == null)
64
 
                                yield break;
65
 
 
66
 
                        bool isStatic = state.CurrentMember.IsStatic | state.CurrentTypeDefinition.IsStatic;
67
 
 
68
 
//                      var service = (NamingConventionService)context.GetService(typeof(NamingConventionService));
69
 
//                      if (service != null && !service.IsValidName(identifier.Identifier, AffectedEntity.Field, Modifiers.Private, isStatic)) { 
70
 
//                              yield break;
71
 
//                      }
72
 
 
73
 
                        yield return new CodeAction(context.TranslateString("Create field"), script => {
74
 
                                var decl = new FieldDeclaration() {
75
 
                                        ReturnType = guessedType,
76
 
                                        Variables = { new VariableInitializer(identifier.Identifier) }
77
 
                                };
78
 
                                if (isStatic)
79
 
                                        decl.Modifiers |= Modifiers.Static;
80
 
                                script.InsertWithCursor(context.TranslateString("Create field"), Script.InsertPosition.Before, decl);
81
 
                        });
82
 
 
83
 
                }
84
 
 
85
 
                #region Type guessing
86
 
                static int GetArgumentIndex(IEnumerable<Expression> arguments, AstNode parameter)
87
 
                {
88
 
                        int argumentNumber = 0;
89
 
                        foreach (var arg in arguments) {
90
 
                                if (arg == parameter) {
91
 
                                        return argumentNumber;
92
 
                                }
93
 
                                argumentNumber++;
94
 
                        }
95
 
                        return -1;
96
 
                }
97
 
 
98
 
                static IEnumerable<IType> GetAllValidTypesFromInvokation(CSharpAstResolver resolver, InvocationExpression invoke, AstNode parameter)
99
 
                {
100
 
                        int index = GetArgumentIndex(invoke.Arguments, parameter);
101
 
                        if (index < 0)
102
 
                                yield break;
103
 
                                        
104
 
                        var targetResult = resolver.Resolve(invoke.Target);
105
 
                        if (targetResult is MethodGroupResolveResult) {
106
 
                                foreach (var method in ((MethodGroupResolveResult)targetResult).Methods) {
107
 
                                        if (index < method.Parameters.Count) {
108
 
                                                yield return method.Parameters [index].Type;
109
 
                                        }
110
 
                                }
111
 
                        }
112
 
                }
113
 
 
114
 
                static IEnumerable<IType> GetAllValidTypesFromObjectCreation(CSharpAstResolver resolver, ObjectCreateExpression invoke, AstNode parameter)
115
 
                {
116
 
                        int index = GetArgumentIndex(invoke.Arguments, parameter);
117
 
                        if (index < 0)
118
 
                                yield break;
119
 
 
120
 
                        var targetResult = resolver.Resolve(invoke.Type);
121
 
                        if (targetResult is TypeResolveResult) {
122
 
                                var type = ((TypeResolveResult)targetResult).Type;
123
 
                                if (type.Kind == TypeKind.Delegate && index == 0) {
124
 
                                        yield return type;
125
 
                                        yield break;
126
 
                                }
127
 
                                foreach (var constructor in type.GetConstructors ()) {
128
 
                                        if (index < constructor.Parameters.Count)
129
 
                                                yield return constructor.Parameters [index].Type;
130
 
                                }
131
 
                        }
132
 
                }
133
 
 
134
 
                static IType GetElementType(CSharpAstResolver resolver, IType type)
135
 
                {
136
 
                        // TODO: A better get element type method.
137
 
                        if (type.Kind == TypeKind.Array || type.Kind == TypeKind.Dynamic) {
138
 
                                if (type.Kind == TypeKind.Array)
139
 
                                        return ((ArrayType)type).ElementType;
140
 
                                return resolver.Compilation.FindType(KnownTypeCode.Object);
141
 
                        }
142
 
 
143
 
                        foreach (var method in type.GetMethods (m => m.Name == "GetEnumerator")) {
144
 
                                var pr = method.ReturnType.GetProperties(p => p.Name == "Current").FirstOrDefault();
145
 
                                if (pr != null)
146
 
                                        return pr.ReturnType;
147
 
                        }
148
 
 
149
 
                        return resolver.Compilation.FindType(KnownTypeCode.Object);
150
 
                }
151
 
 
152
 
                internal static IEnumerable<IType> GetValidTypes(CSharpAstResolver resolver, Expression expr)
153
 
                {
154
 
                        if (expr.Parent is DirectionExpression) {
155
 
                                var parent = expr.Parent.Parent;
156
 
                                if (parent is InvocationExpression) {
157
 
                                        var invoke = (InvocationExpression)parent;
158
 
                                        return GetAllValidTypesFromInvokation(resolver, invoke, expr.Parent);
159
 
                                }
160
 
                        }
161
 
 
162
 
                        if (expr.Parent is ArrayInitializerExpression) {
163
 
                                var aex = expr.Parent as ArrayInitializerExpression;
164
 
                                if (aex.IsSingleElement)
165
 
                                        aex = aex.Parent as ArrayInitializerExpression;
166
 
                                var type = GetElementType(resolver, resolver.Resolve(aex.Parent).Type);
167
 
                                if (type.Kind != TypeKind.Unknown)
168
 
                                        return new [] { type };
169
 
                        }
170
 
 
171
 
                        if (expr.Parent is ObjectCreateExpression) {
172
 
                                var invoke = (ObjectCreateExpression)expr.Parent;
173
 
                                return GetAllValidTypesFromObjectCreation(resolver, invoke, expr);
174
 
                        }
175
 
 
176
 
                        if (expr.Parent is ArrayCreateExpression) {
177
 
                                var ace = (ArrayCreateExpression)expr.Parent;
178
 
                                if (!ace.Type.IsNull) {
179
 
                                        return new [] { resolver.Resolve(ace.Type).Type };
180
 
                                }
181
 
                        }
182
 
 
183
 
                        if (expr.Parent is InvocationExpression) {
184
 
                                var parent = expr.Parent;
185
 
                                if (parent is InvocationExpression) {
186
 
                                        var invoke = (InvocationExpression)parent;
187
 
                                        return GetAllValidTypesFromInvokation(resolver, invoke, expr);
188
 
                                }
189
 
                        }
190
 
                        
191
 
                        if (expr.Parent is VariableInitializer) {
192
 
                                var initializer = (VariableInitializer)expr.Parent;
193
 
                                var field = initializer.GetParent<FieldDeclaration>();
194
 
                                if (field != null)
195
 
                                        return new [] { resolver.Resolve(field.ReturnType).Type };
196
 
                                return new [] { resolver.Resolve(initializer).Type };
197
 
                        }
198
 
                        
199
 
                        if (expr.Parent is CastExpression) {
200
 
                                var cast = (CastExpression)expr.Parent;
201
 
                                return new [] { resolver.Resolve(cast.Type).Type };
202
 
                        }
203
 
                        
204
 
                        if (expr.Parent is AsExpression) {
205
 
                                var cast = (AsExpression)expr.Parent;
206
 
                                return new [] { resolver.Resolve(cast.Type).Type };
207
 
                        }
208
 
 
209
 
                        if (expr.Parent is AssignmentExpression) {
210
 
                                var assign = (AssignmentExpression)expr.Parent;
211
 
                                var other = assign.Left == expr ? assign.Right : assign.Left;
212
 
                                return new [] { resolver.Resolve(other).Type };
213
 
                        }
214
 
 
215
 
                        if (expr.Parent is BinaryOperatorExpression) {
216
 
                                var assign = (BinaryOperatorExpression)expr.Parent;
217
 
                                var other = assign.Left == expr ? assign.Right : assign.Left;
218
 
                                return new [] { resolver.Resolve(other).Type };
219
 
                        }
220
 
                        
221
 
                        if (expr.Parent is ReturnStatement) {
222
 
                                var state = resolver.GetResolverStateBefore(expr.Parent);
223
 
                                if (state != null  && state.CurrentMember != null)
224
 
                                        return new [] { state.CurrentMember.ReturnType };
225
 
                        }
226
 
 
227
 
                        if (expr.Parent is YieldReturnStatement) {
228
 
                                var state = resolver.GetResolverStateBefore(expr);
229
 
                                if (state != null && (state.CurrentMember.ReturnType is ParameterizedType)) {
230
 
                                        var pt = (ParameterizedType)state.CurrentMember.ReturnType;
231
 
                                        if (pt.FullName == "System.Collections.Generic.IEnumerable") {
232
 
                                                return new [] { pt.TypeArguments.First() };
233
 
                                        }
234
 
                                }
235
 
                        }
236
 
 
237
 
                        if (expr.Parent is UnaryOperatorExpression) {
238
 
                                var uop = (UnaryOperatorExpression)expr.Parent;
239
 
                                switch (uop.Operator) {
240
 
                                        case UnaryOperatorType.Not:
241
 
                                                return new [] { resolver.Compilation.FindType(KnownTypeCode.Boolean) };
242
 
                                        case UnaryOperatorType.Minus:
243
 
                                        case UnaryOperatorType.Plus:
244
 
                                        case UnaryOperatorType.Increment:
245
 
                                        case UnaryOperatorType.Decrement:
246
 
                                        case UnaryOperatorType.PostIncrement:
247
 
                                        case UnaryOperatorType.PostDecrement:
248
 
                                                return new [] { resolver.Compilation.FindType(KnownTypeCode.Int32) };
249
 
                                }
250
 
                        }
251
 
                        return Enumerable.Empty<IType>();
252
 
                }
253
 
                static readonly IType[] emptyTypes = new IType[0];
254
 
                internal static AstType GuessAstType(RefactoringContext context, Expression expr)
255
 
                {
256
 
                        var type = GetValidTypes(context.Resolver, expr).ToArray();
257
 
                        var typeInference = new TypeInference(context.Compilation);
258
 
                        typeInference.Algorithm = TypeInferenceAlgorithm.ImprovedReturnAllResults;
259
 
                        var inferedType = typeInference.FindTypeInBounds(type, emptyTypes);
260
 
                        if (inferedType.Kind == TypeKind.Unknown)
261
 
                                return new PrimitiveType("object");
262
 
                        return context.CreateShortType(inferedType);
263
 
                }
264
 
 
265
 
                internal static IType GuessType(RefactoringContext context, Expression expr)
266
 
                {
267
 
                        var type = GetValidTypes(context.Resolver, expr).ToArray();
268
 
                        var typeInference = new TypeInference(context.Compilation);
269
 
                        typeInference.Algorithm = TypeInferenceAlgorithm.ImprovedReturnAllResults;
270
 
                        var inferedType = typeInference.FindTypeInBounds(type, emptyTypes);
271
 
                        return inferedType;
272
 
                }
273
 
                #endregion
274
 
        }
275
 
}
276