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)
5
using System.Collections;
6
using System.Collections.Generic;
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;
17
namespace ICSharpCode.VBNetBinding
19
public static class CompletionDataHelper
21
public static VBNetCompletionItemList GenerateCompletionData(this ExpressionResult expressionResult, ITextEditor editor, char pressedKey)
23
VBNetCompletionItemList result = new VBNetCompletionItemList();
25
IResolver resolver = ParserService.CreateResolver(editor.FileName);
26
ParseInformation info = ParserService.GetParseInformation(editor.FileName);
31
List<ICompletionEntry> data = new List<ICompletionEntry>();
33
bool completingDotExpression = false;
34
IReturnType resolvedType = null;
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)
43
: expressionResult.Expression.LastIndexOf('.');
46
expressionResult.Expression = expressionResult.Expression.Substring(0, idx);
47
// its the same as if . was pressed
48
completingDotExpression = true;
50
expressionResult.Expression = "";
54
var rr = resolver.Resolve(expressionResult, info, editor.Document.Text);
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);
62
if (rr is MethodGroupResolveResult) {
63
IMethod singleMethod = ((MethodGroupResolveResult)rr).GetMethodWithEmptyParameterList();
64
if (singleMethod != null)
65
rr = new MemberResolveResult(rr.CallingClass, rr.CallingMember, singleMethod);
68
if (rr is IntegerLiteralResolveResult && pressedKey == '.')
71
data = rr.GetCompletionData(info.CompilationUnit.ProjectContent, ((NRefactoryCompletionItemList)result).ContainsItemsFromAllNamespaces) ?? new List<ICompletionEntry>();
73
resolvedType = rr.ResolvedType;
77
bool addedKeywords = false;
79
if (expressionResult.Tag != null && (expressionResult.Context != ExpressionContext.Importable) && pressedKey != '.' && !completingDotExpression) {
80
AddVBNetKeywords(data, (BitArray)expressionResult.Tag);
84
CodeCompletionItemProvider.ConvertCompletionData(result, data, expressionResult.Context);
86
if (addedKeywords && result.Items.Any())
87
AddTemplates(editor, result);
89
string word = editor.GetWordBeforeCaret().Trim();
91
IClass c = GetCurrentClass(editor);
92
IMember m = GetCurrentMember(editor);
94
HandleKeyword(ref result, resolvedType, word, c, m, editor, pressedKey);
96
AddSpecialItems(ref result, info, resolvedType, m, expressionResult, editor);
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() : "";
104
if (!string.IsNullOrWhiteSpace(word))
105
result.PreselectionLength = word.Length;
108
prevChar = editor.Caret.Offset > 0 ? editor.Document.GetCharAt(editor.Caret.Offset - 1) : '\0';
111
result.PreselectionLength++;
118
static void HandleKeyword(ref VBNetCompletionItemList result, IReturnType resolvedType, string word, IClass c, IMember m, ITextEditor editor, char pressedKey)
120
if (pressedKey == ' ') {
121
if (word.Equals("return", StringComparison.OrdinalIgnoreCase) && m != null) {
122
c = m.ReturnType != null ? m.ReturnType.GetUnderlyingClass() : 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;
134
if (word.Equals("overrides", StringComparison.OrdinalIgnoreCase) && c != null) {
135
result = new OverrideCompletionItemProvider().GenerateCompletionList(editor).ToVBCCList();
140
static void AddSpecialItems(ref VBNetCompletionItemList result, ParseInformation info, IReturnType resolvedType, IMember m, ExpressionResult expressionResult, ITextEditor editor)
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}")
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 });
154
static bool AllowsAttributeValueAccess(IReturnType resolvedType, IProjectContent content)
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.
162
string baseClass = "System.Xml.Linq.XElement";
163
string methodName = "Attributes";
165
return AllowsHelper(baseClass, methodName, resolvedType, content);
168
static bool AllowsDescendentAccess(IReturnType resolvedType, IProjectContent content)
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.
176
string baseClass = "System.Xml.Linq.XContainer";
177
string methodName = "Descendants";
179
return AllowsHelper(baseClass, methodName, resolvedType, content);
182
static bool AllowsHelper(string baseClass, string methodName, IReturnType resolvedType, IProjectContent content)
184
IClass extensions = content.GetClass("System.Xml.Linq.Extensions", 0);
185
if (extensions == null)
187
IMethod descendents = extensions.Methods.FirstOrDefault(m => m.Name == methodName);
188
if (descendents == null)
190
IParameter param = descendents.Parameters.FirstOrDefault();
193
IClass resolvedTypeClass = resolvedType.GetUnderlyingClass();
194
if (resolvedTypeClass == null)
196
return MemberLookupHelper.IsApplicable(resolvedType, param, descendents)
197
|| resolvedTypeClass.IsTypeInInheritanceTree(content.GetClass(baseClass, 0));
200
static void AddVBNetKeywords(List<ICompletionEntry> ar, BitArray keywords)
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)));
209
static void AddTemplates(ITextEditor editor, DefaultCompletionItemList list)
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);
220
static bool FitsToContext(ICompletionItem item, List<ICompletionItem> list)
222
var snippetItem = item as ISnippetCompletionItem;
224
if (snippetItem == null)
227
if (string.IsNullOrEmpty(snippetItem.Keyword))
230
return list.Any(x => x.Image == ClassBrowserIconService.Keyword
231
&& x.Text == snippetItem.Keyword);
234
static IMember GetCurrentMember(ITextEditor editor)
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;
245
static IClass GetCurrentClass(ITextEditor editor)
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;