CompletionDataList CreateCtrlSpaceCompletionData (CodeCompletionContext ctx, ExpressionResult expressionResult)
		{
			NRefactoryResolver resolver = CreateResolver ();
			DomLocation cursorLocation = new DomLocation (ctx.TriggerLine, ctx.TriggerLineOffset);
			resolver.SetupResolver (cursorLocation);
			CompletionDataList result = new ProjectDomCompletionDataList ();
			CompletionDataCollector col = new CompletionDataCollector (dom, result, Document.CompilationUnit, resolver.CallingType, cursorLocation);
			
			if (expressionResult == null) {
				AddPrimitiveTypes (col);
				resolver.AddAccessibleCodeCompletionData (ExpressionContext.Global, col);
			} else if (expressionResult.ExpressionContext == ExpressionContext.TypeDeclaration) {
				AddPrimitiveTypes (col);
				AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.TypeLevel);
				resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col);
			} else if (expressionResult.ExpressionContext == ExpressionContext.InterfaceDeclaration) {
				AddPrimitiveTypes (col);
				AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.InterfaceLevel);
				resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col);
			} else if (expressionResult.ExpressionContext == ExpressionContext.MethodBody) {
				col.Add ("global", "md-keyword");
				col.Add ("var", "md-keyword");
				AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.StatementStart);
				AddPrimitiveTypes (col);
				resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col);
			} else if (expressionResult.ExpressionContext == ExpressionContext.InterfacePropertyDeclaration) {
				col.Add ("get", "md-keyword");
				col.Add ("set", "md-keyword");
			} else if (expressionResult.ExpressionContext == ExpressionContext.ConstraintsStart) {
				col.Add ("where", "md-keyword");
			} else if (expressionResult.ExpressionContext == ExpressionContext.Constraints) {
				col.Add ("new", "md-keyword");
				col.Add ("class", "md-keyword");
				col.Add ("struct", "md-keyword");
				AddPrimitiveTypes (col);
				resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col);
			} else if (expressionResult.ExpressionContext == ExpressionContext.Attribute) {
				col.Add ("assembly", "md-keyword");
				col.Add ("module", "md-keyword");
				col.Add ("type", "md-keyword");
				col.Add ("method", "md-keyword");
				col.Add ("field", "md-keyword");
				col.Add ("property", "md-keyword");
				col.Add ("event", "md-keyword");
				col.Add ("param", "md-keyword");
				col.Add ("return", "md-keyword");
				resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col);
			} else if (expressionResult.ExpressionContext == ExpressionContext.BaseConstructorCall) {
				col.Add ("this", "md-keyword");
				col.Add ("base", "md-keyword");
			} else if (expressionResult.ExpressionContext == ExpressionContext.ParameterType || expressionResult.ExpressionContext == ExpressionContext.FirstParameterType) {
				col.Add ("ref", "md-keyword");
				col.Add ("out", "md-keyword");
				col.Add ("params", "md-keyword");
				// C# 3.0 extension method
				if (expressionResult.ExpressionContext == ExpressionContext.FirstParameterType)
					col.Add ("this", "md-keyword");
				AddPrimitiveTypes (col);
				resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col);
			} else if (expressionResult.ExpressionContext == ExpressionContext.PropertyDeclaration) {
				AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.InPropertyDeclaration);
			} else if (expressionResult.ExpressionContext == ExpressionContext.EventDeclaration) {
				col.Add ("add", "md-keyword");
				col.Add ("remove", "md-keyword");
			} //else if (expressionResult.ExpressionContext == ExpressionContext.FullyQualifiedType) {} 
			else if (expressionResult.ExpressionContext == ExpressionContext.Default) {
				col.Add ("global", "md-keyword");
				col.Add ("var", "md-keyword");
				AddPrimitiveTypes (col);
				AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.ExpressionStart);
				AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.ExpressionContent);
				resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col);
			} else if (expressionResult.ExpressionContext == ExpressionContext.Global) {
				AddNRefactoryKeywords (col, ICSharpCode.NRefactory.Parser.CSharp.Tokens.GlobalLevel);
				CodeTemplateService.AddCompletionDataForMime ("text/x-csharp", result);
			} else if (expressionResult.ExpressionContext == ExpressionContext.ObjectInitializer) {
				ExpressionContext exactContext = new NewCSharpExpressionFinder (dom).FindExactContextForObjectInitializer (textEditorData, resolver.Unit, Document.FileName, resolver.CallingType);
				if (exactContext is ExpressionContext.TypeExpressionContext) {
					IReturnType objectInitializer = ((ExpressionContext.TypeExpressionContext)exactContext).UnresolvedType;
					if (objectInitializer.ArrayDimensions > 0 || objectInitializer.PointerNestingLevel > 0) {
						col.Add ("global", "md-keyword");
						col.Add ("new", "md-keyword");
						AddPrimitiveTypes (col);
						resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col);
						return result;
					}
						
					IType foundType = resolver.SearchType (objectInitializer);
					if (foundType == null)
						foundType = dom.GetType (objectInitializer);
					
					if (foundType != null) {
						bool includeProtected = DomType.IncludeProtected (dom, foundType, resolver.CallingType);
						foreach (IType type in dom.GetInheritanceTree (foundType)) {
							foreach (IProperty property in type.Properties) {
								if (property.IsAccessibleFrom (dom, resolver.CallingType, resolver.CallingMember, includeProtected)) {
									col.Add (property);
								}
							}
							foreach (var field in type.Fields) {
								if (field.IsAccessibleFrom (dom, resolver.CallingType, resolver.CallingMember, includeProtected)) {
									col.Add (field);
								}
							}
						}
					}
				}
