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

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementInterfaceAction.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
// ImplementInterfaceAction.cs
 
3
//  
 
4
// Author:
 
5
//       Mike KrĆ¼ger <mkrueger@xamarin.com>
 
6
// 
 
7
// Copyright (c) 2012 Xamarin Inc. (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
using System;
 
27
using ICSharpCode.NRefactory.TypeSystem;
 
28
using System.Threading;
 
29
using System.Collections.Generic;
 
30
using System.Linq;
 
31
 
 
32
namespace ICSharpCode.NRefactory.CSharp.Refactoring
 
33
{
 
34
        [ContextAction("Implement interface", Description = "Creates an interface implementation.")]
 
35
        public class ImplementInterfaceAction : ICodeActionProvider
 
36
        {
 
37
                public IEnumerable<CodeAction> GetActions(RefactoringContext context)
 
38
                {
 
39
                        var type = context.GetNode<AstType>();
 
40
                        if (type == null || type.Role != Roles.BaseType)
 
41
                                yield break;
 
42
                        
 
43
                        var state = context.GetResolverStateBefore(type);
 
44
                        if (state.CurrentTypeDefinition == null)
 
45
                                yield break;
 
46
                        
 
47
                        var resolveResult = context.Resolve(type);
 
48
                        if (resolveResult.Type.Kind != TypeKind.Interface)
 
49
                                yield break;
 
50
                        
 
51
                        var toImplement = CollectMembersToImplement(state.CurrentTypeDefinition, resolveResult.Type, false);
 
52
                        if (toImplement.Count == 0)
 
53
                                yield break;
 
54
                        
 
55
                        yield return new CodeAction(context.TranslateString("Implement interface"), script => {
 
56
                                script.InsertWithCursor(
 
57
                                        context.TranslateString("Implement Interface"),
 
58
                                        state.CurrentTypeDefinition,
 
59
                                        GenerateImplementation(context, toImplement)
 
60
                                );
 
61
                        }, type);
 
62
                }
 
63
                
 
64
                public static IEnumerable<AstNode> GenerateImplementation(RefactoringContext context, IEnumerable<Tuple<IMember, bool>> toImplement)
 
65
                {
 
66
                        var nodes = new Dictionary<IType, List<AstNode>>();
 
67
                        
 
68
                        foreach (var member in toImplement) {
 
69
                                if (!nodes.ContainsKey(member.Item1.DeclaringType)) 
 
70
                                        nodes [member.Item1.DeclaringType] = new List<AstNode>();
 
71
                                nodes [member.Item1.DeclaringType].Add(GenerateMemberImplementation(context, member.Item1, member.Item2));
 
72
                        }
 
73
                        
 
74
                        foreach (var kv in nodes) {
 
75
                                if (kv.Key.Kind == TypeKind.Interface) {
 
76
                                        yield return new PreProcessorDirective(
 
77
                                                PreProcessorDirectiveType.Region,
 
78
                                                string.Format("{0} implementation", kv.Key.Name));
 
79
                                } else {
 
80
                                        yield return new PreProcessorDirective(
 
81
                                                PreProcessorDirectiveType.Region,
 
82
                                                string.Format("implemented abstract members of {0}", kv.Key.Name));
 
83
                                }
 
84
                                foreach (var member in kv.Value)
 
85
                                        yield return member;
 
86
                                yield return new PreProcessorDirective(
 
87
                                        PreProcessorDirectiveType.Endregion
 
88
                                );
 
89
                        }
 
90
                }
 
91
                
 
92
                static EntityDeclaration GenerateMemberImplementation(RefactoringContext context, IMember member, bool explicitImplementation)
 
93
                {
 
94
                        var builder = context.CreateTypeSytemAstBuilder();
 
95
                        builder.GenerateBody = true;
 
96
                        builder.ShowModifiers = false;
 
97
                        builder.ShowAccessibility = true;
 
98
                        builder.ShowConstantValues = !explicitImplementation;
 
99
                        builder.ShowTypeParameterConstraints = !explicitImplementation;
 
100
                        builder.UseCustomEvents = explicitImplementation;
 
101
                        var decl = builder.ConvertEntity(member);
 
102
                        if (explicitImplementation) {
 
103
                                decl.Modifiers = Modifiers.None;
 
104
                                decl.AddChild(builder.ConvertType(member.DeclaringType), EntityDeclaration.PrivateImplementationTypeRole);
 
105
                        } else if (member.DeclaringType.Kind == TypeKind.Interface) {
 
106
                                decl.Modifiers |= Modifiers.Public;
 
107
                        } else {
 
108
                                // Remove 'internal' modifier from 'protected internal' members if the override is in a different assembly than the member
 
109
                                if (!member.ParentAssembly.InternalsVisibleTo(context.Compilation.MainAssembly)) {
 
110
                                        decl.Modifiers &= ~Modifiers.Internal;
 
111
                                }
 
112
                        }
 
113
                        return decl;
 
114
                }
 
115
                
 
116
                public static List<Tuple<IMember, bool>> CollectMembersToImplement(ITypeDefinition implementingType, IType interfaceType, bool explicitly)
 
117
                {
 
118
                        var def = interfaceType.GetDefinition();
 
119
                        List<Tuple<IMember, bool>> toImplement = new List<Tuple<IMember, bool>>();
 
120
                        bool alreadyImplemented;
 
121
                        
 
122
                        // Stub out non-implemented events defined by @iface
 
123
                        foreach (var evGroup in interfaceType.GetEvents (e => !e.IsSynthetic).GroupBy (m => m.DeclaringType).Reverse ())
 
124
                                foreach (var ev in evGroup) {
 
125
                                        bool needsExplicitly = explicitly;
 
126
                                        alreadyImplemented = implementingType.GetAllBaseTypeDefinitions().Any(
 
127
                                        x => x.Kind != TypeKind.Interface && x.Events.Any(y => y.Name == ev.Name)
 
128
                                        );
 
129
                                
 
130
                                        if (!alreadyImplemented)
 
131
                                                toImplement.Add(new Tuple<IMember, bool>(ev, needsExplicitly));
 
132
                                }
 
133
                        
 
134
                        // Stub out non-implemented methods defined by @iface
 
135
                        foreach (var methodGroup in interfaceType.GetMethods (d => !d.IsSynthetic).GroupBy (m => m.DeclaringType).Reverse ())
 
136
                                foreach (var method in methodGroup) {
 
137
                                
 
138
                                        bool needsExplicitly = explicitly;
 
139
                                        alreadyImplemented = false;
 
140
                                
 
141
                                        foreach (var cmet in implementingType.GetMethods ()) {
 
142
                                                if (CompareMethods(method, cmet)) {
 
143
                                                        if (!needsExplicitly && !cmet.ReturnType.Equals(method.ReturnType))
 
144
                                                                needsExplicitly = true;
 
145
                                                        else
 
146
                                                                alreadyImplemented |= !needsExplicitly /*|| cmet.InterfaceImplementations.Any (impl => impl.InterfaceType.Equals (interfaceType))*/;
 
147
                                                }
 
148
                                        }
 
149
                                        if (toImplement.Where(t => t.Item1 is IMethod).Any(t => CompareMethods(method, (IMethod)t.Item1)))
 
150
                                                needsExplicitly = true;
 
151
                                        if (!alreadyImplemented) 
 
152
                                                toImplement.Add(new Tuple<IMember, bool>(method, needsExplicitly));
 
153
                                }
 
154
                        
 
155
                        // Stub out non-implemented properties defined by @iface
 
156
                        foreach (var propGroup in interfaceType.GetProperties (p => !p.IsSynthetic).GroupBy (m => m.DeclaringType).Reverse ())
 
157
                                foreach (var prop in propGroup) {
 
158
                                        bool needsExplicitly = explicitly;
 
159
                                        alreadyImplemented = false;
 
160
                                        foreach (var t in implementingType.GetAllBaseTypeDefinitions ()) {
 
161
                                                if (t.Kind == TypeKind.Interface) {
 
162
                                                        foreach (var cprop in t.Properties) {
 
163
                                                                if (cprop.Name == prop.Name && cprop.IsShadowing) {
 
164
                                                                        if (!needsExplicitly && !cprop.ReturnType.Equals(prop.ReturnType))
 
165
                                                                                needsExplicitly = true;
 
166
                                                                }
 
167
                                                        }
 
168
                                                        continue;
 
169
                                                }
 
170
                                                foreach (var cprop in t.Properties) {
 
171
                                                        if (cprop.Name == prop.Name) {
 
172
                                                                if (!needsExplicitly && !cprop.ReturnType.Equals(prop.ReturnType))
 
173
                                                                        needsExplicitly = true;
 
174
                                                                else
 
175
                                                                        alreadyImplemented |= !needsExplicitly/* || cprop.InterfaceImplementations.Any (impl => impl.InterfaceType.Resolve (ctx).Equals (interfaceType))*/;
 
176
                                                        }
 
177
                                                }
 
178
                                        }
 
179
                                        if (!alreadyImplemented)
 
180
                                                toImplement.Add(new Tuple<IMember, bool>(prop, needsExplicitly));
 
181
                                }
 
182
                        return toImplement;
 
183
                }
 
184
                
 
185
                internal static bool CompareMethods(IMethod interfaceMethod, IMethod typeMethod)
 
186
                {
 
187
                        if (typeMethod.IsExplicitInterfaceImplementation)
 
188
                                return typeMethod.ImplementedInterfaceMembers.Any(m => m.Equals(interfaceMethod));
 
189
                        return SignatureComparer.Ordinal.Equals(interfaceMethod, typeMethod);
 
190
                }
 
191
        }
 
192
}
 
193