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

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateClassDeclarationAction.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
// CreateClassDeclarationAction.cs
 
3
//  
 
4
// Author:
 
5
//       Mike KrĆ¼ger <mkrueger@xamarin.com>
 
6
// 
 
7
// Copyright (c) 2012 Xamarin <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.
 
26
 
 
27
using System.Collections.Generic;
 
28
using ICSharpCode.NRefactory.Semantics;
 
29
using System.Linq;
 
30
using ICSharpCode.NRefactory.TypeSystem;
 
31
 
 
32
namespace ICSharpCode.NRefactory.CSharp.Refactoring
 
33
{
 
34
        [ContextAction("Create class", Description = "Creates a class declaration out of an object creation.")]
 
35
        public class CreateClassDeclarationAction : ICodeActionProvider
 
36
        {
 
37
                public IEnumerable<CodeAction> GetActions(RefactoringContext context)
 
38
                {
 
39
                        var simpleType = context.GetNode<SimpleType>();
 
40
                        if (simpleType != null && !(simpleType.Parent is EventDeclaration || simpleType.Parent is CustomEventDeclaration)) 
 
41
                                return GetActions(context, simpleType);
 
42
 
 
43
                        var createExpression = context.GetNode<ObjectCreateExpression>();
 
44
                        if (createExpression != null) 
 
45
                                return GetActions(context, createExpression);
 
46
 
 
47
                        var identifier = context.GetNode<IdentifierExpression>();
 
48
                        if (identifier != null && (identifier.Parent is MemberReferenceExpression)) 
 
49
                                return GetActions(context, identifier);
 
50
 
 
51
                        return Enumerable.Empty<CodeAction>();
 
52
                }
 
53
 
 
54
                static IEnumerable<CodeAction> GetActions(RefactoringContext context, AstNode node)
 
55
                {
 
56
                        var resolveResult = context.Resolve(node) as UnknownIdentifierResolveResult;
 
57
                        if (resolveResult == null)
 
58
                                yield break;
 
59
 
 
60
                        var service = (NamingConventionService)context.GetService(typeof(NamingConventionService));
 
61
                        if (service != null && !service.IsValidName(resolveResult.Identifier, AffectedEntity.Class)) { 
 
62
                                yield break;
 
63
                        }
 
64
                        ClassType classType = GuessClassTypeByName(service, node);
 
65
                        ModifyClassTypeBasedOnTypeGuessing(context, node, ref classType);
 
66
 
 
67
                        string message;
 
68
                        switch (classType) {
 
69
                                case ClassType.Struct:
 
70
                                        message = context.TranslateString("Create struct");
 
71
                                        break;
 
72
                                case ClassType.Interface:
 
73
                                        message = context.TranslateString("Create interface");
 
74
                                        break;
 
75
                                default:
 
76
                                        message = context.TranslateString("Create class");
 
77
                                        break;
 
78
                        }
 
79
                        yield return new CodeAction(message, script => {
 
80
                                script.CreateNewType(CreateType(context, service, node, classType));
 
81
                        }, node);
 
82
 
 
83
                        if (node.Parent is TypeDeclaration || classType != ClassType.Class)
 
84
                                yield break;
 
85
                        yield return new CodeAction(context.TranslateString("Create nested class"), script => {
 
86
                                script.InsertWithCursor(
 
87
                                        context.TranslateString("Create nested class"),
 
88
                                        Script.InsertPosition.Before,
 
89
                                        CreateType(context, service, node, classType)
 
90
                                );
 
91
                        }, node);
 
92
                }
 
93
 
 
94
                static void ModifyClassTypeBasedOnTypeGuessing(RefactoringContext context, AstNode node, ref ClassType classType)
 
95
                {
 
96
                        var guessedType = CreateFieldAction.GuessType(context, node);
 
97
                        if (guessedType.Kind == TypeKind.TypeParameter) {
 
98
                                var tp = (ITypeParameter)guessedType;
 
99
                                if (tp.HasValueTypeConstraint)
 
100
                                        classType = ClassType.Struct;
 
101
                                if (tp.HasReferenceTypeConstraint)
 
102
                                        classType = ClassType.Class;
 
103
                        }
 
104
                }
 
105
                
 
106
                static ClassType GuessClassTypeByName(NamingConventionService service,  string identifier)
 
107
                {
 
108
                        if (service == null)
 
109
                                return ClassType.Class;
 
110
                        if (service.IsValidName (identifier, AffectedEntity.Interface, Modifiers.Public))
 
111
                                return ClassType.Interface;
 
112
                        if (!service.IsValidName (identifier, AffectedEntity.Class, Modifiers.Public) &&
 
113
                             service.IsValidName (identifier, AffectedEntity.Struct, Modifiers.Public))
 
114
                                return ClassType.Struct;
 
115
                        return ClassType.Class;
 
116
                }
 
117
 
 
118
                static ClassType GuessClassTypeByName(NamingConventionService service, AstNode node)
 
119
                {
 
120
                        if (node is SimpleType) 
 
121
                                return GuessClassTypeByName (service, ((SimpleType)node).Identifier);
 
122
                        if (node is IdentifierExpression) 
 
123
                                return GuessClassTypeByName (service, ((IdentifierExpression)node).Identifier);
 
124
                        return ClassType.Class;
 
125
                }
 
126
 
 
127
                static TypeDeclaration CreateType(RefactoringContext context, NamingConventionService service, AstNode node, ClassType classType)
 
128
                {
 
129
                        TypeDeclaration result;
 
130
                        if (node is SimpleType) {
 
131
                                result = CreateClassFromType(context, classType, (SimpleType)node);
 
132
                        } else if (node is ObjectCreateExpression) {
 
133
                                result = CreateClassFromObjectCreation(context, (ObjectCreateExpression)node);
 
134
                        } else {
 
135
                                result = CreateClassFromIdentifier(context, classType, (IdentifierExpression)node);
 
136
                        }
 
137
 
 
138
                        return AddBaseTypesAccordingToNamingRules(context, service, result);
 
139
                }
 
140
 
 
141
                static TypeDeclaration CreateClassFromIdentifier(RefactoringContext context, ClassType classType, IdentifierExpression identifierExpression)
 
142
                {
 
143
                        var result = new TypeDeclaration { Name = identifierExpression.Identifier, ClassType = classType };
 
144
                        var entity = identifierExpression.GetParent<EntityDeclaration>();
 
145
                        if (entity != null)
 
146
                                result.Modifiers |= entity.Modifiers & Modifiers.Public;
 
147
                        return result;
 
148
                }
 
149
 
 
150
                static TypeDeclaration CreateClassFromType(RefactoringContext context, ClassType classType, SimpleType simpleType)
 
151
                {
 
152
                        TypeDeclaration result;
 
153
                        string className = simpleType.Identifier;
 
154
 
 
155
                        if (simpleType.Parent is Attribute && classType == ClassType.Class) {
 
156
                                if (!className.EndsWith("Attribute", System.StringComparison.Ordinal))
 
157
                                        className += "Attribute";
 
158
                        }
 
159
 
 
160
                        result = new TypeDeclaration { Name = className, ClassType = classType };
 
161
                        var entity = simpleType.GetParent<EntityDeclaration>();
 
162
                        if (entity != null)
 
163
                                result.Modifiers |= entity.Modifiers & Modifiers.Public;
 
164
 
 
165
                        var guessedType = CreateFieldAction.GuessType (context, simpleType);
 
166
                        if (guessedType.Kind == TypeKind.TypeParameter)
 
167
                                ImplementConstraints (context, result, (ITypeParameter)guessedType);
 
168
                        return result;
 
169
                }
 
170
 
 
171
                static void ImplementConstraints(RefactoringContext context, TypeDeclaration result, ITypeParameter tp)
 
172
                {
 
173
                        if (tp.HasValueTypeConstraint)
 
174
                                result.ClassType = ClassType.Struct;
 
175
                        if (tp.HasReferenceTypeConstraint)
 
176
                                result.ClassType = ClassType.Class;
 
177
                        if (tp.HasDefaultConstructorConstraint)
 
178
                                result.AddChild (new ConstructorDeclaration { Modifiers = Modifiers.Public, Body = new BlockStatement () }, Roles.TypeMemberRole);
 
179
                        foreach (var baseType in tp.DirectBaseTypes) {
 
180
                                if (baseType.Namespace == "System") {
 
181
                                        if (baseType.Name == "Object" || baseType.Name == "ValueType")
 
182
                                                continue;
 
183
                                }
 
184
                                result.BaseTypes.Add (context.CreateShortType (baseType));
 
185
                        }
 
186
                }
 
187
 
 
188
                static TypeDeclaration CreateClassFromObjectCreation(RefactoringContext context, ObjectCreateExpression createExpression)
 
189
                {
 
190
                        TypeDeclaration result;
 
191
                        string className = createExpression.Type.GetText();
 
192
                        if (!createExpression.Arguments.Any()) {
 
193
                                result = new TypeDeclaration { Name = className };
 
194
                        } else {
 
195
                                var decl = new ConstructorDeclaration {
 
196
                                        Name = className,
 
197
                                        Modifiers = Modifiers.Public,
 
198
                                        Body = new BlockStatement {
 
199
                                                new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")))
 
200
                                        }
 
201
                                };
 
202
                                result = new TypeDeclaration {
 
203
                                        Name = className,
 
204
                                        Members = {
 
205
                                                decl
 
206
                                        }
 
207
                                };
 
208
                                decl.Parameters.AddRange(CreateMethodDeclarationAction.GenerateParameters(context, createExpression.Arguments));
 
209
                        }
 
210
                        var guessedType = CreateFieldAction.GuessType(context, createExpression);
 
211
                        if (guessedType.Kind == TypeKind.Interface || guessedType.Kind == TypeKind.Class && guessedType.GetDefinition ().IsAbstract) {
 
212
                                result.BaseTypes.Add(context.CreateShortType(guessedType));
 
213
                                AddImplementation(context, result, guessedType);
 
214
                        }
 
215
                        
 
216
                        return result;
 
217
                }
 
218
 
 
219
                static Modifiers GetModifiers(IEntity property)
 
220
                {
 
221
                        if (property.DeclaringType.Kind == TypeKind.Interface)
 
222
                                return Modifiers.Public;
 
223
                        switch (property.Accessibility) {
 
224
                                case Accessibility.Public:
 
225
                                        return Modifiers.Public | Modifiers.Override;
 
226
                                case Accessibility.Protected:
 
227
                                        return Modifiers.Protected | Modifiers.Override;
 
228
                                case Accessibility.Internal:
 
229
                                        return Modifiers.Internal | Modifiers.Override;
 
230
                                case Accessibility.ProtectedOrInternal:
 
231
                                        // TODO: oops
 
232
                                        return Modifiers.Internal | Modifiers.Protected | Modifiers.Override;
 
233
                                case Accessibility.ProtectedAndInternal:
 
234
                                        // TODO: oops
 
235
                                        return Modifiers.Internal | Modifiers.Protected | Modifiers.Override;
 
236
                        }
 
237
                        return Modifiers.Override;
 
238
                }
 
239
 
 
240
                static void AddImplementation(RefactoringContext context, TypeDeclaration result, IType guessedType)
 
241
                {
 
242
                        foreach (var property in guessedType.GetProperties ()) {
 
243
                                if (!property.IsAbstract)
 
244
                                        continue;
 
245
                                if (property.IsIndexer) {
 
246
                                        var indexerDecl = new IndexerDeclaration {
 
247
                                                ReturnType = context.CreateShortType(property.ReturnType),
 
248
                                                Modifiers = GetModifiers(property),
 
249
                                                Name = property.Name
 
250
                                        };
 
251
                                        indexerDecl.Parameters.AddRange(ConvertParameters(context, property.Parameters));
 
252
                                        if (property.CanGet)
 
253
                                                indexerDecl.Getter = new Accessor();
 
254
                                        if (property.CanSet)
 
255
                                                indexerDecl.Setter = new Accessor();
 
256
                                        result.AddChild(indexerDecl, Roles.TypeMemberRole);
 
257
                                        continue;
 
258
                                }
 
259
                                var propDecl = new PropertyDeclaration {
 
260
                                        ReturnType = context.CreateShortType(property.ReturnType),
 
261
                                        Modifiers = GetModifiers (property),
 
262
                                        Name = property.Name
 
263
                                };
 
264
                                if (property.CanGet)
 
265
                                        propDecl.Getter = new Accessor();
 
266
                                if (property.CanSet)
 
267
                                        propDecl.Setter = new Accessor();
 
268
                                result.AddChild(propDecl, Roles.TypeMemberRole);
 
269
                        }
 
270
                        
 
271
                        foreach (var method in guessedType.GetMethods ()) {
 
272
                                if (!method.IsAbstract)
 
273
                                        continue;
 
274
                                var decl = new MethodDeclaration {
 
275
                                        ReturnType = context.CreateShortType(method.ReturnType),
 
276
                                        Modifiers = GetModifiers (method),
 
277
                                        Name = method.Name,
 
278
                                        Body = new BlockStatement {
 
279
                                                new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")))
 
280
                                        }
 
281
                                };
 
282
                                decl.Parameters.AddRange(ConvertParameters(context, method.Parameters));
 
283
                                result.AddChild(decl, Roles.TypeMemberRole);
 
284
                        }
 
285
 
 
286
                        foreach (var evt in guessedType.GetEvents ()) {
 
287
                                if (!evt.IsAbstract)
 
288
                                        continue;
 
289
                                var decl = new EventDeclaration {
 
290
                                        ReturnType = context.CreateShortType(evt.ReturnType),
 
291
                                        Modifiers = GetModifiers (evt),
 
292
                                        Variables = {
 
293
                                                new VariableInitializer {
 
294
                                                        Name = evt.Name
 
295
                                                }
 
296
                                        }
 
297
                                };
 
298
                                decl.Variables.Add(new VariableInitializer(evt.Name));
 
299
                                result.AddChild(decl, Roles.TypeMemberRole);
 
300
                        }
 
301
                }
 
302
 
 
303
                static IEnumerable<ParameterDeclaration> ConvertParameters(RefactoringContext context, IList<IParameter> parameters)
 
304
                {
 
305
                        foreach (var param in parameters) {
 
306
                                ParameterModifier mod = ParameterModifier.None;
 
307
                                if (param.IsOut) {
 
308
                                        mod = ParameterModifier.Out;
 
309
                                } else if (param.IsRef) {
 
310
                                        mod = ParameterModifier.Ref;
 
311
                                } else if (param.IsParams) {
 
312
                                        mod = ParameterModifier.Params;
 
313
                                }
 
314
                                yield return new ParameterDeclaration(context.CreateShortType(param.Type), param.Name, mod);
 
315
                        }
 
316
                }
 
317
 
 
318
                static TypeDeclaration AddBaseTypesAccordingToNamingRules(RefactoringContext context, NamingConventionService service, TypeDeclaration result)
 
319
                {
 
320
                        if (service.HasValidRule(result.Name, AffectedEntity.CustomAttributes, Modifiers.Public)) {
 
321
                                result.BaseTypes.Add(context.CreateShortType("System", "Attribute"));
 
322
                        } else if (service.HasValidRule(result.Name, AffectedEntity.CustomEventArgs, Modifiers.Public)) {
 
323
                                result.BaseTypes.Add(context.CreateShortType("System", "EventArgs"));
 
324
                        } else if (service.HasValidRule(result.Name, AffectedEntity.CustomExceptions, Modifiers.Public)) {
 
325
                                result.BaseTypes.Add(context.CreateShortType("System", "Exception"));
 
326
                        }
 
327
                        return result;
 
328
                }
 
329
        }
 
330
}
 
 
b'\\ No newline at end of file'