//				result.Add ("global", "md-literal");
//				AddPrimitiveTypes (result);
//				resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, result);
			} else if (expressionResult.ExpressionContext == ExpressionContext.AttributeArguments) {
				col.Add ("global", "md-keyword");
				AddPrimitiveTypes (col);
				string attributeName = NewCSharpExpressionFinder.FindAttributeName (textEditorData, Document.CompilationUnit, Document.FileName);
				if (attributeName != null) {
					IType type = resolver.SearchType (attributeName + "Attribute");
					if (type == null) 
						type = resolver.SearchType (attributeName);
					if (type != null) {
						foreach (var property in type.Properties) {
							col.Add (property);
						}
						foreach (var field in type.Fields) {
							if (field.IsPublic)
								col.Add (field);
						}
					}
				}
				resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col);
			} else if (expressionResult.ExpressionContext == ExpressionContext.IdentifierExpected) {
				if (!string.IsNullOrEmpty (expressionResult.Expression))
					expressionResult.Expression = expressionResult.Expression.Trim ();
				MemberResolveResult resolveResult = resolver.Resolve (expressionResult, cursorLocation) as MemberResolveResult;
				if (resolveResult != null && resolveResult.ResolvedMember == null && resolveResult.ResolvedType != null) {
					string name = CSharpAmbience.NetToCSharpTypeName (resolveResult.ResolvedType.FullName);
					if (name != resolveResult.ResolvedType.FullName) {
						col.Add (Char.ToLower (name[0]).ToString (), "md-field");
					} else {
						name = resolveResult.ResolvedType.Name;
						List<string> names = new List<string> ();
						int lastNameStart = 0;
						for (int i = 1; i < name.Length; i++) {
							if (Char.IsUpper (name[i])) {
								names.Add (name.Substring (lastNameStart, i - lastNameStart));
								lastNameStart = i;
							}
						}
						names.Add (name.Substring (lastNameStart, name.Length - lastNameStart));
						
						StringBuilder possibleName = new StringBuilder ();
						for (int i = 0; i < names.Count; i++) {
							possibleName.Length  = 0;
							for (int j = i; j < names.Count; j++) {
								if (string.IsNullOrEmpty (names[j]))
									continue;
								if (j == i) 
									names[j] = Char.ToLower (names[j][0]) + names[j].Substring (1);
								possibleName.Append (names[j]);
							}
							if (possibleName.Length > 0)
								col.Add (possibleName.ToString (), "md-field");
						}
						result.IsSorted = true;
					}
				} else {
					col.Add ("global", "md-keyword");
					AddPrimitiveTypes (col);
					resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col);
					if (expressionResult.ExpressionContext == ExpressionContext.Constraints) {
						col.Add ("struct", "md-keyword");
						col.Add ("class", "md-keyword");
						col.Add ("new()", "md-keyword");
					} else {
						col.Add ("var", "md-keyword");
					}
				}
			} else if (expressionResult.ExpressionContext == ExpressionContext.TypeName) {
				col.Add ("global", "md-keyword");
				AddPrimitiveTypes (col);
				resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col);
			} else if (expressionResult.ExpressionContext == ExpressionContext.ForeachInToken) {
				col.Add ("in", "md-keyword");
			} else {
				col.Add ("global", "md-keyword");
				col.Add ("var", "md-keyword");
				AddPrimitiveTypes (col);
				resolver.AddAccessibleCodeCompletionData (expressionResult.ExpressionContext, col);
			}
			
			if (resolver.CallingMember is IMethod) {
				foreach (ITypeParameter tp in ((IMethod)resolver.CallingMember).TypeParameters) {
					col.Add (tp.Name, "md-keyword");
				}
			}
			return result;
		}
		public ICompletionDataList HandleKeywordCompletion (CodeCompletionContext completionContext, ExpressionResult result, int wordStart, string word)
		{
			if (stateTracker.Engine.IsInsideDocLineComment || stateTracker.Engine.IsInsideOrdinaryCommentOrString)
				return null;
			DomLocation location = new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset);
			switch (word) {
			case "using":
				if (result.ExpressionContext != ExpressionContext.NamespaceNameExcepted)
					return null;
				return CreateCompletionData (location, new NamespaceResolveResult (""), result, null);
			case "namespace":
				result.ExpressionContext = ExpressionContext.NamespaceNameExcepted;
				return CreateCompletionData (location, new NamespaceResolveResult (""), result, null);
			case "case":
				return CreateCaseCompletionData (location, result);
			case ",":
			case ":":
				if (result.ExpressionContext == ExpressionContext.InheritableType) {
					IType cls = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
					CompletionDataList completionList = new ProjectDomCompletionDataList ();
					List<string> namespaceList = GetUsedNamespaces ();
					CSharpTextEditorCompletion.CompletionDataCollector col = new CSharpTextEditorCompletion.CompletionDataCollector (dom, completionList, Document.CompilationUnit, null, location);
					bool isInterface = false;
					HashSet<string> baseTypeNames = new HashSet<string> ();
					if (cls != null) {
						baseTypeNames.Add (cls.Name);
						if (cls.ClassType == ClassType.Struct)
							isInterface = true;
					}
					int tokenIndex = completionContext.TriggerOffset;

										// Search base types " : [Type1, ... ,TypeN,] <Caret>"
					string token = null;
					do {
						token = GetPreviousToken (ref tokenIndex, false);
						if (string.IsNullOrEmpty (token))
							break;
						token = token.Trim ();
						if (Char.IsLetterOrDigit (token[0]) || token[0] == '_') {
							IType baseType = dom.SearchType (Document.CompilationUnit, Document.CompilationUnit, token);
							if (baseType != null) {
								if (baseType.ClassType != ClassType.Interface)
									isInterface = true;
								baseTypeNames.Add (baseType.Name);
							}
						}
					} while (token != ":");
					foreach (object o in dom.GetNamespaceContents (namespaceList, true, true)) {
						IType type = o as IType;
						if (type != null && (type.IsStatic || type.IsSealed || baseTypeNames.Contains (type.Name) || isInterface && type.ClassType != ClassType.Interface)) {
							continue;
						}
						if (o is Namespace && !namespaceList.Any (ns => ns.StartsWith (((Namespace)o).FullName)))
							continue;
						col.Add (o);
					}
					// Add inner classes
					Stack<IType> innerStack = new Stack<IType> ();
					innerStack.Push (cls);
					while (innerStack.Count > 0) {
						IType curType = innerStack.Pop ();
						if (curType == null)
							continue;
						foreach (IType innerType in curType.InnerTypes) {
							if (innerType != cls)
								// don't add the calling class as possible base type
								col.Add (innerType);
						}
						if (curType.DeclaringType != null)
							innerStack.Push (curType.DeclaringType);
					}
					return completionList;
				}
				break;
			case "is":
			case "as":
				
				{
					CompletionDataList completionList = new ProjectDomCompletionDataList ();
					ExpressionResult expressionResult = FindExpression (dom, completionContext, wordStart - textEditorData.Caret.Offset);
					NRefactoryResolver resolver = CreateResolver ();
					ResolveResult resolveResult = resolver.Resolve (expressionResult, new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
					if (resolveResult != null && resolveResult.ResolvedType != null) {
						CompletionDataCollector col = new CompletionDataCollector (dom, completionList, Document.CompilationUnit, resolver.CallingType, location);
						IType foundType = null;
						if (word == "as") {
							ExpressionContext exactContext = new NewCSharpExpressionFinder (dom).FindExactContextForAsCompletion (textEditorData, Document.CompilationUnit, Document.FileName, resolver.CallingType);
							if (exactContext is ExpressionContext.TypeExpressionContext) {
								foundType = resolver.SearchType (((ExpressionContext.TypeExpressionContext)exactContext).Type);
								AddAsCompletionData (col, foundType);
							}
						}
					
						if (foundType == null)
							foundType = resolver.SearchType (resolveResult.ResolvedType);
					
						if (foundType != null) {
							if (foundType.ClassType == ClassType.Interface)
								foundType = resolver.SearchType (DomReturnType.Object);
						
							foreach (IType type in dom.GetSubclasses (foundType)) {
								if (type.IsSpecialName || type.Name.StartsWith ("<"))
									continue;
								AddAsCompletionData (col, type);
							}
						}
						List<string> namespaceList = GetUsedNamespaces ();
						foreach (object o in dom.GetNamespaceContents (namespaceList, true, true)) {
							if (o is IType) {
								IType type = (IType)o;
								if (type.ClassType != ClassType.Interface || type.IsSpecialName || type.Name.StartsWith ("<"))
									continue;
//								if (foundType != null && !dom.GetInheritanceTree (foundType).Any (x => x.FullName == type.FullName))
//									continue;
								AddAsCompletionData (col, type);
								continue;
							}
							if (o is Namespace)
								continue;
							col.Add (o);
						}
						return completionList;
					}
					result.ExpressionContext = ExpressionContext.TypeName;
					return CreateCtrlSpaceCompletionData (completionContext, result);
				}
			case "override":
				// Look for modifiers, in order to find the beginning of the declaration
				int firstMod = wordStart;
				int i = wordStart;
				for (int n = 0; n < 3; n++) {
					string mod = GetPreviousToken (ref i, true);
					if (mod == "public" || mod == "protected" || mod == "private" || mod == "internal" || mod == "sealed") {
						firstMod = i;
					} else if (mod == "static") {
						// static methods are not overridable
						return null;
					} else
						break;
				}
				IType overrideCls = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
				if (overrideCls == null)
					overrideCls = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new DomLocation (completionContext.TriggerLine - 1, 1));
				if (overrideCls != null && (overrideCls.ClassType == ClassType.Class || overrideCls.ClassType == ClassType.Struct)) {
					string modifiers = textEditorData.GetTextBetween (firstMod, wordStart);
					return GetOverrideCompletionData (completionContext, overrideCls, modifiers);
				}
				return null;
			case "partial":
				// Look for modifiers, in order to find the beginning of the declaration
				firstMod = wordStart;
				i = wordStart;
				for (int n = 0; n < 3; n++) {
					string mod = GetPreviousToken (ref i, true);
					if (mod == "public" || mod == "protected" || mod == "private" || mod == "internal" || mod == "sealed") {
						firstMod = i;
					} else if (mod == "static") {
						// static methods are not overridable
						return null;
					} else
						break;
				}
				overrideCls = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
				if (overrideCls != null && (overrideCls.ClassType == ClassType.Class || overrideCls.ClassType == ClassType.Struct)) {
					string modifiers = textEditorData.GetTextBetween (firstMod, wordStart);
					return GetPartialCompletionData (completionContext, overrideCls, modifiers);
				}
				return null;
				
			case "new":
				IType callingType = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new DomLocation (textEditorData.Caret.Line, textEditorData.Caret.Column));
				ExpressionContext newExactContext = new NewCSharpExpressionFinder (dom).FindExactContextForNewCompletion (textEditorData, Document.CompilationUnit, Document.FileName, callingType);
				if (newExactContext is ExpressionContext.TypeExpressionContext)
					return CreateTypeCompletionData (location, callingType, newExactContext, ((ExpressionContext.TypeExpressionContext)newExactContext).Type, ((ExpressionContext.TypeExpressionContext)newExactContext).UnresolvedType);
				if (newExactContext == null) {
					int j = completionContext.TriggerOffset - 4;
					string token = GetPreviousToken (ref j, true);
					string yieldToken = GetPreviousToken (ref j, true);
					if (token == "return") {
						NRefactoryResolver resolver = CreateResolver ();
						resolver.SetupResolver (new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
						IReturnType returnType = resolver.CallingMember.ReturnType;
						if (yieldToken == "yield" && returnType.GenericArguments.Count > 0)
							returnType = returnType.GenericArguments[0];
						if (resolver.CallingMember != null)
							return CreateTypeCompletionData (location, callingType, newExactContext, null, returnType);
					}
				}
				return CreateCtrlSpaceCompletionData (completionContext, null);
			case "if":
			case "elif":
				if (stateTracker.Engine.IsInsidePreprocessorDirective) 
					return GetDefineCompletionData ();
				return null;
			case "yield":
				CompletionDataList yieldDataList = new CompletionDataList ();
				yieldDataList.DefaultCompletionString = "return";
				yieldDataList.Add ("break", "md-keyword");
				yieldDataList.Add ("return", "md-keyword");
				return yieldDataList;
			case "where":
				CompletionDataList whereDataList = new CompletionDataList ();
				NRefactoryResolver constraintResolver = CreateResolver ();
				constraintResolver.SetupResolver (new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
				if (constraintResolver.CallingMember is IMethod) {
					foreach (ITypeParameter tp in ((IMethod)constraintResolver.CallingMember).TypeParameters) {
						whereDataList.Add (tp.Name, "md-keyword");
					}
				} else {
					if (constraintResolver.CallingType != null) {
						foreach (ITypeParameter tp in constraintResolver.CallingType.TypeParameters) {
							whereDataList.Add (tp.Name, "md-keyword");
						}
					}
				}

				return whereDataList;
			}
			if (IsInLinqContext (result)) {
				if (linqKeywords.Contains (word)) {
					if (word == "from") // after from no auto code completion.
						return null;
					result.Expression = "";
					return CreateCtrlSpaceCompletionData (completionContext, result);
				}
				CompletionDataList dataList = new ProjectDomCompletionDataList ();
				CompletionDataCollector col = new CompletionDataCollector (dom, dataList, Document.CompilationUnit, null, new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
				foreach (string kw in linqKeywords) {
					col.Add (kw, "md-keyword");
				}
				return dataList;
			}
			return null;
		}
		public override ICompletionDataList HandleCodeCompletion (CodeCompletionContext completionContext, char completionChar, ref int triggerWordLength)
		{
			if (textEditorData.CurrentMode is CompletionTextLinkMode) {
				if (!((CompletionTextLinkMode)textEditorData.CurrentMode).TriggerCodeCompletion)
					return null;
			} else if (textEditorData.CurrentMode is Mono.TextEditor.TextLinkEditMode) {
				return null;
			}

	//		IDisposable timer = null;
		try {
			if (dom == null /*|| Document.CompilationUnit == null*/)
				return null;
			if (completionChar != '#' && stateTracker.Engine.IsInsidePreprocessorDirective)
				return null;
		//	timer = Counters.ResolveTime.BeginTiming ();
			DomLocation location = new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset - 1);
			stateTracker.UpdateEngine ();
			ExpressionResult result;
			int cursor, newCursorOffset = 0;
			switch (completionChar) {
			case ':':
			case '.':
				if (stateTracker.Engine.IsInsideDocLineComment || stateTracker.Engine.IsInsideOrdinaryCommentOrString)
					return null;
				result = FindExpression (dom, completionContext);
				if (result == null || result.Expression == null)
					return null;
				int idx = result.Expression.LastIndexOf ('.');
				if (idx > 0)
					result.Expression = result.Expression.Substring (0, idx);
				// don't parse expressions that end with more than 1 dot - see #646820
				if (result.Expression.EndsWith ("."))
					return null;
				NRefactoryResolver resolver = CreateResolver ();
				ResolveResult resolveResult = resolver.Resolve (result, location);
				if (resolver.ResolvedExpression is ICSharpCode.NRefactory.Ast.PrimitiveExpression) {
					ICSharpCode.NRefactory.Ast.PrimitiveExpression pex = (ICSharpCode.NRefactory.Ast.PrimitiveExpression)resolver.ResolvedExpression;
					if (!tryToForceCompletion && !(pex.Value is string || pex.Value is char || pex.Value is bool))
						return null;
				}
					
				return CreateCompletionData (location, resolveResult, result, resolver);
			case '#':
				if (stateTracker.Engine.IsInsidePreprocessorDirective) 
					return GetDirectiveCompletionData ();
				return null;
			case '>':
				cursor = textEditorData.IsSomethingSelected ? textEditorData.SelectionRange.Offset : textEditorData.Caret.Offset;
				
				if (stateTracker.Engine.IsInsideDocLineComment) {
					string lineText = textEditorData.GetLineText (completionContext.TriggerLine);
					int startIndex = Math.Min (completionContext.TriggerLineOffset - 1, lineText.Length - 1);
					
					while (startIndex >= 0 && lineText[startIndex] != '<') {
						--startIndex;
						if (lineText[startIndex] == '/') { // already closed.
							startIndex = -1;
							break;
						}
					}
					
					if (startIndex >= 0) {
						int endIndex = startIndex;
						while (endIndex <= completionContext.TriggerLineOffset && endIndex < lineText.Length && !Char.IsWhiteSpace (lineText[endIndex])) {
							endIndex++;
						}
						string tag = endIndex - startIndex - 1 > 0 ? lineText.Substring (startIndex + 1, endIndex - startIndex - 2) : null;
						if (!String.IsNullOrEmpty (tag) && commentTags.IndexOf (tag) >= 0) {
							textEditorData.Insert (cursor, "</" + tag + ">");
							textEditorData.Caret.Offset = cursor; 
							return null;
						}
					}
				}
				return null;
/* Disabled because it gives problems when declaring arrays - for example string [] should not pop up code completion.
 			case '[':
				if (stateTracker.Engine.IsInsideDocLineComment || stateTracker.Engine.IsInsideOrdinaryCommentOrString)
					return null;
				result = FindExpression (dom, completionContext);
				if (result.ExpressionContext == ExpressionContext.Attribute)
					return CreateCtrlSpaceCompletionData (completionContext, result);
				return null;*/
			case '<':
				if (stateTracker.Engine.IsInsideDocLineComment) 
					return GetXmlDocumentationCompletionData ();
				return null;
			case '(':
				if (stateTracker.Engine.IsInsideDocLineComment || stateTracker.Engine.IsInsideOrdinaryCommentOrString)
					return null;
				result = FindExpression (dom, completionContext, -1);
				if (result == null || result.Expression == null)
					return null;
				resolver = CreateResolver ();
				resolveResult = resolver.Resolve (result, new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset - 2));
				
				if (resolveResult != null && resolver.ResolvedExpression is ICSharpCode.NRefactory.Ast.TypeOfExpression) {
					CompletionDataList completionList = new ProjectDomCompletionDataList ();
					
					CompletionDataCollector col = new CompletionDataCollector (dom, completionList, Document.CompilationUnit, resolver.CallingType, location);
					AddPrimitiveTypes (col);
					foreach (object o in dom.GetNamespaceContents (GetUsedNamespaces (), true, true)) {
						col.Add (o);
					}
					if (resolver.CallingMember is IMethod) {
						foreach (ITypeParameter tp in ((IMethod)resolver.CallingMember).TypeParameters) {
							col.Add (tp.Name, "md-keyword");
						}
					}
					if (resolver.CallingType != null) {
						foreach (ITypeParameter tp in resolver.CallingType.TypeParameters) {
							col.Add (tp.Name, "md-keyword");
						}
					}
					return completionList;
				}
				return null;
			case '/':
				cursor = textEditorData.IsSomethingSelected ? textEditorData.SelectionRange.Offset : textEditorData.Caret.Offset;
				if (cursor < 2)
					break;
					
				if (stateTracker.Engine.IsInsideDocLineComment) {
					string lineText = textEditorData.GetLineText (completionContext.TriggerLine);
					bool startsDocComment = true;
					int slashes = 0;
					for (int i = 0; i < completionContext.TriggerLineOffset && i < lineText.Length; i++) {
						if (lineText[i] == '/') {
							slashes++;
							continue;
						}
						if (!Char.IsWhiteSpace (lineText[i])) {
							startsDocComment = false;
							break;
						}
					}
					// check if lines above already start a doc comment
					for (int i = completionContext.TriggerLine - 2; i >= 1; i--) {
						string text = textEditorData.GetLineText (i);
						if (text.Length == 0)
							continue;
						if (text.StartsWith ("///")) {
							startsDocComment = false;
							break;
						}
						break;
					}
						
					// check if following lines start a doc comment
					for (int i = completionContext.TriggerLine; i <= textEditorData.Document.LineCount; i++) {
						string text = textEditorData.GetLineText (i);
						if (text == null)
							break;
						text = text.Trim ();
						if (text.Length == 0)
							continue;
						if (text.StartsWith ("///")) {
							startsDocComment = false;
							break;
						}
						break;
					}
					
					if (!startsDocComment || slashes != 3)
						break;
					StringBuilder generatedComment = new StringBuilder ();
					bool generateStandardComment = true;
					ParsedDocument currentParsedDocument = Document.UpdateParseDocument ();
					IType insideClass = NRefactoryResolver.GetTypeAtCursor (currentParsedDocument.CompilationUnit, Document.FileName, location);
					if (insideClass != null) {
						string indent = textEditorData.Document.GetLineIndent (completionContext.TriggerLine);
						if (insideClass.ClassType == ClassType.Delegate) {
							AppendSummary (generatedComment, indent, out newCursorOffset);
							IMethod m = null;
							foreach (IMethod method in insideClass.Methods)
								m = method;
							AppendMethodComment (generatedComment, indent, m);
							generateStandardComment = false;
						} else {
							if (!IsInsideClassBody (insideClass, completionContext.TriggerLine, completionContext.TriggerLineOffset))
								break;
							string body = GenerateBody (insideClass, completionContext.TriggerLine, indent, out newCursorOffset);
							if (!String.IsNullOrEmpty (body)) {
								generatedComment.Append (body);
								generateStandardComment = false;
							}
						}
					}
					if (generateStandardComment) {
						string indent = textEditorData.Document.GetLineIndent (completionContext.TriggerLine);
						AppendSummary (generatedComment, indent, out newCursorOffset);
					}
					textEditorData.Document.EndAtomicUndo ();
					textEditorData.Document.BeginAtomicUndo ();
					textEditorData.Insert (cursor, generatedComment.ToString ());
					textEditorData.Caret.Offset = cursor + newCursorOffset;
					return null;
				}
				return null;
//			case '\n':
//			case '\r': {
//				if (stateTracker.Engine.IsInsideDocLineComment || stateTracker.Engine.IsInsideOrdinaryCommentOrString)
//					return null;
//				result = FindExpression (dom, completionContext);
//				if (result == null)
//					return null;
//					
//					
//				int tokenIndex = completionContext.TriggerOffset;
//				string token = GetPreviousToken (ref tokenIndex, false);
//				if (result.ExpressionContext == ExpressionContext.ObjectInitializer) {
//					if (token == "{" || token == ",")
//						return CreateCtrlSpaceCompletionData (completionContext, result); 
//				} 
//				return null;
//				}
			case ' ':
				if (stateTracker.Engine.IsInsideDocLineComment || stateTracker.Engine.IsInsideOrdinaryCommentOrString)
					return null;
				result = FindExpression (dom, completionContext);
				if (result == null)
					return null;
					
				int tokenIndex = completionContext.TriggerOffset;
				string token = GetPreviousToken (ref tokenIndex, false);
				if (result.ExpressionContext == ExpressionContext.ObjectInitializer) {
					resolver = CreateResolver ();
					ExpressionContext exactContext = new NewCSharpExpressionFinder (dom).FindExactContextForObjectInitializer (textEditorData, resolver.Unit, Document.FileName, resolver.CallingType);
					IReturnType objectInitializer = ((ExpressionContext.TypeExpressionContext)exactContext).UnresolvedType;
					if (objectInitializer != null && objectInitializer.ArrayDimensions == 0 && objectInitializer.PointerNestingLevel == 0 && (token == "{" || token == ","))
						return CreateCtrlSpaceCompletionData (completionContext, result); 
				}
				if (token == "=") {
					int j = tokenIndex;
					string prevToken = GetPreviousToken (ref j, false);
					if (prevToken == "=" || prevToken == "+" || prevToken == "-") {
						token = prevToken + token;
						tokenIndex = j;
					}
				}
				switch (token) {
				case "=":
				case "==":
					result = FindExpression (dom, completionContext, tokenIndex - completionContext.TriggerOffset - 1);
					resolver = CreateResolver ();
					resolveResult = resolver.Resolve (result, location);
					if (resolveResult != null) {
						IType resolvedType = dom.GetType (resolveResult.ResolvedType);
						if (resolvedType == null) 
							return null;
						if (resolvedType.ClassType == ClassType.Enum) {
							CompletionDataList completionList = new ProjectDomCompletionDataList ();
							CompletionDataCollector cdc = new CompletionDataCollector (dom, completionList, Document.CompilationUnit, resolver.CallingType, location);
							IReturnType returnType = new DomReturnType (resolvedType);
							bool added = false;
							foreach (IUsing u in Document.CompilationUnit.Usings) {
								foreach (KeyValuePair<string, IReturnType> alias in u.Aliases) {
									if (alias.Value.ToInvariantString () == returnType.ToInvariantString ()) {
										cdc.Add (alias.Key, "md-class");
										added = true;
									}
								}
							}
							if (!added)
								cdc.Add (returnType);/*
							foreach (object o in CreateCtrlSpaceCompletionData (completionContext, result)) {
								MemberCompletionData memberData = o as MemberCompletionData;
								if (memberData == null || memberData.Member == null) {
									completionList.Add (o as CompletionData);
									continue;
								}
								if (memberData.Member is IMember) {
									returnType = ((IMember)memberData.Member).ReturnType;
								} else if (memberData.Member is IParameter) {
									returnType = ((IParameter)memberData.Member).ReturnType;
								} else {
									returnType = ((LocalVariable)memberData.Member).ReturnType;
								}
								// filter out void types
								if (returnType != null && returnType.FullName != DomReturnType.Void.FullName)
									completionList.Add (memberData);
							}*/
							completionList.AutoCompleteEmptyMatch = false;
							resolver.AddAccessibleCodeCompletionData (result.ExpressionContext, cdc);
							return completionList;
						}
						
						if (resolvedType.FullName == DomReturnType.Bool.FullName) {
							CompletionDataList completionList = new ProjectDomCompletionDataList ();
							CompletionDataCollector cdc = new CompletionDataCollector (dom, completionList, Document.CompilationUnit, resolver.CallingType, location);
							completionList.AutoCompleteEmptyMatch = false;
							cdc.Add ("true", "md-keyword");
							cdc.Add ("false", "md-keyword");
/*							foreach (object o in CreateCtrlSpaceCompletionData (completionContext, result)) {
								MemberCompletionData memberData = o as MemberCompletionData;
								if (memberData == null || memberData.Member == null) {
									completionList.Add (o as CompletionData);
									continue;
								}
								IReturnType returnType = null;
								if (memberData.Member is IMember) {
									returnType = ((IMember)memberData.Member).ReturnType;
								} else if (memberData.Member is IParameter) {
									returnType = ((IParameter)memberData.Member).ReturnType;
								} else {
									returnType = ((LocalVariable)memberData.Member).ReturnType;
								}
								// filter out void types
								if (returnType != null && returnType.FullName != DomReturnType.Void.FullName)
									completionList.Add (memberData);
							}*/
							resolver.AddAccessibleCodeCompletionData (result.ExpressionContext, cdc);
							return completionList;
						}
							
						if (resolvedType.ClassType == ClassType.Delegate && token == "=") {
							IMethod delegateMethod = resolvedType.Methods.First ();
							CompletionDataList completionList = new ProjectDomCompletionDataList ();
								
							completionList.Add ("delegate", "md-keyword", GettextCatalog.GetString ("Creates anonymous delegate."), "delegate {" + Document.Editor.EolMarker + stateTracker.Engine.ThisLineIndent  + TextEditorProperties.IndentString + "|" + Document.Editor.EolMarker + stateTracker.Engine.ThisLineIndent +"};");
							StringBuilder sb = new StringBuilder ("(");
							for (int k = 0; k < delegateMethod.Parameters.Count; k++) {
								if (k > 0)
									sb.Append (", ");
								IType parameterType = dom.GetType (delegateMethod.Parameters[k].ReturnType);
								IReturnType returnType = parameterType != null ? new DomReturnType (parameterType) : delegateMethod.Parameters[k].ReturnType;
								sb.Append (CompletionDataCollector.ambience.GetString (Document.CompilationUnit.ShortenTypeName (returnType, textEditorData.Caret.Line, textEditorData.Caret.Column), OutputFlags.ClassBrowserEntries | OutputFlags.UseFullName  | OutputFlags.UseFullInnerTypeName));
								sb.Append (" ");
								sb.Append (delegateMethod.Parameters[k].Name);
							}
							sb.Append (")");
							completionList.Add ("delegate" + sb, "md-keyword", GettextCatalog.GetString ("Creates anonymous delegate."), "delegate" + sb + " {" + Document.Editor.EolMarker + stateTracker.Engine.ThisLineIndent  + TextEditorProperties.IndentString + "|" + Document.Editor.EolMarker + stateTracker.Engine.ThisLineIndent +"};");
							string varName = GetPreviousToken (ref tokenIndex, false);
							varName = GetPreviousToken (ref tokenIndex, false);
							if (varName != ".") {
								varName = null;
							} else {
								List<string> names = new List<string> ();
								while (varName == ".") {
									varName = GetPreviousToken (ref tokenIndex, false);
									if (varName == "this") {
										names.Add ("handle");
									} else if (varName != null) {
										string trimmedName = varName.Trim ();
										if (trimmedName.Length == 0)
											break;
										names.Insert (0, trimmedName);
									}
									varName = GetPreviousToken (ref tokenIndex, false);
								}
								varName = String.Join ("", names.ToArray ());
								foreach (char ch in varName) {
									if (!char.IsLetterOrDigit (ch) && ch != '_') {
										varName = "";
										break;
									}
								}
							}
							completionList.Add (new EventCreationCompletionData (textEditorData, varName, resolvedType, null, sb.ToString (), resolver.CallingMember, resolvedType));
							return completionList;
						}
					}
					return null;
				case "+=":
				case "-=":
					if (stateTracker.Engine.IsInsideDocLineComment || stateTracker.Engine.IsInsideOrdinaryCommentOrString)
						return null;
					result = FindExpression (dom, completionContext, tokenIndex - completionContext.TriggerOffset);
					resolver = CreateResolver ();
					resolveResult = resolver.Resolve (result, location);
					
					if (resolveResult is MemberResolveResult) {
						MemberResolveResult mrr = resolveResult as MemberResolveResult;
						IEvent evt = mrr.ResolvedMember as IEvent;
						if (evt == null)
							return null;
						IType delegateType = resolver.SearchType (evt.ReturnType);
						if (delegateType == null || delegateType.ClassType != ClassType.Delegate)
							return null;
						CompletionDataList completionList = new ProjectDomCompletionDataList ();
						CompletionDataCollector cdc = new CompletionDataCollector (dom, completionList, Document.CompilationUnit, resolver.CallingType, location);
						
						IType declaringType = resolver.CallingType;
						if (Document.LastErrorFreeParsedDocument != null) {
							declaringType = Document.LastErrorFreeParsedDocument.CompilationUnit.GetType (declaringType.FullName, declaringType.TypeParameters.Count);
						}
						IType typeFromDatabase = null;
						if (declaringType != null) {
							typeFromDatabase = dom.GetType (declaringType.FullName, new DomReturnType (declaringType).GenericArguments) ?? declaringType;
							bool includeProtected = DomType.IncludeProtected (dom, typeFromDatabase, resolver.CallingType);
							foreach (IType type in dom.GetInheritanceTree (typeFromDatabase)) {
								foreach (IMethod method in type.Methods) {
									if (method.IsAccessibleFrom (dom, resolver.CallingType, resolver.CallingMember, includeProtected) && MatchDelegate (delegateType, method)) {
										CompletionData data = cdc.Add (method);
										data.SetText (data.CompletionText + ";");
									}
								}
							}
						}
						if (token == "+=") {
							IMethod delegateMethod = delegateType.Methods.First ();
							completionList.Add ("delegate", "md-keyword", GettextCatalog.GetString ("Creates anonymous delegate."), "delegate {" + Document.Editor.EolMarker + stateTracker.Engine.ThisLineIndent  + TextEditorProperties.IndentString + "|" + Document.Editor.EolMarker + stateTracker.Engine.ThisLineIndent +"};");
							StringBuilder sb = new StringBuilder ("(");
							for (int k = 0; k < delegateMethod.Parameters.Count; k++) {
								if (k > 0)
									sb.Append (", ");
								IType parameterType = dom.GetType (delegateMethod.Parameters[k].ReturnType);
								IReturnType returnType = parameterType != null ? new DomReturnType (parameterType) : delegateMethod.Parameters[k].ReturnType;
								sb.Append (CompletionDataCollector.ambience.GetString (Document.CompilationUnit.ShortenTypeName (returnType, textEditorData.Caret.Line, textEditorData.Caret.Column), OutputFlags.ClassBrowserEntries | OutputFlags.UseFullName  | OutputFlags.UseFullInnerTypeName));
								sb.Append (" ");
								sb.Append (delegateMethod.Parameters[k].Name);
							}
							sb.Append (")");
							completionList.Add ("delegate" + sb, "md-keyword", GettextCatalog.GetString ("Creates anonymous delegate."), "delegate" + sb + " {" + Document.Editor.EolMarker + stateTracker.Engine.ThisLineIndent  + TextEditorProperties.IndentString + "|" + Document.Editor.EolMarker + stateTracker.Engine.ThisLineIndent +"};");
							string varName = GetPreviousToken (ref tokenIndex, false);
							varName = GetPreviousToken (ref tokenIndex, false);
							if (varName != ".") {
								varName = null;
							} else {
								List<string> names = new List<string> ();
								while (varName == ".") {
									varName = GetPreviousToken (ref tokenIndex, false);
									if (varName == "this") {
										names.Add ("handle");
									} else if (varName != null) {
										string trimmedName = varName.Trim ();
										if (trimmedName.Length == 0)
											break;
										names.Insert (0, trimmedName);
									}
									varName = GetPreviousToken (ref tokenIndex, false);
								}
								varName = String.Join ("", names.ToArray ());
								foreach (char ch in varName) {
									if (!char.IsLetterOrDigit (ch) && ch != '_') {
										varName = "";
										break;
									}
								}
							}
								
							completionList.Add (new EventCreationCompletionData (textEditorData, varName, delegateType, evt, sb.ToString (), resolver.CallingMember, typeFromDatabase));
						}
						return completionList;
					}
					return null;
				}
				return HandleKeywordCompletion (completionContext, result, tokenIndex, token);
			default:
				if ((Char.IsLetter (completionChar) || completionChar == '_') && TextEditorProperties.EnableAutoCodeCompletion
					    && !stateTracker.Engine.IsInsideDocLineComment
					    && !stateTracker.Engine.IsInsideOrdinaryCommentOrString)
				{
					char prevCh = completionContext.TriggerOffset > 2
							? textEditorData.GetCharAt (completionContext.TriggerOffset - 2)
							: '\0';
					
					char nextCh = completionContext.TriggerOffset < textEditorData.Length
							? textEditorData.GetCharAt (completionContext.TriggerOffset)
							: ' ';
					const string allowedChars = ";,[(){}+-*/%^?:&|~!<>=";
					if (!Char.IsWhiteSpace (nextCh) && allowedChars.IndexOf (nextCh) < 0)
						return null;
					if (Char.IsWhiteSpace (prevCh) || allowedChars.IndexOf (prevCh) >= 0)
					{
						result = FindExpression (dom, completionContext, -1);
						if (result == null)
							return null;
						if (IsInLinqContext (result)) {
							tokenIndex = completionContext.TriggerOffset;
							token = GetPreviousToken (ref tokenIndex, false); // token last typed
							token = GetPreviousToken (ref tokenIndex, false); // possible linq keyword ?
							triggerWordLength = 1;
							
							if (linqKeywords.Contains (token)) {
								if (token == "from") // after from no auto code completion.
									return null;
								result.Expression = "";
								return CreateCtrlSpaceCompletionData (completionContext, result);
							}
							CompletionDataList dataList = new ProjectDomCompletionDataList ();
							CompletionDataCollector col = new CompletionDataCollector (dom, dataList, Document.CompilationUnit, null, new DomLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
							foreach (string kw in linqKeywords) {
								col.Add (kw, "md-keyword");
							}
							return dataList;
						} else if (result.ExpressionContext != ExpressionContext.IdentifierExpected) {
							triggerWordLength = 1;
							bool autoSelect = true;
							int cpos;
							if ((prevCh == ',' || prevCh == '(') && GetParameterCompletionCommandOffset (out cpos)) {
								CodeCompletionContext ctx = CompletionWidget.CreateCodeCompletionContext (cpos);
								NRefactoryParameterDataProvider provider = ParameterCompletionCommand (ctx) as NRefactoryParameterDataProvider;
								if (provider != null) {
									int i = provider.GetCurrentParameterIndex (CompletionWidget, ctx) - 1;
									if (i < provider.Methods[0].Parameters.Count) {
										IType returnType = dom.GetType (provider.Methods[0].Parameters[i].ReturnType);
										autoSelect = returnType == null || returnType.ClassType != ClassType.Delegate;
									}
								}
							}
							if (result.ExpressionContext == ExpressionContext.TypeName)
								autoSelect = false;
							CompletionDataList dataList = CreateCtrlSpaceCompletionData (completionContext, result);
							dataList.AutoSelect = autoSelect;
							return dataList;
						} else {
							result = FindExpression (dom, completionContext, 0);
							tokenIndex = completionContext.TriggerOffset;
								
							// check foreach case, unfortunately the expression finder is too dumb to handle full type names
							// should be overworked if the expression finder is replaced with a mcs ast based analyzer.
							var possibleForeachToken = GetPreviousToken (ref tokenIndex, false); // starting letter
							possibleForeachToken = GetPreviousToken (ref tokenIndex, false); // varname
							
							// read return types to '(' token
							possibleForeachToken = GetPreviousToken (ref tokenIndex, false); // varType
							if (possibleForeachToken == ">") {
								while (possibleForeachToken != "(")
									possibleForeachToken = GetPreviousToken (ref tokenIndex, false);
							} else {
								possibleForeachToken = GetPreviousToken (ref tokenIndex, false); // (
								if (possibleForeachToken == ".")
									while (possibleForeachToken != "(")
										possibleForeachToken = GetPreviousToken (ref tokenIndex, false);
							}
							possibleForeachToken = GetPreviousToken (ref tokenIndex, false); // foreach
							
							if (possibleForeachToken == "foreach") {
								result.ExpressionContext = ExpressionContext.ForeachInToken;
							} else {
								return null;
//								result.ExpressionContext = ExpressionContext.IdentifierExpected;
							}
							result.Expression = "";
							result.Region = DomRegion.Empty;
							
							// identifier has already started with the first letter
							completionContext.TriggerOffset--;
							completionContext.TriggerLineOffset--;
							completionContext.TriggerWordLength = 1;
							return CreateCtrlSpaceCompletionData (completionContext, result);
						}
					}
				}
				break;
			}
			} catch (Exception e) {
				LoggingService.LogError ("Unexpected code completion exception." + Environment.NewLine + 
					"FileName: " + Document.FileName + Environment.NewLine + 
					"Position: line=" + completionContext.TriggerLine + " col=" + completionContext.TriggerLineOffset + Environment.NewLine + 
					"Line text: " + Document.Editor.GetLineText (completionContext.TriggerLine),
					e);
			} finally {
	//			if (timer != null)
	//				timer.Dispose ();
			}
			return null;
		}
		ExpressionResult FindExpression (ProjectDom dom, CodeCompletionContext ctx)
		{
			NewCSharpExpressionFinder expressionFinder = new NewCSharpExpressionFinder (dom);
			try {
				return expressionFinder.FindExpression (textEditorData, ctx.TriggerOffset);
			} catch (Exception ex) {
				LoggingService.LogWarning (ex.Message, ex);
				return null;
			}
		}
		ExpressionResult FindExpression (ProjectDom dom, CodeCompletionContext ctx, int offset)
		{
			NewCSharpExpressionFinder expressionFinder = new NewCSharpExpressionFinder (dom);
			try {
				return expressionFinder.FindExpression (Editor.Text, Math.Max (ctx.TriggerOffset + offset, 0));
			} catch (Exception ex) {
				LoggingService.LogWarning (ex.Message, ex);
				return null;
			}
		}
		public MonoDevelop.Projects.Dom.ResolveResult GetLanguageItem (ProjectDom dom, Mono.TextEditor.TextEditorData data, int offset)
		{
			if (offset < 0)
				return null;
			string fileName = data.Document.FileName;
			IParser parser = ProjectDomService.GetParser (fileName);
			if (parser == null)
				return null;
			
			MonoDevelop.Ide.Gui.Document doc = IdeApp.Workbench.ActiveDocument;
			if (doc == null)
				return null;
			
			IResolver         resolver = parser.CreateResolver (dom, doc, fileName);
			if (resolver == null) 
				return null;
			var expressionFinder = new NewCSharpExpressionFinder (dom);
			
			int wordEnd = Math.Min (offset, data.Length - 1);
			if (data.GetCharAt (wordEnd) == '@')
				wordEnd++;
			while (wordEnd < data.Length && (Char.IsLetterOrDigit (data.GetCharAt (wordEnd)) || data.GetCharAt (wordEnd) == '_'))
				wordEnd++;
			
			while (wordEnd < data.Length - 1 && Char.IsWhiteSpace (data.GetCharAt (wordEnd)))
				wordEnd++;
			/* is checked at the end.
			int saveEnd = wordEnd;
			if (wordEnd < data.Length && data.GetCharAt (wordEnd) == '<') {
				int matchingBracket = data.Document.GetMatchingBracketOffset (wordEnd);
				if (matchingBracket > 0)
					wordEnd = matchingBracket;
				while (wordEnd < data.Length - 1 && Char.IsWhiteSpace (data.GetCharAt (wordEnd)))
					wordEnd++;
			}
			
			bool wasMethodCall = false;
			if (data.GetCharAt (wordEnd) == '(') {
				int matchingBracket = data.Document.GetMatchingBracketOffset (wordEnd);
				if (matchingBracket > 0) {
					wordEnd = matchingBracket;
					wasMethodCall = true;
				}
			}
			if (!wasMethodCall)
				wordEnd = saveEnd;*/

			ExpressionResult expressionResult = expressionFinder.FindExpression (data, wordEnd);
			if (expressionResult == null)
				return null;
			
			ResolveResult resolveResult;
			DocumentLocation loc = data.Document.OffsetToLocation (offset);
			string savedExpression = null;
			
			// special handling for 'var' "keyword"
			if (expressionResult.ExpressionContext == ExpressionContext.IdentifierExpected && expressionResult.Expression != null && expressionResult.Expression.Trim () == "var") {
				int endOffset = data.Document.LocationToOffset (expressionResult.Region.End.Line, expressionResult.Region.End.Column);
				StringBuilder identifer = new StringBuilder ();
				for (int i = endOffset; i >= 0 && i < data.Document.Length; i++) {
					char ch = data.Document.GetCharAt (i);
					if (Char.IsWhiteSpace (ch))
						continue;
					if (ch == '=')
						break;
					if (Char.IsLetterOrDigit (ch) || ch =='_') {
						identifer.Append (ch);
						continue;
					}
					identifer.Length = 0;
					break;
				}
				if (identifer.Length > 0) {
					expressionResult.Expression = identifer.ToString ();
					resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line, loc.Column));
					if (resolveResult != null) {
						resolveResult = new MemberResolveResult (dom.GetType (resolveResult.ResolvedType));
						resolveResult.ResolvedExpression = expressionResult;
						return resolveResult;
					}
				}
			}
			if (expressionResult.ExpressionContext == ExpressionContext.Attribute) {
				savedExpression = expressionResult.Expression;
				expressionResult.Expression = expressionResult.Expression.Trim () + "Attribute";
				expressionResult.ExpressionContext = ExpressionContext.ObjectCreation;
			} 
			resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line, loc.Column));
			if (savedExpression != null && resolveResult == null) {
				expressionResult.Expression = savedExpression;
				resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line, loc.Column));
			}
			// Search for possible generic parameters.
