~halega/+junk/sharpdevelop

« back to all changes in this revision

Viewing changes to src/AddIns/BackendBindings/VBNetBinding/Project/Src/CompletionDataHelper.cs

  • Committer: sk
  • Date: 2011-09-10 05:17:57 UTC
  • Revision ID: halega@halega.com-20110910051757-qfouz1llya9m6boy
4.1.0.7915 Release Candidate 1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
 
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
 
3
 
 
4
using System;
 
5
using System.Collections;
 
6
using System.Collections.Generic;
 
7
using System.Linq;
 
8
 
 
9
using ICSharpCode.Core;
 
10
using ICSharpCode.NRefactory.Parser.VB;
 
11
using ICSharpCode.SharpDevelop;
 
12
using ICSharpCode.SharpDevelop.Dom;
 
13
using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver;
 
14
using ICSharpCode.SharpDevelop.Editor;
 
15
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
 
16
 
 
17
namespace ICSharpCode.VBNetBinding
 
18
{
 
19
        public static class CompletionDataHelper
 
20
        {
 
21
                public static VBNetCompletionItemList GenerateCompletionData(this ExpressionResult expressionResult, ITextEditor editor, char pressedKey)
 
22
                {
 
23
                        VBNetCompletionItemList result = new VBNetCompletionItemList();
 
24
                        
 
25
                        IResolver resolver = ParserService.CreateResolver(editor.FileName);
 
26
                        ParseInformation info = ParserService.GetParseInformation(editor.FileName);
 
27
                        
 
28
                        if (info == null)
 
29
                                return result;
 
30
                        
 
31
                        List<ICompletionEntry> data = new List<ICompletionEntry>();
 
32
                        
 
33
                        bool completingDotExpression = false;
 
34
                        IReturnType resolvedType = null;
 
35
                        
 
36
                        if (expressionResult.Context != ExpressionContext.Global && expressionResult.Context != ExpressionContext.TypeDeclaration) {
 
37
                                if (expressionResult.Context == ExpressionContext.Importable
 
38
                                    && string.IsNullOrWhiteSpace(expressionResult.Expression)) {
 
39
                                        expressionResult.Expression = "Global";
 
40
                                } else if (pressedKey == '\0') {
 
41
                                        int idx = string.IsNullOrWhiteSpace(expressionResult.Expression)
 
42
                                                ? -1
 
43
                                                : expressionResult.Expression.LastIndexOf('.');
 
44
                                        
 
45
                                        if (idx > -1) {
 
46
                                                expressionResult.Expression = expressionResult.Expression.Substring(0, idx);
 
47
                                                // its the same as if . was pressed
 
48
                                                completingDotExpression = true;
 
49
                                        } else {
 
50
                                                expressionResult.Expression = "";
 
51
                                        }
 
52
                                }
 
53
                                
 
54
                                var rr = resolver.Resolve(expressionResult, info, editor.Document.Text);
 
55
                                
 
56
                                if (rr == null || !rr.IsValid || (pressedKey != '.' && !completingDotExpression)) {
 
57
                                        if (((BitArray)expressionResult.Tag)[Tokens.Identifier])
 
58
                                                data = new NRefactoryResolver(LanguageProperties.VBNet)
 
59
                                                        .CtrlSpace(editor.Caret.Line, editor.Caret.Column, info, editor.Document.Text, expressionResult.Context,
 
60
                                                                   ((NRefactoryCompletionItemList)result).ContainsItemsFromAllNamespaces);
 
61
                                } else {
 
62
                                        if (rr is MethodGroupResolveResult) {
 
63
                                                IMethod singleMethod = ((MethodGroupResolveResult)rr).GetMethodWithEmptyParameterList();
 
64
                                                if (singleMethod != null)
 
65
                                                        rr = new MemberResolveResult(rr.CallingClass, rr.CallingMember, singleMethod);
 
66
                                        }
 
67
                                        
 
68
                                        if (rr is IntegerLiteralResolveResult && pressedKey == '.')
 
69
                                                return result;
 
70
                                        
 
71
                                        data = rr.GetCompletionData(info.CompilationUnit.ProjectContent, ((NRefactoryCompletionItemList)result).ContainsItemsFromAllNamespaces) ?? new List<ICompletionEntry>();
 
72
                                        
 
73
                                        resolvedType = rr.ResolvedType;
 
74
                                }
 
75
                        }
 
76
                        
 
77
                        bool addedKeywords = false;
 
78
                        
 
79
                        if (expressionResult.Tag != null && (expressionResult.Context != ExpressionContext.Importable) && pressedKey != '.' && !completingDotExpression) {
 
80
                                AddVBNetKeywords(data, (BitArray)expressionResult.Tag);
 
81
                                addedKeywords = true;
 
82
                        }
 
83
                        
 
84
                        CodeCompletionItemProvider.ConvertCompletionData(result, data, expressionResult.Context);
 
85
                        
 
86
                        if (addedKeywords && result.Items.Any())
 
87
                                AddTemplates(editor, result);
 
88
                        
 
89
                        string word = editor.GetWordBeforeCaret().Trim();
 
90
                        
 
91
                        IClass c = GetCurrentClass(editor);
 
92
                        IMember m = GetCurrentMember(editor);
 
93
                        
 
94
                        HandleKeyword(ref result,  resolvedType, word, c, m, editor, pressedKey);
 
95
                        
 
96
                        AddSpecialItems(ref result, info, resolvedType, m, expressionResult, editor);
 
97
                        
 
98
                        char prevChar;
 
99
                        
 
100
                        if (pressedKey == '\0') { // ctrl+space
 
101
                                prevChar = editor.Caret.Offset > 0 ? editor.Document.GetCharAt(editor.Caret.Offset - 1) : '\0';
 
102
                                word = char.IsLetterOrDigit(prevChar) || prevChar == '_' ? editor.GetWordBeforeCaret() : "";
 
103
                                
 
104
                                if (!string.IsNullOrWhiteSpace(word))
 
105
                                        result.PreselectionLength = word.Length;
 
106
                        }
 
107
                        
 
108
                        prevChar =  editor.Caret.Offset > 0 ? editor.Document.GetCharAt(editor.Caret.Offset - 1) : '\0';
 
109
                        
 
110
                        if (prevChar == '_')
 
111
                                result.PreselectionLength++;
 
112
                        
 
113
                        result.SortItems();
 
114
                        
 
115
                        return result;
 
116
                }
 
117
 
 
118
                static void HandleKeyword(ref VBNetCompletionItemList result, IReturnType resolvedType, string word, IClass c, IMember m, ITextEditor editor, char pressedKey)
 
119
                {
 
120
                        if (pressedKey == ' ') {
 
121
                                if (word.Equals("return", StringComparison.OrdinalIgnoreCase) && m != null) {
 
122
                                        c = m.ReturnType != null ? m.ReturnType.GetUnderlyingClass() : null;
 
123
                                        if (c != null) {
 
124
                                                foreach (CodeCompletionItem item in result.Items.OfType<CodeCompletionItem>()) {
 
125
                                                        IClass itemClass = item.Entity as IClass;
 
126
                                                        if (itemClass != null && c.FullyQualifiedName == itemClass.FullyQualifiedName && c.TypeParameters.Count == itemClass.TypeParameters.Count) {
 
127
                                                                result.SuggestedItem = item;
 
128
                                                                break;
 
129
                                                        }
 
130
                                                }
 
131
                                        }
 
132
                                }
 
133
                                
 
134
                                if (word.Equals("overrides", StringComparison.OrdinalIgnoreCase) && c != null) {
 
135
                                        result = new OverrideCompletionItemProvider().GenerateCompletionList(editor).ToVBCCList();
 
136
                                }
 
137
                        }
 
138
                }
 
139
 
 
140
                static void AddSpecialItems(ref VBNetCompletionItemList result, ParseInformation info, IReturnType resolvedType, IMember m, ExpressionResult expressionResult, ITextEditor editor)
 
141
                {
 
142
                        if (expressionResult.Context == ExpressionContext.Type && m != null && m.BodyRegion.IsInside(editor.Caret.Line, editor.Caret.Column)) {
 
143
                                result.Items.Add(new DefaultCompletionItem("? =") {
 
144
                                                        Image = ClassBrowserIconService.GotoArrow,
 
145
                                                        Description = StringParser.Parse("${res:AddIns.VBNetBinding.CodeCompletion.QuestionmarkEqualsItem.Description}")
 
146
                                                 });
 
147
                        }
 
148
                        if (resolvedType != null && AllowsDescendentAccess(resolvedType, info.CompilationUnit.ProjectContent))
 
149
                                result.Items.Add(new DefaultCompletionItem("..") { Image = ClassBrowserIconService.GotoArrow });
 
150
                        if (resolvedType != null && AllowsAttributeValueAccess(resolvedType, info.CompilationUnit.ProjectContent))
 
151
                                result.Items.Add(new DefaultCompletionItem("@") { Image = ClassBrowserIconService.GotoArrow });
 
152
                }
 
153
                
 
154
                static bool AllowsAttributeValueAccess(IReturnType resolvedType, IProjectContent content)
 
155
                {
 
156
                        /* See VB 10 Spec, pg. 282:
 
157
                         * If an attribute access, System.Xml.Linq.XElement or a derived type, or
 
158
                         * System.Collections.Generic.IEnumerable(Of T) or a derived type, where T is
 
159
                         * System.Xml.Linq.XElement or a derived type.
 
160
                         **/
 
161
                        
 
162
                        string baseClass = "System.Xml.Linq.XElement";
 
163
                        string methodName = "Attributes";
 
164
                        
 
165
                        return AllowsHelper(baseClass, methodName, resolvedType, content);
 
166
                }
 
167
                
 
168
                static bool AllowsDescendentAccess(IReturnType resolvedType, IProjectContent content)
 
169
                {
 
170
                        /* See VB 10 Spec, pg. 282:
 
171
                         * If an element or descendents access, System.Xml.Linq.XContainer or a
 
172
                         * derived type, or System.Collections.Generic.IEnumerable(Of T) or a derived
 
173
                         * type, where T is System.Xml.Linq.XContainer or a derived type.
 
174
                         **/
 
175
                        
 
176
                        string baseClass = "System.Xml.Linq.XContainer";
 
177
                        string methodName = "Descendants";
 
178
                        
 
179
                        return AllowsHelper(baseClass, methodName, resolvedType, content);
 
180
                }
 
181
                
 
182
                static bool AllowsHelper(string baseClass, string methodName, IReturnType resolvedType, IProjectContent content)
 
183
                {
 
184
                        IClass extensions = content.GetClass("System.Xml.Linq.Extensions", 0);
 
185
                        if (extensions == null)
 
186
                                return false;
 
187
                        IMethod descendents = extensions.Methods.FirstOrDefault(m => m.Name == methodName);
 
188
                        if (descendents == null)
 
189
                                return false;
 
190
                        IParameter param = descendents.Parameters.FirstOrDefault();
 
191
                        if (param == null)
 
192
                                return false;
 
193
                        IClass resolvedTypeClass = resolvedType.GetUnderlyingClass();
 
194
                        if (resolvedTypeClass == null)
 
195
                                return false;
 
196
                        return MemberLookupHelper.IsApplicable(resolvedType, param, descendents)
 
197
                                || resolvedTypeClass.IsTypeInInheritanceTree(content.GetClass(baseClass, 0));
 
198
                }
 
199
                
 
200
                static void AddVBNetKeywords(List<ICompletionEntry> ar, BitArray keywords)
 
201
                {
 
202
                        for (int i = 0; i < keywords.Length; i++) {
 
203
                                if (keywords[i] && i >= Tokens.AddHandler && i < Tokens.MaxToken) {
 
204
                                        ar.Add(new KeywordEntry(Tokens.GetTokenString(i)));
 
205
                                }
 
206
                        }
 
207
                }
 
208
                
 
209
                static void AddTemplates(ITextEditor editor, DefaultCompletionItemList list)
 
210
                {
 
211
                        if (list == null)
 
212
                                return;
 
213
                        List<ICompletionItem> snippets = editor.GetSnippets().ToList();
 
214
                        snippets.RemoveAll(item => !FitsToContext(item, list.Items));
 
215
                        list.Items.RemoveAll(item => item.Image == ClassBrowserIconService.Keyword && snippets.Exists(i => i.Text == item.Text));
 
216
                        list.Items.AddRange(snippets);
 
217
                        list.SortItems();
 
218
                }
 
219
                
 
220
                static bool FitsToContext(ICompletionItem item, List<ICompletionItem> list)
 
221
                {
 
222
                        var snippetItem = item as ISnippetCompletionItem;
 
223
                        
 
224
                        if (snippetItem == null)
 
225
                                return false;
 
226
                        
 
227
                        if (string.IsNullOrEmpty(snippetItem.Keyword))
 
228
                                return true;
 
229
                        
 
230
                        return list.Any(x => x.Image == ClassBrowserIconService.Keyword
 
231
                                        && x.Text == snippetItem.Keyword);
 
232
                }
 
233
                
 
234
                static IMember GetCurrentMember(ITextEditor editor)
 
235
                {
 
236
                        var caret = editor.Caret;
 
237
                        NRefactoryResolver r = new NRefactoryResolver(LanguageProperties.VBNet);
 
238
                        if (r.Initialize(ParserService.GetParseInformation(editor.FileName), caret.Line, caret.Column)) {
 
239
                                return r.CallingMember;
 
240
                        } else {
 
241
                                return null;
 
242
                        }
 
243
                }
 
244
                
 
245
                static IClass GetCurrentClass(ITextEditor editor)
 
246
                {
 
247
                        var caret = editor.Caret;
 
248
                        NRefactoryResolver r = new NRefactoryResolver(LanguageProperties.VBNet);
 
249
                        if (r.Initialize(ParserService.GetParseInformation(editor.FileName), caret.Line, caret.Column)) {
 
250
                                return r.CallingClass;
 
251
                        } else {
 
252
                                return null;
 
253
                        }
 
254
                }
 
255
        }
 
256
}