2
// CSharpCompletionEngine.cs
5
// Mike KrĆ¼ger <mkrueger@xamarin.com>
7
// Copyright (c) 2011 Xamarin Inc. (http://xamarin.com)
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:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
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
27
using System.Collections.Generic;
31
using ICSharpCode.NRefactory.Completion;
32
using ICSharpCode.NRefactory.CSharp.Refactoring;
33
using ICSharpCode.NRefactory.CSharp.Resolver;
34
using ICSharpCode.NRefactory.Editor;
35
using ICSharpCode.NRefactory.Semantics;
36
using ICSharpCode.NRefactory.TypeSystem;
37
using ICSharpCode.NRefactory.CSharp.TypeSystem;
39
namespace ICSharpCode.NRefactory.CSharp.Completion
41
public class CSharpCompletionEngine : CSharpCompletionEngineBase
43
internal ICompletionDataFactory factory;
45
#region Additional input properties
46
public CSharpFormattingOptions FormattingPolicy { get; set; }
48
public string EolMarker { get; set; }
50
public string IndentString { get; set; }
53
#region Result properties
54
public bool AutoCompleteEmptyMatch;
55
public bool AutoSelect;
56
public string DefaultCompletionString;
57
public bool CloseOnSquareBrackets;
60
public CSharpCompletionEngine(IDocument document, ICompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) : base (content, ctx, unit, parsedFile)
62
if (document == null) {
63
throw new ArgumentNullException("document");
65
if (factory == null) {
66
throw new ArgumentNullException("factory");
68
this.document = document;
69
this.factory = factory;
70
// Set defaults for additional input properties
71
this.FormattingPolicy = FormattingOptionsFactory.CreateMono();
72
this.EolMarker = Environment.NewLine;
73
this.IndentString = "\t";
76
public bool TryGetCompletionWord(int offset, out int startPos, out int wordLength)
78
startPos = wordLength = 0;
81
char c = document.GetCharAt(pos);
82
if (!char.IsLetterOrDigit(c) && c != '_')
92
while (pos < document.TextLength) {
93
char c = document.GetCharAt(pos);
94
if (!char.IsLetterOrDigit(c) && c != '_')
98
wordLength = pos - startPos;
102
public IEnumerable<ICompletionData> GetCompletionData(int offset, bool controlSpace)
104
this.AutoCompleteEmptyMatch = true;
105
this.AutoSelect = true;
106
this.DefaultCompletionString = null;
109
char lastChar = document.GetCharAt(offset - 1);
110
var result = MagicKeyCompletion(lastChar, controlSpace) ?? Enumerable.Empty<ICompletionData>();
111
if (controlSpace && char.IsWhiteSpace(lastChar)) {
113
while (offset >= 0 && char.IsWhiteSpace (document.GetCharAt (offset))) {
117
var nonWsResult = MagicKeyCompletion(
118
document.GetCharAt(offset),
121
if (nonWsResult != null) {
122
var text = new HashSet<string>(result.Select(r => r.CompletionText));
123
result = result.Concat(nonWsResult.Where(r => !text.Contains(r.CompletionText)));
130
return Enumerable.Empty<ICompletionData>();
133
IEnumerable<string> GenerateNameProposals(AstType type)
135
if (type is PrimitiveType) {
136
var pt = (PrimitiveType)type;
137
switch (pt.Keyword) {
162
if (type is SimpleType) {
163
name = ((SimpleType)type).Identifier;
164
} else if (type is MemberType) {
165
name = ((SimpleType)type).Identifier;
170
var names = WordParser.BreakWords(name);
172
var possibleName = new StringBuilder();
173
for (int i = 0; i < names.Count; i++) {
174
possibleName.Length = 0;
175
for (int j = i; j < names.Count; j++) {
176
if (string.IsNullOrEmpty(names [j])) {
180
names [j] = Char.ToLower(names [j] [0]) + names [j].Substring(1);
182
possibleName.Append(names [j]);
184
yield return possibleName.ToString();
188
IEnumerable<ICompletionData> HandleMemberReferenceCompletion(ExpressionResult expr)
193
// do not complete <number>. (but <number>.<number>.)
194
if (expr.Node is PrimitiveExpression) {
195
var pexpr = (PrimitiveExpression)expr.Node;
196
if (!(pexpr.Value is string || pexpr.Value is char) && !pexpr.LiteralValue.Contains('.')) {
200
var resolveResult = ResolveExpression(expr);
201
if (resolveResult == null) {
204
if (expr.Node is AstType) {
205
// need to look at paren.parent because of "catch (<Type>.A" expression
206
if (expr.Node.Parent != null && expr.Node.Parent.Parent is CatchClause)
207
return HandleCatchClauseType(expr);
208
return CreateTypeAndNamespaceCompletionData(
215
return CreateCompletionData(
223
bool IsInPreprocessorDirective()
225
var text = GetMemberTextToCaret().Item1;
226
var miniLexer = new MiniLexer(text);
228
return miniLexer.IsInPreprocessorDirective;
231
IEnumerable<ICompletionData> HandleObjectInitializer(CompilationUnit unit, AstNode n)
234
while (p != null && !(p is ObjectCreateExpression)) {
237
var parent = (ArrayInitializerExpression)n.Parent;
238
if (parent.IsSingleElement)
239
parent = (ArrayInitializerExpression)parent.Parent;
241
var contextList = new CompletionDataWrapper(this);
242
var initializerResult = ResolveExpression(p, unit);
243
if (initializerResult != null && initializerResult.Item1.Type.Kind != TypeKind.Unknown) {
245
// 1) New initalizer { xpr
246
// 2) Object initializer { prop = val1, field = val2, xpr
247
// 3) Array initializer { new Foo (), a, xpr
248
// in case 1 all object/array initializer options should be given - in the others not.
251
if (parent.Elements.Count > 1) {
252
prev = parent.Elements.First();
253
if (prev is ArrayInitializerExpression && ((ArrayInitializerExpression)prev).IsSingleElement)
254
prev = ((ArrayInitializerExpression)prev).Elements.FirstOrDefault();
257
if (prev != null && !(prev is NamedExpression)) {
258
AddContextCompletion(contextList, GetState(), n, unit);
260
return contextList.Result;
263
foreach (var m in initializerResult.Item1.Type.GetMembers (m => m.IsPublic && (m.EntityType == EntityType.Property || m.EntityType == EntityType.Field))) {
264
contextList.AddMember(m);
267
if (prev != null && (prev is NamedExpression)) {
269
return contextList.Result;
274
// check if the object is a list, if not only provide object initalizers
275
var list = typeof(System.Collections.IList).ToTypeReference().Resolve(Compilation);
276
if (initializerResult.Item1.Type.Kind != TypeKind.Array && list != null) {
277
var def = initializerResult.Item1.Type.GetDefinition();
278
if (def != null && !def.IsDerivedFrom(list.GetDefinition()))
279
return contextList.Result;
282
AddContextCompletion(contextList, GetState(), n, unit);
283
return contextList.Result;
289
IEnumerable<ICompletionData> MagicKeyCompletion(char completionChar, bool controlSpace)
291
Tuple<ResolveResult, CSharpResolver> resolveResult;
292
switch (completionChar) {
293
// Magic key completion
296
if (IsInsideCommentStringOrDirective()) {
297
return Enumerable.Empty<ICompletionData>();
299
return HandleMemberReferenceCompletion(GetExpressionBeforeCursor());
301
if (!IsInPreprocessorDirective())
303
return GetDirectiveCompletionData();
304
// XML doc completion
306
if (IsInsideDocComment()) {
307
return GetXmlDocumentationCompletionData();
310
return DefaultControlSpaceItems();
314
if (!IsInsideDocComment()) {
317
string lineText = document.GetText(document.GetLineByNumber(location.Line));
318
int startIndex = Math.Min(location.Column - 1, lineText.Length - 1);
320
while (startIndex >= 0 && lineText [startIndex] != '<') {
322
if (lineText [startIndex] == '/') {
329
if (startIndex >= 0) {
330
int endIndex = startIndex;
331
while (endIndex <= location.Column && endIndex < lineText.Length && !Char.IsWhiteSpace (lineText [endIndex])) {
334
string tag = endIndex - startIndex - 1 > 0 ? lineText.Substring(
336
endIndex - startIndex - 2
338
if (!string.IsNullOrEmpty(tag) && commentTags.IndexOf(tag) >= 0) {
339
document.Insert(offset, "</" + tag + ">");
344
// Parameter completion
346
if (IsInsideCommentStringOrDirective()) {
349
var invoke = GetInvocationBeforeCursor(true);
350
if (invoke == null) {
352
return DefaultControlSpaceItems(invoke);
355
if (invoke.Node is TypeOfExpression) {
356
return CreateTypeList();
358
var invocationResult = ResolveExpression(invoke);
359
if (invocationResult == null) {
362
var methodGroup = invocationResult.Item1 as MethodGroupResolveResult;
363
if (methodGroup != null) {
364
return CreateParameterCompletion(
366
invocationResult.Item2,
375
return DefaultControlSpaceItems(invoke);
379
return controlSpace ? DefaultControlSpaceItems() : null;
382
if (!GetParameterCompletionCommandOffset(out cpos2)) {
385
// completionContext = CompletionWidget.CreateCodeCompletionContext (cpos2);
386
// int currentParameter2 = MethodParameterDataProvider.GetCurrentParameterIndex (CompletionWidget, completionContext) - 1;
387
// return CreateParameterCompletion (CreateResolver (), location, ExpressionContext.MethodBody, provider.Methods, currentParameter);
390
// Completion on space:
392
int tokenIndex = offset;
393
string token = GetPreviousToken(ref tokenIndex, false);
394
if (IsInsideCommentStringOrDirective()) {
395
if (IsInPreprocessorDirective())
396
return HandleKeywordCompletion(tokenIndex, token);
399
// check propose name, for context <variable name> <ctrl+space> (but only in control space context)
400
//IType isAsType = null;
401
var isAsExpression = GetExpressionAt(offset);
402
if (controlSpace && isAsExpression != null && isAsExpression.Node is VariableDeclarationStatement && token != "new") {
403
var parent = isAsExpression.Node as VariableDeclarationStatement;
404
var proposeNameList = new CompletionDataWrapper(this);
405
if (parent.Variables.Count != 1)
406
return DefaultControlSpaceItems(isAsExpression, controlSpace);
408
foreach (var possibleName in GenerateNameProposals (parent.Type)) {
409
if (possibleName.Length > 0) {
410
proposeNameList.Result.Add(factory.CreateLiteralCompletionData(possibleName.ToString()));
415
AutoCompleteEmptyMatch = false;
416
return proposeNameList.Result;
418
// int tokenIndex = offset;
419
// string token = GetPreviousToken (ref tokenIndex, false);
420
// if (result.ExpressionContext == ExpressionContext.ObjectInitializer) {
421
// resolver = CreateResolver ();
422
// ExpressionContext exactContext = new NewCSharpExpressionFinder (dom).FindExactContextForObjectInitializer (document, resolver.Unit, Document.FileName, resolver.CallingType);
423
// IReturnType objectInitializer = ((ExpressionContext.TypeExpressionContext)exactContext).UnresolvedType;
424
// if (objectInitializer != null && objectInitializer.ArrayDimensions == 0 && objectInitializer.PointerNestingLevel == 0 && (token == "{" || token == ","))
425
// return CreateCtrlSpaceCompletionData (completionContext, result);
429
string prevToken = GetPreviousToken(ref j, false);
430
if (prevToken == "=" || prevToken == "+" || prevToken == "-") {
431
token = prevToken + token;
439
if (!GetParameterCompletionCommandOffset(out cpos)) {
442
int currentParameter = GetCurrentParameterIndex(cpos - 1, this.offset) - 1;
443
if (currentParameter < 0) {
446
invoke = GetInvocationBeforeCursor(token == "(");
447
if (invoke == null) {
450
invocationResult = ResolveExpression(invoke);
451
if (invocationResult == null) {
454
methodGroup = invocationResult.Item1 as MethodGroupResolveResult;
455
if (methodGroup != null) {
456
return CreateParameterCompletion(
458
invocationResult.Item2,
467
GetPreviousToken(ref tokenIndex, false);
468
var expressionOrVariableDeclaration = GetExpressionAt(tokenIndex);
469
if (expressionOrVariableDeclaration == null) {
473
resolveResult = ResolveExpression(expressionOrVariableDeclaration);
475
if (resolveResult == null) {
478
if (resolveResult.Item1.Type.Kind == TypeKind.Enum) {
479
var wrapper = new CompletionDataWrapper(this);
480
AddContextCompletion(
483
expressionOrVariableDeclaration.Node,
484
expressionOrVariableDeclaration.Unit);
485
AddEnumMembers(wrapper, resolveResult.Item1.Type, resolveResult.Item2);
486
AutoCompleteEmptyMatch = false;
487
return wrapper.Result;
490
// if (resolvedType.FullName == DomReturnType.Bool.FullName) {
491
// CompletionDataList completionList = new ProjectDomCompletionDataList ();
492
// CompletionDataCollector cdc = new CompletionDataCollector (this, dom, completionList, Document.CompilationUnit, resolver.CallingType, location);
493
// completionList.AutoCompleteEmptyMatch = false;
494
// cdc.Add ("true", "md-keyword");
495
// cdc.Add ("false", "md-keyword");
496
// resolver.AddAccessibleCodeCompletionData (result.ExpressionContext, cdc);
497
// return completionList;
499
// if (resolvedType.ClassType == ClassType.Delegate && token == "=") {
500
// CompletionDataList completionList = new ProjectDomCompletionDataList ();
501
// string parameterDefinition = AddDelegateHandlers (completionList, resolvedType);
502
// string varName = GetPreviousMemberReferenceExpression (tokenIndex);
503
// completionList.Add (new EventCreationCompletionData (document, varName, resolvedType, null, parameterDefinition, resolver.CallingMember, resolvedType));
505
// CompletionDataCollector cdc = new CompletionDataCollector (this, dom, completionList, Document.CompilationUnit, resolver.CallingType, location);
506
// resolver.AddAccessibleCodeCompletionData (result.ExpressionContext, cdc);
507
// foreach (var data in completionList) {
508
// if (data is MemberCompletionData)
509
// ((MemberCompletionData)data).IsDelegateExpected = true;
511
// return completionList;
516
GetPreviousToken(ref tokenIndex, false);
518
expressionOrVariableDeclaration = GetExpressionAt(tokenIndex);
519
if (expressionOrVariableDeclaration == null) {
523
resolveResult = ResolveExpression(expressionOrVariableDeclaration);
524
if (resolveResult == null) {
529
var mrr = resolveResult.Item1 as MemberResolveResult;
531
var evt = mrr.Member as IEvent;
535
var delegateType = evt.ReturnType;
536
if (delegateType.Kind != TypeKind.Delegate) {
540
var wrapper = new CompletionDataWrapper(this);
541
if (currentType != null) {
542
// bool includeProtected = DomType.IncludeProtected (dom, typeFromDatabase, resolver.CallingType);
543
foreach (var method in currentType.Methods) {
544
if (MatchDelegate(delegateType, method) /*&& method.IsAccessibleFrom (dom, resolver.CallingType, resolver.CallingMember, includeProtected) &&*/) {
545
wrapper.AddMember(method);
546
// data.SetText (data.CompletionText + ";");
551
string parameterDefinition = AddDelegateHandlers(
555
string varName = GetPreviousMemberReferenceExpression(tokenIndex);
557
factory.CreateEventCreationCompletionData(
567
return wrapper.Result;
571
if (currentMember == null) {
572
token = GetPreviousToken(ref tokenIndex, false);
573
token = GetPreviousToken(ref tokenIndex, false);
575
return HandleEnumContext();
576
var wrapper = new CompletionDataWrapper(this);
578
AddTypesAndNamespaces(
582
t => currentType != null && !currentType.ReflectionName.Equals(t.ReflectionName) ? t : null
584
return wrapper.Result;
589
var keywordCompletion = HandleKeywordCompletion(tokenIndex, token);
590
if (keywordCompletion == null && controlSpace) {
593
return keywordCompletion;
594
// Automatic completion
596
if (IsInsideCommentStringOrDirective()) {
599
if (IsInLinqContext(offset)) {
600
if (!controlSpace && !(char.IsLetter(completionChar) || completionChar == '_')) {
604
token = GetPreviousToken(ref tokenIndex, false);
606
if (!char.IsWhiteSpace(completionChar) && !linqKeywords.Contains(token)) {
607
token = GetPreviousToken(ref tokenIndex, false);
611
if (linqKeywords.Contains(token)) {
612
if (token == "from") {
613
// after from no auto code completion.
616
return DefaultControlSpaceItems();
618
var dataList = new CompletionDataWrapper(this);
619
AddKeywords(dataList, linqKeywords);
620
return dataList.Result;
622
if (currentType != null && currentType.Kind == TypeKind.Enum) {
623
return HandleEnumContext();
625
var contextList = new CompletionDataWrapper(this);
626
var identifierStart = GetExpressionAtCursor();
627
if (identifierStart != null) {
628
if (identifierStart.Node is TypeParameterDeclaration) {
632
if (identifierStart.Node is MemberReferenceExpression) {
633
return HandleMemberReferenceCompletion(
634
new ExpressionResult(
635
((MemberReferenceExpression)identifierStart.Node).Target,
641
if (identifierStart.Node is Identifier) {
642
// May happen in variable names
643
return controlSpace ? DefaultControlSpaceItems(identifierStart) : null;
645
if (identifierStart.Node is VariableInitializer && location <= ((VariableInitializer)identifierStart.Node).NameToken.EndLocation) {
646
return controlSpace ? HandleAccessorContext() ?? DefaultControlSpaceItems(identifierStart) : null;
649
if (identifierStart.Node is CatchClause) {
650
if (((CatchClause)identifierStart.Node).VariableNameToken.Contains(location)) {
653
return HandleCatchClauseType(identifierStart);
656
if (!(char.IsLetter(completionChar) || completionChar == '_') && (!controlSpace || identifierStart == null || !(identifierStart.Node.Parent is ArrayInitializerExpression))) {
657
return controlSpace ? HandleAccessorContext() ?? DefaultControlSpaceItems(identifierStart) : null;
660
char prevCh = offset > 2 ? document.GetCharAt(offset - 2) : ';';
661
char nextCh = offset < document.TextLength ? document.GetCharAt(offset) : ' ';
662
const string allowedChars = ";,.[](){}+-*/%^?:&|~!<>=";
663
if (!Char.IsWhiteSpace(nextCh) && allowedChars.IndexOf(nextCh) < 0) {
666
if (!(Char.IsWhiteSpace(prevCh) || allowedChars.IndexOf(prevCh) >= 0)) {
670
// Do not pop up completion on identifier identifier (should be handled by keyword completion).
671
tokenIndex = offset - 1;
672
token = GetPreviousToken(ref tokenIndex, false);
673
if (token == "class" || token == "interface" || token == "struct" || token == "enum" || token == "namespace") {
674
// after these always follows a name
677
var keywordresult = HandleKeywordCompletion(tokenIndex, token);
678
if (keywordresult != null) {
679
return keywordresult;
682
int prevTokenIndex = tokenIndex;
683
var prevToken2 = GetPreviousToken(ref prevTokenIndex, false);
684
if (prevToken2 == "delegate") {
685
// after these always follows a name
689
if (identifierStart == null && !string.IsNullOrEmpty(token) && !IsInsideCommentStringOrDirective() && (prevToken2 == ";" || prevToken2 == "{" || prevToken2 == "}")) {
690
char last = token [token.Length - 1];
691
if (char.IsLetterOrDigit(last) || last == '_' || token == ">") {
692
return HandleKeywordCompletion(tokenIndex, token);
696
if (identifierStart == null) {
697
var accCtx = HandleAccessorContext();
698
if (accCtx != null) {
701
return DefaultControlSpaceItems(null, controlSpace);
703
CSharpResolver csResolver;
704
AstNode n = identifierStart.Node;
705
if (n != null && n.Parent is AnonymousTypeCreateExpression) {
709
// Handle foreach (type name _
710
if (n is IdentifierExpression) {
711
var prev = n.GetPrevNode() as ForeachStatement;
712
if (prev != null && prev.InExpression.IsNull) {
714
contextList.AddCustom("in");
715
return contextList.Result;
720
// var astResolver = new CSharpAstResolver(
722
// identifierStart.Unit,
726
// foreach (var type in CreateFieldAction.GetValidTypes(astResolver, (Expression)n)) {
727
// if (type.Kind == TypeKind.Delegate) {
728
// AddDelegateHandlers(contextList, type, false, false);
729
// AutoSelect = false;
730
// AutoCompleteEmptyMatch = false;
735
// Handle object/enumerable initialzer expressions: "new O () { P$"
736
if (n is IdentifierExpression && n.Parent is ArrayInitializerExpression) {
737
var result = HandleObjectInitializer(identifierStart.Unit, n);
742
if (n != null && n.Parent is InvocationExpression) {
743
var invokeParent = (InvocationExpression)n.Parent;
744
var invokeResult = ResolveExpression(
748
var mgr = invokeResult != null ? invokeResult.Item1 as MethodGroupResolveResult : null;
751
foreach (var arg in invokeParent.Arguments) {
758
foreach (var method in mgr.Methods) {
759
if (idx < method.Parameters.Count && method.Parameters [idx].Type.Kind == TypeKind.Delegate) {
761
AutoCompleteEmptyMatch = false;
763
foreach (var p in method.Parameters) {
764
contextList.AddNamedParameterVariable(p);
768
foreach (var list in mgr.GetExtensionMethods ()) {
769
foreach (var method in list) {
770
if (idx < method.Parameters.Count && method.Parameters [idx].Type.Kind == TypeKind.Delegate) {
772
AutoCompleteEmptyMatch = false;
779
if (n != null && n.Parent is ObjectCreateExpression) {
780
var invokeResult = ResolveExpression(n.Parent, identifierStart.Unit);
781
var mgr = invokeResult != null ? invokeResult.Item1 as ResolveResult : null;
783
foreach (var constructor in mgr.Type.GetConstructors ()) {
784
foreach (var p in constructor.Parameters) {
785
contextList.AddVariable(p);
791
if (n is IdentifierExpression) {
792
var bop = n.Parent as BinaryOperatorExpression;
793
Expression evaluationExpr = null;
795
if (bop != null && bop.Right == n && (bop.Operator == BinaryOperatorType.Equality || bop.Operator == BinaryOperatorType.InEquality)) {
796
evaluationExpr = bop.Left;
798
// check for compare to enum case
799
if (evaluationExpr != null) {
800
resolveResult = ResolveExpression(evaluationExpr, identifierStart.Unit);
801
if (resolveResult != null && resolveResult.Item1.Type.Kind == TypeKind.Enum) {
802
var wrapper = new CompletionDataWrapper(this);
803
AddContextCompletion(
809
AddEnumMembers(wrapper, resolveResult.Item1.Type, resolveResult.Item2);
810
AutoCompleteEmptyMatch = false;
811
return wrapper.Result;
816
if (n is Identifier && n.Parent is ForeachStatement) {
818
return DefaultControlSpaceItems();
823
if (n is ArrayInitializerExpression) {
824
// check for new [] {...} expression -> no need to resolve the type there
825
var parent = n.Parent as ArrayCreateExpression;
826
if (parent != null && parent.Type.IsNull) {
827
return DefaultControlSpaceItems();
830
var initalizerResult = ResolveExpression(n.Parent, identifierStart.Unit);
832
var concreteNode = identifierStart.Unit.GetNodeAt<IdentifierExpression>(location);
833
// check if we're on the right side of an initializer expression
834
if (concreteNode != null && concreteNode.Parent != null && concreteNode.Parent.Parent != null && concreteNode.Identifier != "a" && concreteNode.Parent.Parent is NamedExpression) {
835
return DefaultControlSpaceItems();
837
if (initalizerResult != null && initalizerResult.Item1.Type.Kind != TypeKind.Unknown) {
839
foreach (var property in initalizerResult.Item1.Type.GetProperties ()) {
840
if (!property.IsPublic) {
843
contextList.AddMember(property);
845
foreach (var field in initalizerResult.Item1.Type.GetFields ()) {
846
if (!field.IsPublic) {
849
contextList.AddMember(field);
851
return contextList.Result;
853
return DefaultControlSpaceItems();
855
if (IsAttributeContext(n)) {
856
// add attribute targets
857
if (currentType == null) {
858
contextList.AddCustom("assembly");
859
contextList.AddCustom("module");
860
contextList.AddCustom("type");
862
contextList.AddCustom("param");
863
contextList.AddCustom("field");
864
contextList.AddCustom("property");
865
contextList.AddCustom("method");
866
contextList.AddCustom("event");
868
contextList.AddCustom("return");
870
if (n is MemberType) {
871
resolveResult = ResolveExpression(
872
((MemberType)n).Target,
875
return CreateTypeAndNamespaceCompletionData(
878
((MemberType)n).Target,
882
if (n != null/* && !(identifierStart.Item2 is TypeDeclaration)*/) {
883
csResolver = new CSharpResolver(ctx);
884
var nodes = new List<AstNode>();
886
if (n.Parent is ICSharpCode.NRefactory.CSharp.Attribute) {
889
var astResolver = new CSharpAstResolver(
891
identifierStart.Unit,
894
astResolver.ApplyNavigator(new NodeListResolveVisitorNavigator(nodes));
896
csResolver = astResolver.GetResolverStateBefore(n);
897
} catch (Exception) {
898
csResolver = GetState();
900
// add attribute properties.
901
if (n.Parent is ICSharpCode.NRefactory.CSharp.Attribute) {
902
var resolved = astResolver.Resolve(n.Parent);
903
if (resolved != null && resolved.Type != null) {
904
foreach (var property in resolved.Type.GetProperties (p => p.Accessibility == Accessibility.Public)) {
905
contextList.AddMember(property);
907
foreach (var field in resolved.Type.GetFields (p => p.Accessibility == Accessibility.Public)) {
908
contextList.AddMember(field);
913
csResolver = GetState();
915
// identifier has already started with the first letter
917
AddContextCompletion(
920
identifierStart.Node,
923
return contextList.Result;
924
// if (stub.Parent is BlockStatement)
926
// result = FindExpression (dom, completionContext, -1);
927
// if (result == null)
929
// else if (result.ExpressionContext != ExpressionContext.IdentifierExpected) {
930
// triggerWordLength = 1;
931
// bool autoSelect = true;
932
// IType returnType = null;
933
// if ((prevCh == ',' || prevCh == '(') && GetParameterCompletionCommandOffset (out cpos)) {
934
// ctx = CompletionWidget.CreateCodeCompletionContext (cpos);
935
// NRefactoryParameterDataProvider dataProvider = ParameterCompletionCommand (ctx) as NRefactoryParameterDataProvider;
936
// if (dataProvider != null) {
937
// int i = dataProvider.GetCurrentParameterIndex (CompletionWidget, ctx) - 1;
938
// foreach (var method in dataProvider.Methods) {
939
// if (i < method.Parameters.Count) {
940
// returnType = dom.GetType (method.Parameters [i].ReturnType);
941
// autoSelect = returnType == null || returnType.ClassType != ClassType.Delegate;
947
// // Bug 677531 - Auto-complete doesn't always highlight generic parameter in method signature
948
// //if (result.ExpressionContext == ExpressionContext.TypeName)
949
// // autoSelect = false;
950
// CompletionDataList dataList = CreateCtrlSpaceCompletionData (completionContext, result);
951
// AddEnumMembers (dataList, returnType);
952
// dataList.AutoSelect = autoSelect;
955
// result = FindExpression (dom, completionContext, 0);
956
// tokenIndex = offset;
958
// // check foreach case, unfortunately the expression finder is too dumb to handle full type names
959
// // should be overworked if the expression finder is replaced with a mcs ast based analyzer.
960
// var possibleForeachToken = GetPreviousToken (ref tokenIndex, false); // starting letter
961
// possibleForeachToken = GetPreviousToken (ref tokenIndex, false); // varname
963
// // read return types to '(' token
964
// possibleForeachToken = GetPreviousToken (ref tokenIndex, false); // varType
965
// if (possibleForeachToken == ">") {
966
// while (possibleForeachToken != null && possibleForeachToken != "(") {
967
// possibleForeachToken = GetPreviousToken (ref tokenIndex, false);
970
// possibleForeachToken = GetPreviousToken (ref tokenIndex, false); // (
971
// if (possibleForeachToken == ".")
972
// while (possibleForeachToken != null && possibleForeachToken != "(")
973
// possibleForeachToken = GetPreviousToken (ref tokenIndex, false);
975
// possibleForeachToken = GetPreviousToken (ref tokenIndex, false); // foreach
977
// if (possibleForeachToken == "foreach") {
978
// result.ExpressionContext = ExpressionContext.ForeachInToken;
981
// // result.ExpressionContext = ExpressionContext.IdentifierExpected;
983
// result.Expression = "";
984
// result.Region = DomRegion.Empty;
986
// return CreateCtrlSpaceCompletionData (completionContext, result);
993
IEnumerable<ICompletionData> HandleCatchClauseType(ExpressionResult identifierStart)
995
Func<IType, IType> typePred = delegate (IType type) {
996
if (type.GetAllBaseTypes().Any(t => t.ReflectionName == "System.Exception"))
1000
if (identifierStart.Node is CatchClause) {
1001
var wrapper = new CompletionDataWrapper(this);
1002
AddTypesAndNamespaces(
1005
identifierStart.Node,
1009
return wrapper.Result;
1012
var resolveResult = ResolveExpression(identifierStart);
1013
return CreateCompletionData(
1015
resolveResult.Item1,
1016
identifierStart.Node,
1017
resolveResult.Item2,
1022
string[] validEnumBaseTypes = {
1033
IEnumerable<ICompletionData> HandleEnumContext()
1035
var cu = ParseStub("a", false);
1040
var curType = cu.GetNodeAt<TypeDeclaration>(location);
1041
if (curType == null || curType.ClassType != ClassType.Enum) {
1042
cu = ParseStub("a {}", false);
1043
var node = cu.GetNodeAt<AstType>(location);
1045
var wrapper = new CompletionDataWrapper(this);
1046
AddKeywords(wrapper, validEnumBaseTypes);
1047
return wrapper.Result;
1051
var member = cu.GetNodeAt<EnumMemberDeclaration>(location);
1052
if (member != null && member.NameToken.EndLocation < location) {
1053
return DefaultControlSpaceItems();
1058
bool IsInLinqContext(int offset)
1061
while (null != (token = GetPreviousToken (ref offset, true)) && !IsInsideCommentStringOrDirective ()) {
1063
if (token == "from") {
1064
return !IsInsideCommentStringOrDirective(offset);
1066
if (token == ";" || token == "{") {
1073
IEnumerable<ICompletionData> HandleAccessorContext()
1075
var unit = ParseStub("get; }", false);
1076
var node = unit.GetNodeAt(location, cn => !(cn is CSharpTokenNode));
1077
if (node is Accessor) {
1080
var contextList = new CompletionDataWrapper(this);
1081
if (node is PropertyDeclaration) {
1082
contextList.AddCustom("get");
1083
contextList.AddCustom("set");
1084
AddKeywords(contextList, accessorModifierKeywords);
1085
} else if (node is CustomEventDeclaration) {
1086
contextList.AddCustom("add");
1087
contextList.AddCustom("remove");
1092
return contextList.Result;
1095
IEnumerable<ICompletionData> DefaultControlSpaceItems(ExpressionResult xp = null, bool controlSpace = true)
1097
var wrapper = new CompletionDataWrapper(this);
1098
if (offset >= document.TextLength) {
1099
offset = document.TextLength - 1;
1101
while (offset > 1 && char.IsWhiteSpace (document.GetCharAt (offset))) {
1104
location = document.GetLocation(offset);
1107
xp = GetExpressionAtCursor();
1110
CompilationUnit unit;
1111
Tuple<ResolveResult, CSharpResolver> rr;
1114
rr = ResolveExpression(node, xp.Unit);
1117
unit = ParseStub("foo", false);
1118
node = unit.GetNodeAt(
1120
location.Column + 2,
1121
n => n is Expression || n is AstType
1123
rr = ResolveExpression(node, unit);
1125
if (node is Identifier && node.Parent is ForeachStatement) {
1126
var foreachStmt = (ForeachStatement)node.Parent;
1127
foreach (var possibleName in GenerateNameProposals (foreachStmt.VariableType)) {
1128
if (possibleName.Length > 0) {
1129
wrapper.Result.Add(factory.CreateLiteralCompletionData(possibleName.ToString()));
1134
AutoCompleteEmptyMatch = false;
1135
return wrapper.Result;
1138
if (node is Identifier && node.Parent is ParameterDeclaration) {
1139
if (!controlSpace) {
1142
// Try Parameter name case
1143
var param = node.Parent as ParameterDeclaration;
1144
if (param != null) {
1145
foreach (var possibleName in GenerateNameProposals (param.Type)) {
1146
if (possibleName.Length > 0) {
1147
wrapper.Result.Add(factory.CreateLiteralCompletionData(possibleName.ToString()));
1151
AutoCompleteEmptyMatch = false;
1152
return wrapper.Result;
1155
if (Unit != null && (node == null || node is TypeDeclaration)) {
1156
var constructor = Unit.GetNodeAt<ConstructorDeclaration>(
1160
if (constructor != null && !constructor.ColonToken.IsNull && constructor.Initializer.IsNull) {
1161
wrapper.AddCustom("this");
1162
wrapper.AddCustom("base");
1163
return wrapper.Result;
1167
var initializer = node != null ? node.Parent as ArrayInitializerExpression : null;
1168
if (initializer != null) {
1169
var result = HandleObjectInitializer(unit, initializer);
1173
CSharpResolver csResolver = null;
1175
csResolver = rr.Item2;
1177
if (csResolver == null) {
1179
csResolver = GetState();
1180
//var astResolver = new CSharpAstResolver (csResolver, node, xp != null ? xp.Item1 : CSharpParsedFile);
1183
//csResolver = astResolver.GetResolverStateBefore (node);
1184
Console.WriteLine(csResolver.LocalVariables.Count());
1185
} catch (Exception e) {
1186
Console.WriteLine("E!!!" + e);
1190
csResolver = GetState();
1193
AddContextCompletion(wrapper, csResolver, node, unit);
1195
return wrapper.Result;
1198
void AddContextCompletion(CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, CompilationUnit unit)
1200
if (state != null && !(node is AstType)) {
1201
foreach (var variable in state.LocalVariables) {
1202
if (variable.Region.IsInside(location.Line, location.Column - 1)) {
1205
wrapper.AddVariable(variable);
1209
if (currentMember is IUnresolvedParameterizedMember && !(node is AstType)) {
1210
var param = (IParameterizedMember)currentMember.CreateResolved(ctx);
1211
foreach (var p in param.Parameters) {
1212
wrapper.AddVariable(p);
1216
if (currentMember is IUnresolvedMethod) {
1217
var method = (IUnresolvedMethod)currentMember;
1218
foreach (var p in method.TypeParameters) {
1219
wrapper.AddTypeParameter(p);
1223
Func<IType, IType> typePred = null;
1224
if (IsAttributeContext(node)) {
1225
var attribute = Compilation.FindType(KnownTypeCode.Attribute);
1227
return t.GetAllBaseTypeDefinitions().Any(bt => bt.Equals(attribute)) ? t : null;
1230
AddTypesAndNamespaces(wrapper, state, node, typePred);
1232
wrapper.Result.Add(factory.CreateLiteralCompletionData("global"));
1234
if (!(node is AstType)) {
1235
if (currentMember != null || node is Expression) {
1236
AddKeywords(wrapper, statementStartKeywords);
1237
AddKeywords(wrapper, expressionLevelKeywords);
1238
if (node is TypeDeclaration)
1239
AddKeywords(wrapper, typeLevelKeywords);
1240
} else if (currentType != null) {
1241
AddKeywords(wrapper, typeLevelKeywords);
1243
AddKeywords(wrapper, globalLevelKeywords);
1245
var prop = currentMember as IUnresolvedProperty;
1246
if (prop != null && prop.Setter != null && prop.Setter.Region.IsInside(location)) {
1247
wrapper.AddCustom("value");
1249
if (currentMember is IUnresolvedEvent) {
1250
wrapper.AddCustom("value");
1253
if (IsInSwitchContext(node)) {
1254
wrapper.AddCustom("case");
1257
if (((AstType)node).Parent is ParameterDeclaration) {
1258
AddKeywords(wrapper, parameterTypePredecessorKeywords);
1262
AddKeywords(wrapper, primitiveTypesKeywords);
1263
if (currentMember != null) {
1264
wrapper.AddCustom("var");
1266
wrapper.Result.AddRange(factory.CreateCodeTemplateCompletionData());
1268
if (node != null && node.Role == Roles.Argument) {
1269
var resolved = ResolveExpression(node.Parent, unit);
1270
var invokeResult = resolved != null ? resolved.Item1 as CSharpInvocationResolveResult : null;
1271
if (invokeResult != null) {
1273
foreach (var arg in node.Parent.Children.Where (c => c.Role == Roles.Argument)) {
1279
var param = argNum < invokeResult.Member.Parameters.Count ? invokeResult.Member.Parameters [argNum] : null;
1280
if (param != null && param.Type.Kind == TypeKind.Enum) {
1281
AddEnumMembers(wrapper, param.Type, state);
1286
if (node is Expression) {
1287
var astResolver = new CSharpAstResolver(state, unit, CSharpParsedFile);
1288
foreach (var type in CreateFieldAction.GetValidTypes(astResolver, (Expression)node)) {
1289
if (type.Kind == TypeKind.Enum) {
1290
AddEnumMembers(wrapper, type, state);
1291
} else if (type.Kind == TypeKind.Delegate) {
1292
AddDelegateHandlers(wrapper, type, true, true);
1294
AutoCompleteEmptyMatch = false;
1299
// Add 'this' keyword for first parameter (extension method case)
1300
if (node != null && node.Parent is ParameterDeclaration &&
1301
node.Parent.PrevSibling != null && node.Parent.PrevSibling.Role == Roles.LPar) {
1302
wrapper.AddCustom("this");
1306
static bool IsInSwitchContext(AstNode node)
1309
while (n != null && !(n is EntityDeclaration)) {
1310
if (n is SwitchStatement) {
1313
if (n is BlockStatement) {
1321
void AddTypesAndNamespaces(CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, Func<IType, IType> typePred = null, Predicate<IMember> memberPred = null, Action<ICompletionData, IType> callback = null)
1323
var lookup = new MemberLookup(
1324
ctx.CurrentTypeDefinition,
1325
Compilation.MainAssembly
1327
if (currentType != null) {
1328
for (var ct = currentType; ct != null; ct = ct.DeclaringTypeDefinition) {
1329
foreach (var nestedType in ct.NestedTypes) {
1330
string name = nestedType.Name;
1331
if (IsAttributeContext(node) && name.EndsWith("Attribute") && name.Length > "Attribute".Length) {
1332
name = name.Substring(0, name.Length - "Attribute".Length);
1335
if (typePred == null) {
1336
wrapper.AddType(nestedType, name);
1340
var type = typePred(nestedType.Resolve(ctx));
1342
var a2 = wrapper.AddType(type, name);
1343
if (a2 != null && callback != null) {
1350
if (this.currentMember != null && !(node is AstType)) {
1351
var def = ctx.CurrentTypeDefinition ?? Compilation.MainAssembly.GetTypeDefinition(currentType);
1353
bool isProtectedAllowed = true;
1354
foreach (var member in def.GetMembers ()) {
1355
if (member is IMethod && ((IMethod)member).FullName == "System.Object.Finalize") {
1358
if (member.EntityType == EntityType.Operator) {
1361
if (member.IsExplicitInterfaceImplementation) {
1364
if (!lookup.IsAccessible(member, isProtectedAllowed)) {
1368
if (memberPred == null || memberPred(member)) {
1369
wrapper.AddMember(member);
1372
var declaring = def.DeclaringTypeDefinition;
1373
while (declaring != null) {
1374
foreach (var member in declaring.GetMembers (m => m.IsStatic)) {
1375
if (memberPred == null || memberPred(member)) {
1376
wrapper.AddMember(member);
1379
declaring = declaring.DeclaringTypeDefinition;
1383
foreach (var p in currentType.TypeParameters) {
1384
wrapper.AddTypeParameter(p);
1387
var scope = CSharpParsedFile.GetUsingScope(location).Resolve(Compilation);
1389
for (var n = scope; n != null; n = n.Parent) {
1390
foreach (var pair in n.UsingAliases) {
1391
wrapper.AddNamespace(pair.Key);
1393
foreach (var u in n.Usings) {
1394
foreach (var type in u.Types) {
1395
if (!lookup.IsAccessible(type, false))
1398
IType addType = typePred != null ? typePred(type) : type;
1399
if (addType != null) {
1400
string name = type.Name;
1401
if (IsAttributeContext(node) && name.EndsWith("Attribute") && name.Length > "Attribute".Length) {
1402
name = name.Substring(0, name.Length - "Attribute".Length);
1404
var a = wrapper.AddType(addType, name);
1405
if (a != null && callback != null) {
1412
foreach (var type in n.Namespace.Types) {
1413
if (!lookup.IsAccessible(type, false))
1415
IType addType = typePred != null ? typePred(type) : type;
1416
if (addType != null) {
1417
var a2 = wrapper.AddType(addType, addType.Name);
1418
if (a2 != null && callback != null) {
1424
foreach (var curNs in n.Namespace.ChildNamespaces) {
1425
wrapper.AddNamespace(curNs.Name);
1430
IEnumerable<ICompletionData> HandleKeywordCompletion(int wordStart, string word)
1432
if (IsInsideCommentStringOrDirective()) {
1433
if (IsInPreprocessorDirective()) {
1434
if (word == "if" || word == "elif") {
1435
if (wordStart > 0 && document.GetCharAt(wordStart - 1) == '#') {
1436
return factory.CreatePreProcessorDefinesCompletionData();
1446
if (currentType != null) {
1449
var wrapper = new CompletionDataWrapper(this);
1450
AddTypesAndNamespaces(wrapper, GetState(), null, t => null);
1451
return wrapper.Result;
1453
return CreateCaseCompletionData(location);
1456
// if (result.ExpressionContext == ExpressionContext.InheritableType) {
1457
// IType cls = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new TextLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
1458
// CompletionDataList completionList = new ProjectDomCompletionDataList ();
1459
// List<string > namespaceList = GetUsedNamespaces ();
1460
// var col = new CSharpTextEditorCompletion.CompletionDataCollector (this, dom, completionList, Document.CompilationUnit, null, location);
1461
// bool isInterface = false;
1462
// HashSet<string > baseTypeNames = new HashSet<string> ();
1463
// if (cls != null) {
1464
// baseTypeNames.Add (cls.Name);
1465
// if (cls.ClassType == ClassType.Struct)
1466
// isInterface = true;
1468
// int tokenIndex = offset;
1470
// // Search base types " : [Type1, ... ,TypeN,] <Caret>"
1471
// string token = null;
1473
// token = GetPreviousToken (ref tokenIndex, false);
1474
// if (string.IsNullOrEmpty (token))
1476
// token = token.Trim ();
1477
// if (Char.IsLetterOrDigit (token [0]) || token [0] == '_') {
1478
// IType baseType = dom.SearchType (Document.CompilationUnit, cls, result.Region.Start, token);
1479
// if (baseType != null) {
1480
// if (baseType.ClassType != ClassType.Interface)
1481
// isInterface = true;
1482
// baseTypeNames.Add (baseType.Name);
1485
// } while (token != ":");
1486
// foreach (object o in dom.GetNamespaceContents (namespaceList, true, true)) {
1487
// IType type = o as IType;
1488
// if (type != null && (type.IsStatic || type.IsSealed || baseTypeNames.Contains (type.Name) || isInterface && type.ClassType != ClassType.Interface)) {
1491
// if (o is Namespace && !namespaceList.Any (ns => ns.StartsWith (((Namespace)o).FullName)))
1495
// // Add inner classes
1496
// Stack<IType > innerStack = new Stack<IType> ();
1497
// innerStack.Push (cls);
1498
// while (innerStack.Count > 0) {
1499
// IType curType = innerStack.Pop ();
1500
// if (curType == null)
1502
// foreach (IType innerType in curType.InnerTypes) {
1503
// if (innerType != cls)
1504
// // don't add the calling class as possible base type
1505
// col.Add (innerType);
1507
// if (curType.DeclaringType != null)
1508
// innerStack.Push (curType.DeclaringType);
1510
// return completionList;
1515
if (currentType == null) {
1518
IType isAsType = null;
1519
var isAsExpression = GetExpressionAt(wordStart);
1520
if (isAsExpression != null) {
1521
var parent = isAsExpression.Node.Parent;
1522
if (parent is VariableInitializer) {
1523
parent = parent.Parent;
1525
if (parent is VariableDeclarationStatement) {
1526
var resolved = ResolveExpression(parent, isAsExpression.Unit);
1527
if (resolved != null) {
1528
isAsType = resolved.Item1.Type;
1532
var isAsWrapper = new CompletionDataWrapper(this);
1533
var def = isAsType != null ? isAsType.GetDefinition() : null;
1534
AddTypesAndNamespaces(
1538
t => t.GetDefinition() == null || def == null || t.GetDefinition().IsDerivedFrom(def) ? t : null,
1540
return isAsWrapper.Result;
1542
// CompletionDataList completionList = new ProjectDomCompletionDataList ();
1543
// ExpressionResult expressionResult = FindExpression (dom, completionContext, wordStart - document.Caret.Offset);
1544
// NRefactoryResolver resolver = CreateResolver ();
1545
// ResolveResult resolveResult = resolver.Resolve (expressionResult, new TextLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
1546
// if (resolveResult != null && resolveResult.ResolvedType != null) {
1547
// CompletionDataCollector col = new CompletionDataCollector (this, dom, completionList, Document.CompilationUnit, resolver.CallingType, location);
1548
// IType foundType = null;
1549
// if (word == "as") {
1550
// ExpressionContext exactContext = new NewCSharpExpressionFinder (dom).FindExactContextForAsCompletion (document, Document.CompilationUnit, Document.FileName, resolver.CallingType);
1551
// if (exactContext is ExpressionContext.TypeExpressionContext) {
1552
// foundType = resolver.SearchType (((ExpressionContext.TypeExpressionContext)exactContext).Type);
1553
// AddAsCompletionData (col, foundType);
1557
// if (foundType == null)
1558
// foundType = resolver.SearchType (resolveResult.ResolvedType);
1560
// if (foundType != null) {
1561
// if (foundType.ClassType == ClassType.Interface)
1562
// foundType = resolver.SearchType (DomReturnType.Object);
1564
// foreach (IType type in dom.GetSubclasses (foundType)) {
1565
// if (type.IsSpecialName || type.Name.StartsWith ("<"))
1567
// AddAsCompletionData (col, type);
1570
// List<string > namespaceList = GetUsedNamespaces ();
1571
// foreach (object o in dom.GetNamespaceContents (namespaceList, true, true)) {
1572
// if (o is IType) {
1573
// IType type = (IType)o;
1574
// if (type.ClassType != ClassType.Interface || type.IsSpecialName || type.Name.StartsWith ("<"))
1576
// // if (foundType != null && !dom.GetInheritanceTree (foundType).Any (x => x.FullName == type.FullName))
1578
// AddAsCompletionData (col, type);
1581
// if (o is Namespace)
1585
// return completionList;
1587
// result.ExpressionContext = ExpressionContext.TypeName;
1588
// return CreateCtrlSpaceCompletionData (completionContext, result);
1591
// Look for modifiers, in order to find the beginning of the declaration
1592
int firstMod = wordStart;
1594
for (int n = 0; n < 3; n++) {
1595
string mod = GetPreviousToken(ref i, true);
1596
if (mod == "public" || mod == "protected" || mod == "private" || mod == "internal" || mod == "sealed") {
1598
} else if (mod == "static") {
1599
// static methods are not overridable
1605
if (!IsLineEmptyUpToEol()) {
1608
if (currentType != null && (currentType.Kind == TypeKind.Class || currentType.Kind == TypeKind.Struct)) {
1609
string modifiers = document.GetText(firstMod, wordStart - firstMod);
1610
return GetOverrideCompletionData(currentType, modifiers);
1614
// Look for modifiers, in order to find the beginning of the declaration
1615
firstMod = wordStart;
1617
for (int n = 0; n < 3; n++) {
1618
string mod = GetPreviousToken(ref i, true);
1619
if (mod == "public" || mod == "protected" || mod == "private" || mod == "internal" || mod == "sealed") {
1621
} else if (mod == "static") {
1622
// static methods are not overridable
1628
if (!IsLineEmptyUpToEol()) {
1631
var state = GetState();
1633
if (state.CurrentTypeDefinition != null && (state.CurrentTypeDefinition.Kind == TypeKind.Class || state.CurrentTypeDefinition.Kind == TypeKind.Struct)) {
1634
string modifiers = document.GetText(firstMod, wordStart - firstMod);
1635
return GetPartialCompletionData(state.CurrentTypeDefinition, modifiers);
1645
var accessorContext = HandleAccessorContext();
1646
if (accessorContext != null) {
1647
return accessorContext;
1649
wrapper = new CompletionDataWrapper(this);
1651
if (currentType != null) {
1652
AddTypesAndNamespaces(wrapper, state, null, null, m => false);
1653
AddKeywords(wrapper, primitiveTypesKeywords);
1655
AddKeywords(wrapper, typeLevelKeywords);
1656
return wrapper.Result;
1659
// string token = GetPreviousToken (ref j, true);
1661
IType hintType = null;
1662
var expressionOrVariableDeclaration = GetNewExpressionAt(j);
1663
if (expressionOrVariableDeclaration == null)
1665
var astResolver = new CSharpAstResolver(
1667
expressionOrVariableDeclaration.Unit,
1670
hintType = CreateFieldAction.GetValidTypes(
1672
expressionOrVariableDeclaration.Node as Expression
1676
return CreateTypeCompletionData(hintType);
1678
var yieldDataList = new CompletionDataWrapper(this);
1679
DefaultCompletionString = "return";
1680
yieldDataList.AddCustom("break");
1681
yieldDataList.AddCustom("return");
1682
return yieldDataList.Result;
1684
var inList = new CompletionDataWrapper(this);
1686
var expr = GetExpressionAtCursor();
1687
var rr = ResolveExpression(expr);
1689
AddContextCompletion(
1691
rr != null ? rr.Item2 : GetState(),
1695
return inList.Result;
1700
bool IsLineEmptyUpToEol()
1702
var line = document.GetLineByNumber(location.Line);
1703
for (int j = offset; j < line.EndOffset; j++) {
1704
char ch = document.GetCharAt(j);
1705
if (!char.IsWhiteSpace(ch)) {
1712
string GetLineIndent(int lineNr)
1714
var line = document.GetLineByNumber(lineNr);
1715
for (int j = line.Offset; j < line.EndOffset; j++) {
1716
char ch = document.GetCharAt(j);
1717
if (!char.IsWhiteSpace(ch)) {
1718
return document.GetText(line.Offset, j - line.Offset - 1);
1724
static CSharpAmbience amb = new CSharpAmbience();
1726
class Category : CompletionCategory
1728
public Category(string displayText, string icon) : base (displayText, icon)
1732
public override int CompareTo(CompletionCategory other)
1738
IEnumerable<ICompletionData> CreateTypeCompletionData(IType hintType)
1740
var wrapper = new CompletionDataWrapper(this);
1741
var state = GetState();
1742
Func<IType, IType> pred = null;
1743
Action<ICompletionData, IType> typeCallback = null;
1744
var inferredTypesCategory = new Category("Inferred Types", null);
1745
var derivedTypesCategory = new Category("Derived Types", null);
1747
if (hintType != null) {
1748
if (hintType.Kind != TypeKind.Unknown) {
1749
var lookup = new MemberLookup(
1750
ctx.CurrentTypeDefinition,
1751
Compilation.MainAssembly
1753
typeCallback = (data, t) => {
1754
//check if type is in inheritance tree.
1755
if (hintType.GetDefinition() != null &&
1756
t.GetDefinition() != null &&
1757
t.GetDefinition().IsDerivedFrom(hintType.GetDefinition())) {
1758
data.CompletionCategory = derivedTypesCategory;
1762
if (t.Kind == TypeKind.Interface && hintType.Kind != TypeKind.Array) {
1765
// check for valid constructors
1766
if (t.GetConstructors().Count() > 0) {
1767
bool isProtectedAllowed = currentType != null ?
1768
currentType.Resolve(ctx).GetDefinition().IsDerivedFrom(t.GetDefinition()) :
1770
if (!t.GetConstructors().Any(m => lookup.IsAccessible(
1779
var typeInference = new TypeInference(Compilation);
1780
typeInference.Algorithm = TypeInferenceAlgorithm.ImprovedReturnAllResults;
1781
var inferedType = typeInference.FindTypeInBounds(
1785
if (inferedType != SpecialType.UnknownType) {
1786
var newType = wrapper.AddType(inferedType, amb.ConvertType(inferedType));
1787
if (newType != null) {
1788
newType.CompletionCategory = inferredTypesCategory;
1794
if (!(hintType.Kind == TypeKind.Interface && hintType.Kind != TypeKind.Array)) {
1795
DefaultCompletionString = GetShortType(hintType, GetState());
1796
var hint = wrapper.AddType(hintType, DefaultCompletionString);
1798
hint.CompletionCategory = derivedTypesCategory;
1801
if (hintType is ParameterizedType && hintType.TypeParameterCount == 1 && hintType.FullName == "System.Collections.Generic.IEnumerable") {
1802
var arg = ((ParameterizedType)hintType).TypeArguments.FirstOrDefault();
1803
var array = new ArrayTypeReference(arg.ToTypeReference(), 1).Resolve(ctx);
1804
wrapper.AddType(array, amb.ConvertType(array));
1807
var hint = wrapper.AddType(hintType, DefaultCompletionString);
1809
DefaultCompletionString = hint.DisplayText;
1810
hint.CompletionCategory = derivedTypesCategory;
1814
AddTypesAndNamespaces(wrapper, state, null, pred, m => false, typeCallback);
1815
if (hintType == null || hintType == SpecialType.UnknownType) {
1816
AddKeywords(wrapper, primitiveTypesKeywords.Where(k => k != "void"));
1819
CloseOnSquareBrackets = true;
1820
AutoCompleteEmptyMatch = true;
1821
return wrapper.Result;
1824
IEnumerable<ICompletionData> GetOverrideCompletionData(IUnresolvedTypeDefinition type, string modifiers)
1826
var wrapper = new CompletionDataWrapper(this);
1827
var alreadyInserted = new List<IMember>();
1828
//bool addedVirtuals = false;
1830
int declarationBegin = offset;
1831
int j = declarationBegin;
1832
for (int i = 0; i < 3; i++) {
1833
switch (GetPreviousToken(ref j, true)) {
1840
declarationBegin = j;
1843
return null; // don't add override completion for static members
1853
return wrapper.Result;
1856
IEnumerable<ICompletionData> GetPartialCompletionData(ITypeDefinition type, string modifiers)
1858
var wrapper = new CompletionDataWrapper(this);
1859
int declarationBegin = offset;
1860
int j = declarationBegin;
1861
for (int i = 0; i < 3; i++) {
1862
switch (GetPreviousToken(ref j, true)) {
1869
declarationBegin = j;
1872
return null; // don't add override completion for static members
1876
var methods = new List<IUnresolvedMethod>();
1878
foreach (var part in type.Parts) {
1879
foreach (var method in part.Methods) {
1880
if (method.BodyRegion.IsEmpty) {
1881
if (GetImplementation(type, method) != null) {
1884
methods.Add(method);
1889
foreach (var method in methods) {
1890
wrapper.Add(factory.CreateNewPartialCompletionData(
1892
method.DeclaringTypeDefinition,
1898
return wrapper.Result;
1901
IMethod GetImplementation(ITypeDefinition type, IUnresolvedMethod method)
1903
foreach (var cur in type.Methods) {
1904
if (cur.Name == method.Name && cur.Parameters.Count == method.Parameters.Count && !cur.BodyRegion.IsEmpty) {
1906
/*for (int i = 0; i < cur.Parameters.Count; i++) {
1907
if (!cur.Parameters [i].Type.Equals (method.Parameters [i].Type)) {
1920
void AddVirtuals(List<IMember> alreadyInserted, CompletionDataWrapper col, string modifiers, IType curType, int declarationBegin)
1922
if (curType == null) {
1925
foreach (var m in curType.GetMembers ().Reverse ()) {
1926
if (m.IsSynthetic || curType.Kind != TypeKind.Interface && !m.IsOverridable) {
1929
// filter out the "Finalize" methods, because finalizers should be done with destructors.
1930
if (m is IMethod && m.Name == "Finalize") {
1934
var data = factory.CreateNewOverrideCompletionData(
1939
// check if the member is already implemented
1940
bool foundMember = curType.GetMembers().Any(cm => SignatureComparer.Ordinal.Equals(
1943
) && cm.DeclaringTypeDefinition == curType.GetDefinition()
1948
if (alreadyInserted.Any(cm => SignatureComparer.Ordinal.Equals(cm, m)))
1950
alreadyInserted.Add(m);
1951
data.CompletionCategory = col.GetCompletionCategory(m.DeclaringTypeDefinition);
1956
static void AddKeywords(CompletionDataWrapper wrapper, IEnumerable<string> keywords)
1958
foreach (string keyword in keywords) {
1959
if (wrapper.Result.Any(data => data.DisplayText == keyword))
1961
wrapper.AddCustom(keyword);
1965
public string GetPreviousMemberReferenceExpression(int tokenIndex)
1967
string result = GetPreviousToken(ref tokenIndex, false);
1968
result = GetPreviousToken(ref tokenIndex, false);
1969
if (result != ".") {
1972
var names = new List<string>();
1973
while (result == ".") {
1974
result = GetPreviousToken(ref tokenIndex, false);
1975
if (result == "this") {
1976
names.Add("handle");
1977
} else if (result != null) {
1978
string trimmedName = result.Trim();
1979
if (trimmedName.Length == 0) {
1982
names.Insert(0, trimmedName);
1984
result = GetPreviousToken(ref tokenIndex, false);
1986
result = String.Join("", names.ToArray());
1987
foreach (char ch in result) {
1988
if (!char.IsLetterOrDigit(ch) && ch != '_') {
1997
bool MatchDelegate(IType delegateType, IUnresolvedMethod method)
1999
var delegateMethod = delegateType.GetDelegateInvokeMethod();
2000
if (delegateMethod == null || delegateMethod.Parameters.Count != method.Parameters.Count) {
2004
for (int i = 0; i < delegateMethod.Parameters.Count; i++) {
2005
if (!delegateMethod.Parameters [i].Type.Equals(method.Parameters [i].Type.Resolve(ctx))) {
2012
string AddDelegateHandlers(CompletionDataWrapper completionList, IType delegateType, bool addSemicolon = true, bool addDefault = true)
2014
IMethod delegateMethod = delegateType.GetDelegateInvokeMethod();
2015
var thisLineIndent = GetLineIndent(location.Line);
2016
string delegateEndString = EolMarker + thisLineIndent + "}" + (addSemicolon ? ";" : "");
2017
//bool containsDelegateData = completionList.Result.Any(d => d.DisplayText.StartsWith("delegate("));
2019
var oldDelegate = completionList.Result.FirstOrDefault(cd => cd.DisplayText == "delegate");
2020
if (oldDelegate != null)
2021
completionList.Result.Remove(oldDelegate);
2022
completionList.AddCustom(
2024
"Creates anonymous delegate.",
2025
"delegate {" + EolMarker + thisLineIndent + IndentString + "|" + delegateEndString
2028
var sb = new StringBuilder("(");
2029
var sbWithoutTypes = new StringBuilder("(");
2030
for (int k = 0; k < delegateMethod.Parameters.Count; k++) {
2033
sbWithoutTypes.Append(", ");
2035
var parameterType = delegateMethod.Parameters [k].Type;
2036
sb.Append(GetShortType(parameterType, GetState()));
2038
sb.Append(delegateMethod.Parameters [k].Name);
2039
sbWithoutTypes.Append(delegateMethod.Parameters [k].Name);
2042
sbWithoutTypes.Append(")");
2043
completionList.AddCustom(
2045
"Creates anonymous delegate.",
2046
"delegate" + sb + " {" + EolMarker + thisLineIndent + IndentString + "|" + delegateEndString
2048
if (!completionList.Result.Any(data => data.DisplayText == sbWithoutTypes.ToString())) {
2049
completionList.AddCustom(
2050
sbWithoutTypes.ToString(),
2051
"Creates lambda expression.",
2052
sbWithoutTypes + " => |" + (addSemicolon ? ";" : "")
2055
/* TODO:Make factory method out of it.
2056
// It's needed to temporarly disable inserting auto matching bracket because the anonymous delegates are selectable with '('
2057
// otherwise we would end up with () => )
2058
if (!containsDelegateData) {
2059
var savedValue = MonoDevelop.SourceEditor.DefaultSourceEditorOptions.Instance.AutoInsertMatchingBracket;
2060
MonoDevelop.SourceEditor.DefaultSourceEditorOptions.Instance.AutoInsertMatchingBracket = false;
2061
completionList.Result.CompletionListClosed += delegate {
2062
MonoDevelop.SourceEditor.DefaultSourceEditorOptions.Instance.AutoInsertMatchingBracket = savedValue;
2065
return sb.ToString();
2068
bool IsAccessibleFrom(IEntity member, ITypeDefinition calledType, IMember currentMember, bool includeProtected)
2070
if (currentMember == null) {
2071
return member.IsStatic || member.IsPublic;
2073
// if (currentMember is MonoDevelop.Projects.Dom.BaseResolveResult.BaseMemberDecorator)
2074
// return member.IsPublic | member.IsProtected;
2075
// if (member.IsStatic && !IsStatic)
2077
if (member.IsPublic || calledType != null && calledType.Kind == TypeKind.Interface && !member.IsProtected) {
2080
if (member.DeclaringTypeDefinition != null) {
2081
if (member.DeclaringTypeDefinition.Kind == TypeKind.Interface) {
2082
return IsAccessibleFrom(
2083
member.DeclaringTypeDefinition,
2090
if (member.IsProtected && !(member.DeclaringTypeDefinition.IsProtectedOrInternal && !includeProtected)) {
2091
return includeProtected;
2094
if (member.IsInternal || member.IsProtectedAndInternal || member.IsProtectedOrInternal) {
2095
//var type1 = member is ITypeDefinition ? (ITypeDefinition)member : member.DeclaringTypeDefinition;
2096
//var type2 = currentMember is ITypeDefinition ? (ITypeDefinition)currentMember : currentMember.DeclaringTypeDefinition;
2098
// easy case, projects are the same
2099
/*// if (type1.ProjectContent == type2.ProjectContent) {
2102
if (type1.ProjectContent != null) {
2103
// maybe type2 hasn't project dom set (may occur in some cases), check if the file is in the project
2105
// result = type1.ProjectContent.Annotation<MonoDevelop.Projects.Project> ().GetProjectFile (type2.Region.FileName) != null;
2107
} else if (type2.ProjectContent != null) {
2109
// result = type2.ProjectContent.Annotation<MonoDevelop.Projects.Project> ().GetProjectFile (type1.Region.FileName) != null;
2112
// should never happen !
2115
return member.IsProtectedAndInternal ? includeProtected && result : result;
2118
if (!(currentMember is IType) && (currentMember.DeclaringTypeDefinition == null || member.DeclaringTypeDefinition == null)) {
2123
var declaringType = currentMember.DeclaringTypeDefinition;
2124
while (declaringType != null) {
2125
if (declaringType.ReflectionName == currentMember.DeclaringType.ReflectionName) {
2128
declaringType = declaringType.DeclaringTypeDefinition;
2132
return currentMember.DeclaringTypeDefinition != null && member.DeclaringTypeDefinition.FullName == currentMember.DeclaringTypeDefinition.FullName;
2135
static bool IsAttributeContext(AstNode node)
2138
while (n is AstType) {
2141
return n is Attribute;
2144
IEnumerable<ICompletionData> CreateTypeAndNamespaceCompletionData(TextLocation location, ResolveResult resolveResult, AstNode resolvedNode, CSharpResolver state)
2146
if (resolveResult == null || resolveResult.IsError) {
2149
var exprParent = resolvedNode.GetParent<Expression>();
2150
var unit = exprParent != null ? exprParent.GetParent<CompilationUnit>() : null;
2152
var astResolver = unit != null ? new CSharpAstResolver(
2157
IType hintType = exprParent != null && astResolver != null ?
2158
CreateFieldAction.GetValidTypes(astResolver, exprParent) .FirstOrDefault() :
2160
var result = new CompletionDataWrapper(this);
2161
if (resolveResult is NamespaceResolveResult) {
2162
var nr = (NamespaceResolveResult)resolveResult;
2163
if (!(resolvedNode.Parent is UsingDeclaration || resolvedNode.Parent != null && resolvedNode.Parent.Parent is UsingDeclaration)) {
2164
foreach (var cl in nr.Namespace.Types) {
2165
string name = cl.Name;
2166
if (hintType != null && hintType.Kind != TypeKind.Array && cl.Kind == TypeKind.Interface) {
2169
if (IsAttributeContext(resolvedNode) && name.EndsWith("Attribute") && name.Length > "Attribute".Length) {
2170
name = name.Substring(0, name.Length - "Attribute".Length);
2172
result.AddType(cl, name);
2175
foreach (var ns in nr.Namespace.ChildNamespaces) {
2176
result.AddNamespace(ns.Name);
2178
} else if (resolveResult is TypeResolveResult) {
2179
var type = resolveResult.Type;
2180
foreach (var nested in type.GetNestedTypes ()) {
2181
if (hintType != null && hintType.Kind != TypeKind.Array && nested.Kind == TypeKind.Interface) {
2184
result.AddType(nested, nested.Name);
2187
return result.Result;
2190
IEnumerable<ICompletionData> CreateTypeList()
2192
foreach (var cl in Compilation.RootNamespace.Types) {
2193
yield return factory.CreateTypeCompletionData(cl, cl.Name);
2196
foreach (var ns in Compilation.RootNamespace.ChildNamespaces) {
2197
yield return factory.CreateNamespaceCompletionData(ns.Name);
2201
IEnumerable<ICompletionData> CreateParameterCompletion(MethodGroupResolveResult resolveResult, CSharpResolver state, AstNode invocation, CompilationUnit unit, int parameter, bool controlSpace)
2203
var result = new CompletionDataWrapper(this);
2204
var addedEnums = new HashSet<string>();
2205
var addedDelegates = new HashSet<string>();
2207
foreach (var method in resolveResult.Methods) {
2208
if (method.Parameters.Count <= parameter) {
2211
var resolvedType = method.Parameters [parameter].Type;
2212
if (resolvedType.Kind == TypeKind.Enum) {
2213
if (addedEnums.Contains(resolvedType.ReflectionName)) {
2216
addedEnums.Add(resolvedType.ReflectionName);
2217
AddEnumMembers(result, resolvedType, state);
2218
} else if (resolvedType.Kind == TypeKind.Delegate) {
2219
if (addedDelegates.Contains(resolvedType.ReflectionName))
2221
string parameterDefinition = AddDelegateHandlers(result, resolvedType);
2222
string varName = "Handle" + method.Parameters [parameter].Type.Name + method.Parameters [parameter].Name;
2224
factory.CreateEventCreationCompletionData(
2228
parameterDefinition,
2234
if (!controlSpace) {
2235
if (addedEnums.Count + addedDelegates.Count == 0) {
2236
return Enumerable.Empty<ICompletionData>();
2238
AutoCompleteEmptyMatch = false;
2241
AddContextCompletion(result, state, invocation, unit);
2243
// resolver.AddAccessibleCodeCompletionData (ExpressionContext.MethodBody, cdc);
2244
// if (addedDelegates.Count > 0) {
2245
// foreach (var data in result.Result) {
2246
// if (data is MemberCompletionData)
2247
// ((MemberCompletionData)data).IsDelegateExpected = true;
2250
return result.Result;
2253
string GetShortType(IType type, CSharpResolver state)
2255
var builder = new TypeSystemAstBuilder(state);
2256
var dt = state.CurrentTypeDefinition;
2257
var declaring = type.DeclaringType != null ? type.DeclaringType.GetDefinition() : null;
2258
if (declaring != null) {
2259
while (dt != null) {
2260
if (dt.Equals(declaring)) {
2261
builder.AlwaysUseShortTypeNames = true;
2264
dt = dt.DeclaringTypeDefinition;
2267
var shortType = builder.ConvertType(type);
2268
return shortType.GetText(FormattingPolicy);
2271
void AddEnumMembers(CompletionDataWrapper completionList, IType resolvedType, CSharpResolver state)
2273
if (resolvedType.Kind != TypeKind.Enum) {
2276
string typeString = GetShortType(resolvedType, state);
2277
if (typeString.Contains(".")) {
2278
completionList.AddType(resolvedType, typeString);
2280
foreach (var field in resolvedType.GetFields ()) {
2281
if (field.IsConst || field.IsStatic) {
2282
completionList.Result.Add(factory.CreateEntityCompletionData(
2284
typeString + "." + field.Name
2289
DefaultCompletionString = typeString;
2292
IEnumerable<ICompletionData> CreateCompletionData(TextLocation location, ResolveResult resolveResult, AstNode resolvedNode, CSharpResolver state, Func<IType, IType> typePred = null)
2294
if (resolveResult == null /*|| resolveResult.IsError*/) {
2298
if (resolveResult is NamespaceResolveResult) {
2299
var nr = (NamespaceResolveResult)resolveResult;
2300
var namespaceContents = new CompletionDataWrapper(this);
2302
foreach (var cl in nr.Namespace.Types) {
2303
IType addType = typePred != null ? typePred(cl) : cl;
2304
if (addType != null)
2305
namespaceContents.AddType(addType, addType.Name);
2308
foreach (var ns in nr.Namespace.ChildNamespaces) {
2309
namespaceContents.AddNamespace(ns.Name);
2311
return namespaceContents.Result;
2314
IType type = resolveResult.Type;
2315
//var typeDef = resolveResult.Type.GetDefinition();
2316
var result = new CompletionDataWrapper(this);
2317
bool includeStaticMembers = false;
2319
var lookup = new MemberLookup(
2320
ctx.CurrentTypeDefinition,
2321
Compilation.MainAssembly
2325
if (resolveResult is LocalResolveResult) {
2326
if (resolvedNode is IdentifierExpression) {
2327
var mrr = (LocalResolveResult)resolveResult;
2328
includeStaticMembers = mrr.Variable.Name == mrr.Type.Name;
2331
if (resolveResult is TypeResolveResult && type.Kind == TypeKind.Enum) {
2332
foreach (var field in type.GetFields ()) {
2333
if (!lookup.IsAccessible(field, false))
2335
result.AddMember(field);
2337
foreach (var m in type.GetMethods ()) {
2338
if (m.Name == "TryParse") {
2339
result.AddMember(m);
2342
return result.Result;
2345
bool isProtectedAllowed = resolveResult is ThisResolveResult ? true : lookup.IsProtectedAccessAllowed(type);
2346
bool skipNonStaticMembers = (resolveResult is TypeResolveResult);
2348
if (resolveResult is MemberResolveResult && resolvedNode is IdentifierExpression) {
2349
var mrr = (MemberResolveResult)resolveResult;
2350
includeStaticMembers = mrr.Member.Name == mrr.Type.Name;
2352
TypeResolveResult trr;
2353
if (state.IsVariableReferenceWithSameType(
2355
((IdentifierExpression)resolvedNode).Identifier,
2358
if (currentMember != null && mrr.Member.IsStatic ^ currentMember.IsStatic) {
2359
skipNonStaticMembers = true;
2361
if (trr.Type.Kind == TypeKind.Enum) {
2362
foreach (var field in trr.Type.GetFields ()) {
2363
result.AddMember(field);
2365
foreach (var m in trr.Type.GetMethods ()) {
2366
if (m.Name == "TryParse" && m.IsStatic) {
2367
result.AddMember(m);
2370
return result.Result;
2375
var scope = CSharpParsedFile.GetUsingScope(location).Resolve(Compilation);
2377
for (var n = scope; n != null; n = n.Parent) {
2378
foreach (var pair in n.UsingAliases) {
2379
if (pair.Key == mrr.Member.Name) {
2380
foreach (var r in CreateCompletionData (location, pair.Value, resolvedNode, state)) {
2381
if (r is IEntityCompletionData && ((IEntityCompletionData)r).Entity is IMember) {
2382
result.AddMember((IMember)((IEntityCompletionData)r).Entity);
2393
if (resolveResult is TypeResolveResult && (resolvedNode is IdentifierExpression || resolvedNode is MemberReferenceExpression)) {
2394
includeStaticMembers = true;
2397
// Console.WriteLine ("type:" + type +"/"+type.GetType ());
2398
// Console.WriteLine ("current:" + ctx.CurrentTypeDefinition);
2399
// Console.WriteLine ("IS PROT ALLOWED:" + isProtectedAllowed + " static: "+ includeStaticMembers);
2400
// Console.WriteLine (resolveResult);
2401
// Console.WriteLine ("node:" + resolvedNode);
2402
// Console.WriteLine (currentMember != null ? currentMember.IsStatic : "currentMember == null");
2404
if (resolvedNode.Annotation<ObjectCreateExpression>() == null) {
2405
//tags the created expression as part of an object create expression.
2407
var filteredList = new List<IMember>();
2408
foreach (var member in type.GetMembers ()) {
2409
if (member.EntityType == EntityType.Indexer || member.EntityType == EntityType.Operator || member.EntityType == EntityType.Constructor || member.EntityType == EntityType.Destructor) {
2412
if (member.IsExplicitInterfaceImplementation) {
2415
// Console.WriteLine ("member:" + member + member.IsShadowing);
2416
if (!lookup.IsAccessible(member, isProtectedAllowed)) {
2417
// Console.WriteLine ("skip access: " + member.FullName);
2420
if (resolvedNode is BaseReferenceExpression && member.IsAbstract) {
2423
bool memberIsStatic = member.IsStatic;
2424
if (!includeStaticMembers && memberIsStatic && !(resolveResult is TypeResolveResult)) {
2425
// Console.WriteLine ("skip static member: " + member.FullName);
2428
var field = member as IField;
2429
if (field != null) {
2430
memberIsStatic |= field.IsConst;
2433
if (!memberIsStatic && skipNonStaticMembers) {
2437
if (member is IMethod && ((IMethod)member).FullName == "System.Object.Finalize") {
2440
if (member.EntityType == EntityType.Operator) {
2443
if (member.IsExplicitInterfaceImplementation) {
2446
if (member.IsShadowing) {
2447
filteredList.RemoveAll(m => m.Name == member.Name);
2449
filteredList.Add(member);
2452
foreach (var member in filteredList) {
2453
// Console.WriteLine ("add:" + member + "/" + member.IsStatic);
2454
result.AddMember(member);
2458
if (resolveResult is TypeResolveResult || includeStaticMembers) {
2459
foreach (var nested in type.GetNestedTypes ()) {
2460
IType addType = typePred != null ? typePred(nested) : nested;
2461
if (addType != null)
2462
result.AddType(addType, addType.Name);
2466
foreach (var meths in state.GetExtensionMethods (type)) {
2467
foreach (var m in meths) {
2468
result.AddMember(m);
2473
// IEnumerable<object> objects = resolveResult.CreateResolveResult (dom, resolver != null ? resolver.CallingMember : null);
2474
// CompletionDataCollector col = new CompletionDataCollector (this, dom, result, Document.CompilationUnit, resolver != null ? resolver.CallingType : null, location);
2475
// col.HideExtensionParameter = !resolveResult.StaticResolve;
2476
// col.NamePrefix = expressionResult.Expression;
2477
// bool showOnlyTypes = expressionResult.Contexts.Any (ctx => ctx == ExpressionContext.InheritableType || ctx == ExpressionContext.Constraints);
2478
// if (objects != null) {
2479
// foreach (object obj in objects) {
2480
// if (expressionResult.ExpressionContext != null && expressionResult.ExpressionContext.FilterEntry (obj))
2482
// if (expressionResult.ExpressionContext == ExpressionContext.NamespaceNameExcepted && !(obj is Namespace))
2484
// if (showOnlyTypes && !(obj is IType))
2486
// CompletionData data = col.Add (obj);
2487
// if (data != null && expressionResult.ExpressionContext == ExpressionContext.Attribute && data.CompletionText != null && data.CompletionText.EndsWith ("Attribute")) {
2488
// string newText = data.CompletionText.Substring (0, data.CompletionText.Length - "Attribute".Length);
2489
// data.SetText (newText);
2494
return result.Result;
2497
IEnumerable<ICompletionData> CreateCaseCompletionData(TextLocation location)
2499
var unit = ParseStub("a: break;");
2503
var s = unit.GetNodeAt<SwitchStatement>(location);
2508
var offset = document.GetOffset(s.Expression.StartLocation);
2509
var expr = GetExpressionAt(offset);
2514
var resolveResult = ResolveExpression(expr);
2515
if (resolveResult == null || resolveResult.Item1.Type.Kind != TypeKind.Enum) {
2518
var wrapper = new CompletionDataWrapper(this);
2519
AddEnumMembers(wrapper, resolveResult.Item1.Type, resolveResult.Item2);
2520
AutoCompleteEmptyMatch = false;
2521
return wrapper.Result;
2524
#region Parsing methods
2525
ExpressionResult GetExpressionBeforeCursor()
2527
CompilationUnit baseUnit;
2528
if (currentMember == null) {
2529
baseUnit = ParseStub("a", false);
2530
var type = baseUnit.GetNodeAt<MemberType>(location);
2532
baseUnit = ParseStub("a;", false);
2533
type = baseUnit.GetNodeAt<MemberType>(location);
2537
baseUnit = ParseStub("A a;", false);
2538
type = baseUnit.GetNodeAt<MemberType>(location);
2541
return new ExpressionResult((AstNode)type.Target, baseUnit);
2545
baseUnit = ParseStub("a", false);
2546
var curNode = baseUnit.GetNodeAt(location);
2548
// hack for local variable declaration missing ';' issue - remove that if it works.
2549
if (curNode is EntityDeclaration || baseUnit.GetNodeAt<Expression>(location) == null && baseUnit.GetNodeAt<MemberType>(location) == null) {
2550
baseUnit = ParseStub("a");
2551
curNode = baseUnit.GetNodeAt(location);
2554
// Hack for handle object initializer continuation expressions
2555
if (curNode is EntityDeclaration || baseUnit.GetNodeAt<Expression>(location) == null && baseUnit.GetNodeAt<MemberType>(location) == null) {
2556
baseUnit = ParseStub("a};");
2558
var mref = baseUnit.GetNodeAt<MemberReferenceExpression>(location);
2559
if (currentMember == null && currentType == null) {
2561
return new ExpressionResult((AstNode)mref.Target, baseUnit);
2566
//var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
2568
var type = baseUnit.GetNodeAt<MemberType>(location);
2570
return new ExpressionResult((AstNode)type.Target, baseUnit);
2573
AstNode expr = null;
2577
Expression tref = baseUnit.GetNodeAt<TypeReferenceExpression>(location);
2578
MemberType memberType = tref != null ? ((TypeReferenceExpression)tref).Type as MemberType : null;
2579
if (memberType == null) {
2580
memberType = baseUnit.GetNodeAt<MemberType>(location);
2581
if (memberType != null) {
2582
if (memberType.Parent is ObjectCreateExpression) {
2583
var mt = memberType.Target.Clone();
2584
memberType.ReplaceWith(mt);
2588
tref = baseUnit.GetNodeAt<Expression>(location);
2590
tref = new TypeReferenceExpression(memberType.Clone());
2591
memberType.Parent.AddChild(tref, Roles.Expression);
2593
if (tref is ObjectCreateExpression) {
2594
expr = new TypeReferenceExpression(memberType.Target.Clone());
2595
expr.AddAnnotation(new ObjectCreateExpression());
2601
if (memberType == null) {
2605
expr = new TypeReferenceExpression(memberType.Target.Clone());
2607
tref.ReplaceWith(expr);
2610
return new ExpressionResult((AstNode)expr, baseUnit);
2613
ExpressionResult GetExpressionAtCursor()
2615
// TextLocation memberLocation;
2616
// if (currentMember != null) {
2617
// memberLocation = currentMember.Region.Begin;
2618
// } else if (currentType != null) {
2619
// memberLocation = currentType.Region.Begin;
2621
// memberLocation = location;
2623
var baseUnit = ParseStub("a");
2624
var tmpUnit = baseUnit;
2625
AstNode expr = baseUnit.GetNodeAt(
2627
n => n is IdentifierExpression || n is MemberReferenceExpression
2631
expr = baseUnit.GetNodeAt<AstType>(location.Line, location.Column - 1);
2634
expr = baseUnit.GetNodeAt<Identifier>(location.Line, location.Column - 1);
2635
// try insertStatement
2636
if (expr == null && baseUnit.GetNodeAt<EmptyStatement>(
2640
tmpUnit = baseUnit = ParseStub("a();", false);
2641
expr = baseUnit.GetNodeAt<InvocationExpression>(
2648
baseUnit = ParseStub("()");
2649
expr = baseUnit.GetNodeAt<IdentifierExpression>(
2654
expr = baseUnit.GetNodeAt<MemberType>(location.Line, location.Column - 1);
2659
baseUnit = ParseStub("a", false);
2660
expr = baseUnit.GetNodeAt(
2662
n => n is IdentifierExpression || n is MemberReferenceExpression || n is CatchClause
2668
expr = tmpUnit.GetNodeAt<SwitchStatement>(
2676
var block = tmpUnit.GetNodeAt<BlockStatement>(location);
2677
var node = block != null ? block.Statements.LastOrDefault() : null;
2679
var forStmt = node != null ? node.PrevSibling as ForStatement : null;
2680
if (forStmt != null && forStmt.EmbeddedStatement.IsNull) {
2682
var id = new IdentifierExpression("stub");
2683
forStmt.EmbeddedStatement = new BlockStatement() { Statements = { new ExpressionStatement (id) }};
2690
var forStmt = tmpUnit.GetNodeAt<ForeachStatement>(
2694
if (forStmt != null && forStmt.EmbeddedStatement.IsNull) {
2695
forStmt.VariableNameToken = Identifier.Create("stub");
2696
expr = forStmt.VariableNameToken;
2701
expr = tmpUnit.GetNodeAt<VariableInitializer>(
2708
// try parameter declaration type
2710
baseUnit = ParseStub(">", false, "{}");
2711
expr = baseUnit.GetNodeAt<TypeParameterDeclaration>(
2717
// try parameter declaration method
2719
baseUnit = ParseStub("> ()", false, "{}");
2720
expr = baseUnit.GetNodeAt<TypeParameterDeclaration>(
2726
// try expression in anonymous type "new { sample = x$" case
2728
baseUnit = ParseStub("a", false);
2729
expr = baseUnit.GetNodeAt<AnonymousTypeCreateExpression>(
2734
expr = baseUnit.GetNodeAt<Expression>(location.Line, location.Column) ?? expr;
2737
expr = baseUnit.GetNodeAt<AstType>(location.Line, location.Column);
2744
return new ExpressionResult(expr, baseUnit);
2747
ExpressionResult GetExpressionAt(int offset)
2749
var parser = new CSharpParser();
2750
string text = this.document.GetText(0, this.offset);
2751
var sb = new StringBuilder(text);
2753
AppendMissingClosingBrackets(sb, text, false);
2754
var stream = new System.IO.StringReader(sb.ToString());
2755
var completionUnit = parser.Parse(stream, CSharpParsedFile.FileName, 0);
2757
var loc = document.GetLocation(offset);
2759
var expr = completionUnit.GetNodeAt(
2761
n => n is Expression || n is VariableDeclarationStatement
2766
return new ExpressionResult(expr, completionUnit);
2769
ExpressionResult GetNewExpressionAt(int offset)
2771
var parser = new CSharpParser();
2772
string text = this.document.GetText(0, this.offset);
2773
var sb = new StringBuilder(text);
2775
AppendMissingClosingBrackets(sb, text, false);
2777
var stream = new System.IO.StringReader(sb.ToString());
2778
var completionUnit = parser.Parse(stream, CSharpParsedFile.FileName, 0);
2780
var loc = document.GetLocation(offset);
2782
var expr = completionUnit.GetNodeAt(loc, n => n is Expression);
2785
sb = new StringBuilder(text);
2787
AppendMissingClosingBrackets(sb, text, false);
2788
stream = new System.IO.StringReader(sb.ToString());
2789
completionUnit = parser.Parse(stream, CSharpParsedFile.FileName, 0);
2791
loc = document.GetLocation(offset);
2793
expr = completionUnit.GetNodeAt(loc, n => n is Expression);
2798
return new ExpressionResult(expr, completionUnit);
2804
#region Helper methods
2805
string GetPreviousToken(ref int i, bool allowLineChange)
2813
c = document.GetCharAt(--i);
2814
} while (i > 0 && char.IsWhiteSpace (c) && (allowLineChange ? true : c != '\n'));
2820
if (!char.IsLetterOrDigit(c)) {
2821
return new string(c, 1);
2824
int endOffset = i + 1;
2827
c = document.GetCharAt(i - 1);
2828
if (!(char.IsLetterOrDigit(c) || c == '_')) {
2835
return document.GetText(i, endOffset - i);
2840
#region Preprocessor
2842
IEnumerable<ICompletionData> GetDirectiveCompletionData()
2844
yield return factory.CreateLiteralCompletionData("if");
2845
yield return factory.CreateLiteralCompletionData("else");
2846
yield return factory.CreateLiteralCompletionData("elif");
2847
yield return factory.CreateLiteralCompletionData("endif");
2848
yield return factory.CreateLiteralCompletionData("define");
2849
yield return factory.CreateLiteralCompletionData("undef");
2850
yield return factory.CreateLiteralCompletionData("warning");
2851
yield return factory.CreateLiteralCompletionData("error");
2852
yield return factory.CreateLiteralCompletionData("pragma");
2853
yield return factory.CreateLiteralCompletionData("line");
2854
yield return factory.CreateLiteralCompletionData("line hidden");
2855
yield return factory.CreateLiteralCompletionData("line default");
2856
yield return factory.CreateLiteralCompletionData("region");
2857
yield return factory.CreateLiteralCompletionData("endregion");
2861
#region Xml Comments
2862
static readonly List<string> commentTags = new List<string>(new string[] {
2886
IEnumerable<ICompletionData> GetXmlDocumentationCompletionData()
2888
yield return factory.CreateLiteralCompletionData(
2890
"Set text in a code-like font"
2892
yield return factory.CreateLiteralCompletionData(
2894
"Set one or more lines of source code or program output"
2896
yield return factory.CreateLiteralCompletionData(
2898
"Indicate an example"
2900
yield return factory.CreateLiteralCompletionData(
2902
"Identifies the exceptions a method can throw",
2903
"exception cref=\"|\"></exception>"
2905
yield return factory.CreateLiteralCompletionData(
2907
"Includes comments from a external file",
2908
"include file=\"|\" path=\"\">"
2910
yield return factory.CreateLiteralCompletionData(
2912
"Create a list or table",
2915
yield return factory.CreateLiteralCompletionData(
2917
"Define the heading row"
2919
yield return factory.CreateLiteralCompletionData(
2921
"Defines list or table item"
2924
yield return factory.CreateLiteralCompletionData("term", "A term to define");
2925
yield return factory.CreateLiteralCompletionData(
2927
"Describes a list item"
2929
yield return factory.CreateLiteralCompletionData(
2931
"Permit structure to be added to text"
2934
yield return factory.CreateLiteralCompletionData(
2936
"Describe a parameter for a method or constructor",
2939
yield return factory.CreateLiteralCompletionData(
2941
"Identify that a word is a parameter name",
2942
"paramref name=\"|\"/>"
2945
yield return factory.CreateLiteralCompletionData(
2947
"Document the security accessibility of a member",
2948
"permission cref=\"|\""
2950
yield return factory.CreateLiteralCompletionData(
2954
yield return factory.CreateLiteralCompletionData(
2956
"Describe the return value of a method"
2958
yield return factory.CreateLiteralCompletionData(
2963
yield return factory.CreateLiteralCompletionData(
2965
"Generate a See Also entry",
2966
"seealso cref=\"|\"/>"
2968
yield return factory.CreateLiteralCompletionData(
2970
"Describe a member of a type"
2972
yield return factory.CreateLiteralCompletionData(
2974
"Describe a type parameter for a generic type or method"
2976
yield return factory.CreateLiteralCompletionData(
2978
"Identify that a word is a type parameter name"
2980
yield return factory.CreateLiteralCompletionData(
2982
"Describe a property"
2988
static string[] expressionLevelKeywords = new string [] {
2998
static string[] primitiveTypesKeywords = new string [] {
3016
static string[] statementStartKeywords = new string [] { "base", "new", "sizeof", "this",
3017
"true", "false", "typeof", "checked", "unchecked", "from", "break", "checked",
3018
"unchecked", "const", "continue", "do", "finally", "fixed", "for", "foreach",
3019
"goto", "if", "lock", "return", "stackalloc", "switch", "throw", "try", "unsafe",
3020
"using", "while", "yield", "dynamic", "var", "dynamic",
3023
static string[] globalLevelKeywords = new string [] {
3024
"namespace", "using", "extern", "public", "internal",
3025
"class", "interface", "struct", "enum", "delegate",
3026
"abstract", "sealed", "static", "unsafe", "partial"
3028
static string[] accessorModifierKeywords = new string [] {
3029
"public", "internal", "protected", "private"
3031
static string[] typeLevelKeywords = new string [] {
3032
"public", "internal", "protected", "private",
3033
"class", "interface", "struct", "enum", "delegate",
3034
"abstract", "sealed", "static", "unsafe", "partial",
3035
"const", "event", "extern", "fixed","new",
3036
"operator", "explicit", "implicit",
3037
"override", "readonly", "virtual", "volatile"
3039
static string[] linqKeywords = new string[] {
3055
static string[] parameterTypePredecessorKeywords = new string[] {