//			if (this.resolveResult == null || this.resolveResult.ResolvedType == null || String.IsNullOrEmpty (this.resolveResult.ResolvedType.Name)) {
			if (!expressionResult.Region.IsEmpty) {
				int j = data.Document.LocationToOffset (expressionResult.Region.End.Line, expressionResult.Region.End.Column);
				int bracket = 0;
				for (int i = j; i >= 0 && i < data.Document.Length; i++) {
					char ch = data.Document.GetCharAt (i);
					if (Char.IsWhiteSpace (ch))
						continue;
					if (ch == '<') {
						bracket++;
					} else if (ch == '>') {
						bracket--;
						if (bracket == 0) {
							expressionResult.Expression += data.Document.GetTextBetween (j, i + 1);
							expressionResult.ExpressionContext = ExpressionContext.ObjectCreation;
							resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line, loc.Column));
							break;
						}
					} else {
						if (bracket == 0)
							break;
					}
				}
			}
			
			// To resolve method overloads the full expression must be parsed.
			// ex.: Overload (1)/ Overload("one") - parsing "Overload" gives just a MethodResolveResult
			// and for constructor initializers it's tried too to to resolve constructor overloads.
			if (resolveResult is ThisResolveResult || 
			    resolveResult is BaseResolveResult || 
			    resolveResult is MethodResolveResult && ((MethodResolveResult)resolveResult).Methods.Count > 1) {
				// put the search offset at the end of the invocation to be able to find the full expression
				// the resolver finds it itself if spaces are between the method name and the argument opening parentheses.
				while (wordEnd < data.Length - 1 && Char.IsWhiteSpace (data.GetCharAt (wordEnd)))
					wordEnd++;
				if (data.GetCharAt (wordEnd) == '(') {
					int matchingBracket = data.Document.GetMatchingBracketOffset (wordEnd);
					if (matchingBracket > 0)
						wordEnd = matchingBracket;
				}
				//Console.WriteLine (expressionFinder.FindFullExpression (txt, wordEnd));
				ResolveResult possibleResult = resolver.Resolve (expressionFinder.FindFullExpression (data, wordEnd), new DomLocation (loc.Line, loc.Column)) ?? resolveResult;
				//Console.WriteLine ("possi:" + resolver.Resolve (expressionFinder.FindFullExpression (txt, wordEnd), new DomLocation (loc.Line, loc.Column)));
				if (possibleResult is MethodResolveResult)
					resolveResult = possibleResult;
			}
			return resolveResult;
		}
예제 #7
0
		internal static RefactoringOptions CreateRefactoringOptions (string text)
		{
			int cursorPosition = -1;
			int endPos = text.IndexOf ('$');
			if (endPos >= 0) {
				cursorPosition = endPos;
				text = text.Substring (0, cursorPosition) + text.Substring (cursorPosition + 1);
			}
			
			int selectionStart = -1;
			int selectionEnd   = -1;
			int idx = text.IndexOf ("<-");
			if (idx >= 0) {
				selectionStart = idx;
				text = text.Substring (0, idx) + text.Substring (idx + 2);
				selectionEnd = idx = text.IndexOf ("->");
				
				text = text.Substring (0, idx) + text.Substring (idx + 2);
				if (cursorPosition < 0)
					cursorPosition = selectionEnd - 1;
			}
			
			TestWorkbenchWindow tww = new TestWorkbenchWindow ();
			TestViewContent sev = new TestViewContent ();
	//		return new RefactoringOptions ();
			
			DotNetProject project = new DotNetAssemblyProject ("C#");
			Solution solution = new Solution ();
			solution.RootFolder.Items.Add (project);
			project.FileName = GetTempFile (".csproj");
			string file = GetTempFile (".cs");
			project.AddFile (file);
			string parsedText = text;
			string editorText = text;
			ProjectDomService.Load (project);
			ProjectDom dom = ProjectDomService.GetProjectDom (project);
			dom.ForceUpdate (true);
			ProjectDomService.Parse (project, file, delegate { return parsedText; });
			ProjectDomService.Parse (project, file, delegate { return parsedText; });
			
			sev.Project = project;
			sev.ContentName = file;
			sev.Text = editorText;
			sev.CursorPosition = cursorPosition;
			
			tww.ViewContent = sev;
			var doc = new MonoDevelop.Ide.Gui.Document (tww);
			doc.Editor.Document.MimeType = "text/x-csharp";
			doc.Editor.Document.FileName = file;
			doc.ParsedDocument = new McsParser ().Parse (null, sev.ContentName, parsedText);
			foreach (var e in doc.ParsedDocument.Errors)
				Console.WriteLine (e);
			if (cursorPosition >= 0)
				doc.Editor.Caret.Offset = cursorPosition;
			if (selectionStart >= 0) 
				doc.Editor.SetSelection (selectionStart, selectionEnd);
			
			NRefactoryResolver resolver = new NRefactoryResolver (dom, 
			                                                      doc.ParsedDocument.CompilationUnit, 
			                                                      sev.Data, 
			                                                      file);
			
			ExpressionResult expressionResult;
			if (selectionStart >= 0) {
				expressionResult = new ExpressionResult (editorText.Substring (selectionStart, selectionEnd - selectionStart).Trim ());
				endPos = selectionEnd;
			} else {
				expressionResult = new NewCSharpExpressionFinder (dom).FindFullExpression (doc.Editor, cursorPosition + 1);
			}
			ResolveResult resolveResult = endPos >= 0 ? resolver.Resolve (expressionResult, new DomLocation (doc.Editor.Caret.Line, doc.Editor.Caret.Column)) : null;
			
			RefactoringOptions result = new RefactoringOptions {
				Document = doc,
				Dom = dom,
				ResolveResult = resolveResult,
				SelectedItem = null
			};
			if (resolveResult is MemberResolveResult)
				result.SelectedItem = ((MemberResolveResult)resolveResult).ResolvedMember;
			if (resolveResult is LocalVariableResolveResult)
				result.SelectedItem = ((LocalVariableResolveResult)resolveResult).LocalVariable;
			if (resolveResult is ParameterResolveResult)
				result.SelectedItem = ((ParameterResolveResult)resolveResult).Parameter;
			result.TestFileProvider = new FileProvider (result);
			return result;
		}