void AddContextCompletion (CompletionDataWrapper wrapper, CppResolver state, AstNode node) { if (state != null && !(node is AstType)) { foreach (var variable in state.LocalVariables) { if (variable.Region.IsInside (location.Line, location.Column - 1)) continue; wrapper.AddVariable (variable); } } if (currentMember is IUnresolvedParameterizedMember && !(node is AstType)) { var param = (IParameterizedMember)currentMember.CreateResolved (ctx); foreach (var p in param.Parameters) { wrapper.AddVariable (p); } } if (currentMember is IUnresolvedMethod) { var method = (IUnresolvedMethod)currentMember; foreach (var p in method.TypeParameters) { wrapper.AddTypeParameter (p); } } Predicate<IType> typePred = null; if (node is Attribute) { var attribute = Compilation.FindType (KnownTypeCode.Attribute); typePred = t => { return t.GetAllBaseTypeDefinitions ().Any (bt => bt.Equals (attribute)); }; } AddTypesAndNamespaces (wrapper, state, node, typePred); wrapper.Result.Add (factory.CreateLiteralCompletionData ("global")); if (!(node is AstType)) { if (currentMember != null) { AddKeywords (wrapper, statementStartKeywords); AddKeywords (wrapper, expressionLevelKeywords); } else if (currentType != null) { AddKeywords (wrapper, typeLevelKeywords); } else { AddKeywords (wrapper, globalLevelKeywords); } var prop = currentMember as IUnresolvedProperty; if (prop != null && prop.Setter != null && prop.Setter.Region.IsInside (location)) wrapper.AddCustom ("value"); if (currentMember is IUnresolvedEvent) wrapper.AddCustom ("value"); if (IsInSwitchContext (node)) { wrapper.AddCustom ("case"); } } AddKeywords (wrapper, primitiveTypesKeywords); if (currentMember != null) wrapper.AddCustom ("var"); wrapper.Result.AddRange (factory.CreateCodeTemplateCompletionData ()); if (node != null && node.Role == AstNode.Roles.Argument) { var resolved = ResolveExpression (CSharpParsedFile, node.Parent, Unit); var invokeResult = resolved != null ? resolved.Item1 as CppInvocationResolveResult : null; if (invokeResult != null) { int argNum = 0; foreach (var arg in node.Parent.Children.Where (c => c.Role == AstNode.Roles.Argument)) { if (arg == node) break; argNum++; } var param = argNum < invokeResult.Member.Parameters.Count ? invokeResult.Member.Parameters [argNum] : null; if (param != null && param.Type.Kind == TypeKind.Enum) { AddEnumMembers (wrapper, param.Type, state); } } } }
IEnumerable<ICompletionData> HandleKeywordCompletion (int wordStart, string word) { if (IsInsideCommentOrString ()) return null; switch (word) { case "using": case "namespace": if (currentType != null) return null; var wrapper = new CompletionDataWrapper (this); AddTypesAndNamespaces (wrapper, GetState (), null, t => false); return wrapper.Result; case "case": return CreateCaseCompletionData (location); // case ",": // case ":": // if (result.ExpressionContext == ExpressionContext.InheritableType) { // IType cls = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new TextLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset)); // CompletionDataList completionList = new ProjectDomCompletionDataList (); // List<string > namespaceList = GetUsedNamespaces (); // var col = new CSharpTextEditorCompletion.CompletionDataCollector (this, 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 = offset; // // // 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, cls, result.Region.Start, 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": if (currentType == null) return null; IType isAsType = null; var isAsExpression = GetExpressionAt (wordStart); if (isAsExpression != null) { var parent = isAsExpression.Item2.Parent; if (parent is VariableInitializer) parent = parent.Parent; if (parent is VariableDeclarationStatement) { var resolved = ResolveExpression (isAsExpression.Item1, parent, isAsExpression.Item3); if (resolved != null) isAsType = resolved.Item1.Type; } } var isAsWrapper = new CompletionDataWrapper (this); AddTypesAndNamespaces (isAsWrapper, GetState (), null, t => isAsType == null || t.GetDefinition ().IsDerivedFrom (isAsType.GetDefinition ())); return isAsWrapper.Result; // { // CompletionDataList completionList = new ProjectDomCompletionDataList (); // ExpressionResult expressionResult = FindExpression (dom, completionContext, wordStart - document.Caret.Offset); // NRefactoryResolver resolver = CreateResolver (); // ResolveResult resolveResult = resolver.Resolve (expressionResult, new TextLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset)); // if (resolveResult != null && resolveResult.ResolvedType != null) { // CompletionDataCollector col = new CompletionDataCollector (this, dom, completionList, Document.CompilationUnit, resolver.CallingType, location); // IType foundType = null; // if (word == "as") { // ExpressionContext exactContext = new NewCSharpExpressionFinder (dom).FindExactContextForAsCompletion (document, 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; } if (!IsLineEmptyUpToEol ()) return null; if (currentType != null && (currentType.Kind == TypeKind.Class || currentType.Kind == TypeKind.Struct)) { string modifiers = document.GetText (firstMod, wordStart - firstMod); return GetOverrideCompletionData (currentType, 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; } if (!IsLineEmptyUpToEol ()) return null; var state = GetState (); if (state.CurrentTypeDefinition != null && (state.CurrentTypeDefinition.Kind == TypeKind.Class || state.CurrentTypeDefinition.Kind == TypeKind.Struct)) { string modifiers = document.GetText (firstMod, wordStart - firstMod); return GetPartialCompletionData (state.CurrentTypeDefinition, modifiers); } return null; case "public": case "protected": case "private": case "internal": case "sealed": case "static": var accessorContext = HandleAccessorContext (); if (accessorContext != null) return accessorContext; wrapper = new CompletionDataWrapper (this); state = GetState (); AddTypesAndNamespaces (wrapper, state, null, null, m => false); AddKeywords (wrapper, typeLevelKeywords); AddKeywords (wrapper, primitiveTypesKeywords); return wrapper.Result; case "new": int j = offset - 4; // string token = GetPreviousToken (ref j, true); IType hintType = null; var expressionOrVariableDeclaration = GetNewExpressionAt (j); AstNode newParentNode = null; AstType hintTypeAst = null; if (expressionOrVariableDeclaration != null) { newParentNode = expressionOrVariableDeclaration.Item2.Parent; if (newParentNode is VariableInitializer) newParentNode = newParentNode.Parent; } if (newParentNode is InvocationExpression) { var invoke = (InvocationExpression)newParentNode; var resolved = ResolveExpression (expressionOrVariableDeclaration.Item1, invoke, expressionOrVariableDeclaration.Item3); if (resolved != null) { var mgr = resolved.Item1 as CppInvocationResolveResult; if (mgr != null) { int i1 = 0; foreach (var a in invoke.Arguments) { if (a == expressionOrVariableDeclaration.Item2) { if (mgr.Member.Parameters.Count > i1) hintType = mgr.Member.Parameters [i1].Type; break; } i1++; } } } } if (newParentNode is ObjectCreateExpression) { var invoke = (ObjectCreateExpression)newParentNode; var resolved = ResolveExpression (expressionOrVariableDeclaration.Item1, invoke, expressionOrVariableDeclaration.Item3); if (resolved != null) { var mgr = resolved.Item1 as CppInvocationResolveResult; if (mgr != null) { int i1 = 0; foreach (var a in invoke.Arguments) { if (a == expressionOrVariableDeclaration.Item2) { if (mgr.Member.Parameters.Count > i1) hintType = mgr.Member.Parameters [i1].Type; break; } i1++; } } } } if (newParentNode is AssignmentExpression) { var assign = (AssignmentExpression)newParentNode; var resolved = ResolveExpression (expressionOrVariableDeclaration.Item1, assign.Left, expressionOrVariableDeclaration.Item3); if (resolved != null) { hintType = resolved.Item1.Type; } } if (newParentNode is VariableDeclarationStatement) { var varDecl = (VariableDeclarationStatement)newParentNode; hintTypeAst = varDecl.Type; var resolved = ResolveExpression (expressionOrVariableDeclaration.Item1, varDecl.Type, expressionOrVariableDeclaration.Item3); if (resolved != null) { hintType = resolved.Item1.Type; } } if (newParentNode is FieldDeclaration) { var varDecl = (FieldDeclaration)newParentNode; hintTypeAst = varDecl.ReturnType; var resolved = ResolveExpression (expressionOrVariableDeclaration.Item1, varDecl.ReturnType, expressionOrVariableDeclaration.Item3); if (resolved != null) hintType = resolved.Item1.Type; } return CreateTypeCompletionData (hintType, hintTypeAst); // IType callingType = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new TextLocation (document.Caret.Line, document.Caret.Column)); // ExpressionContext newExactContext = new NewCSharpExpressionFinder (dom).FindExactContextForNewCompletion (document, 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 = offset - 4; // // string yieldToken = GetPreviousToken (ref j, true); // if (token == "return") { // NRefactoryResolver resolver = CreateResolver (); // resolver.SetupResolver (new TextLocation (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 (wordStart > 0 && document.GetCharAt (wordStart - 1) == '#') return factory.CreatePreProcessorDefinesCompletionData (); return null; case "yield": var yieldDataList = new CompletionDataWrapper (this); DefaultCompletionString = "return"; yieldDataList.AddCustom ("break"); yieldDataList.AddCustom ("return"); return yieldDataList.Result; case "in": var inList = new CompletionDataWrapper (this); var node = Unit.GetNodeAt (location); var rr = ResolveExpression (CSharpParsedFile, node, Unit); AddContextCompletion (inList, rr != null ? rr.Item2 : GetState (), node); return inList.Result; // case "where": // CompletionDataList whereDataList = new CompletionDataList (); // NRefactoryResolver constraintResolver = CreateResolver (); // constraintResolver.SetupResolver (new TextLocation (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 (this, dom, dataList, Document.CompilationUnit, null, new TextLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset)); // foreach (string kw in linqKeywords) { // col.Add (kw, "md-keyword"); // } // return dataList; // } return null; }
IEnumerable<ICompletionData> DefaultControlSpaceItems (Tuple<CppParsedFile, AstNode, CompilationUnit> xp = null, bool controlSpace = true) { var wrapper = new CompletionDataWrapper (this); if (offset >= document.TextLength) offset = document.TextLength - 1; while (offset > 1 && char.IsWhiteSpace (document.GetCharAt (offset))) { offset--; } location = document.GetLocation (offset); if (xp == null) xp = GetExpressionAtCursor (); AstNode node; Tuple<ResolveResult, CppResolver> rr; if (xp != null) { node = xp.Item2; rr = ResolveExpression (xp.Item1, node, xp.Item3); } else { var unit = ParseStub ("a"); node = unit.GetNodeAt (location); rr = ResolveExpression (CSharpParsedFile, node, unit); } if (node is Identifier && node.Parent is ForeachStatement) { var foreachStmt = (ForeachStatement)node.Parent; foreach (var possibleName in GenerateNameProposals (foreachStmt.VariableType)) { if (possibleName.Length > 0) wrapper.Result.Add (factory.CreateLiteralCompletionData (possibleName.ToString ())); } AutoSelect = false; AutoCompleteEmptyMatch = false; return wrapper.Result; } if (node is Identifier && node.Parent is ParameterDeclaration) { if (!controlSpace) return null; // Try Parameter name case var param = node.Parent as ParameterDeclaration; if (param != null) { foreach (var possibleName in GenerateNameProposals (param.Type)) { if (possibleName.Length > 0) wrapper.Result.Add (factory.CreateLiteralCompletionData (possibleName.ToString ())); } AutoSelect = false; AutoCompleteEmptyMatch = false; return wrapper.Result; } } if (Unit != null && (node == null || node is TypeDeclaration)) { var constructor = Unit.GetNodeAt<ConstructorDeclaration> (location.Line, location.Column - 3); if (constructor != null && !constructor.ColonToken.IsNull && constructor.Initializer.IsNull) { wrapper.AddCustom ("this"); wrapper.AddCustom ("base"); return wrapper.Result; } } CppResolver csResolver = null; if (rr != null) csResolver = rr.Item2; if (csResolver == null) { if (node != null) { csResolver = GetState (); //var astResolver = new CSharpAstResolver (csResolver, node, xp != null ? xp.Item1 : CSharpParsedFile); try { //csResolver = astResolver.GetResolverStateBefore (node); Console.WriteLine (csResolver.LocalVariables.Count ()); } catch (Exception e) { Console.WriteLine ("E!!!" + e); } } else { csResolver = GetState (); } } AddContextCompletion (wrapper, csResolver, node); return wrapper.Result; }
IEnumerable<ICompletionData> HandleAccessorContext () { var unit = ParseStub ("get; }", false); var node = unit.GetNodeAt (location, cn => !(cn is CppTokenNode)); if (node is Accessor) node = node.Parent; var contextList = new CompletionDataWrapper (this); if (node is PropertyDeclaration) { contextList.AddCustom ("get"); contextList.AddCustom ("set"); AddKeywords (contextList, accessorModifierKeywords); } else if (node is CustomEventDeclaration) { contextList.AddCustom ("add"); contextList.AddCustom ("remove"); } else { return null; } return contextList.Result; }
IEnumerable<ICompletionData> MagicKeyCompletion (char completionChar, bool controlSpace) { switch (completionChar) { // Magic key completion case ':': case '.': if (IsInsideCommentOrString ()) return Enumerable.Empty<ICompletionData> (); var expr = GetExpressionBeforeCursor (); if (expr == null) return null; // do not complete <number>. (but <number>.<number>.) if (expr.Item2 is PrimitiveExpression) { var pexpr = (PrimitiveExpression)expr.Item2; if (!(pexpr.Value is string || pexpr.Value is char) && !pexpr.LiteralValue.Contains ('.')) return null; } var resolveResult = ResolveExpression (expr.Item1, expr.Item2, expr.Item3); if (resolveResult == null) return null; if (expr.Item2 is AstType) return CreateTypeAndNamespaceCompletionData (location, resolveResult.Item1, expr.Item2, resolveResult.Item2); return CreateCompletionData (location, resolveResult.Item1, expr.Item2, resolveResult.Item2); case '#': if (IsInsideCommentOrString ()) return null; return GetDirectiveCompletionData (); // XML doc completion case '<': if (IsInsideDocComment ()) return GetXmlDocumentationCompletionData (); if (controlSpace) return DefaultControlSpaceItems (); return null; case '>': if (!IsInsideDocComment ()) return null; string lineText = document.GetText (document.GetLineByNumber (location.Line)); int startIndex = Math.Min (location.Column - 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 <= location.Column && 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) document.Insert (offset, "</" + tag + ">"); } return null; // Parameter completion case '(': if (IsInsideCommentOrString ()) return null; var invoke = GetInvocationBeforeCursor (true); if (invoke == null) return null; if (invoke.Item2 is TypeOfExpression) return CreateTypeList (); var invocationResult = ResolveExpression (invoke.Item1, invoke.Item2, invoke.Item3); if (invocationResult == null) return null; var methodGroup = invocationResult.Item1 as MethodGroupResolveResult; if (methodGroup != null) return CreateParameterCompletion (methodGroup, invocationResult.Item2, invoke.Item2, 0, controlSpace); if (controlSpace) return DefaultControlSpaceItems (invoke); return null; case '=': return controlSpace ? DefaultControlSpaceItems () : null; case ',': int cpos2; if (!GetParameterCompletionCommandOffset (out cpos2)) return null; // completionContext = CompletionWidget.CreateCodeCompletionContext (cpos2); // int currentParameter2 = MethodParameterDataProvider.GetCurrentParameterIndex (CompletionWidget, completionContext) - 1; // return CreateParameterCompletion (CreateResolver (), location, ExpressionContext.MethodBody, provider.Methods, currentParameter); break; // Completion on space: case ' ': if (IsInsideCommentOrString ()) return null; int tokenIndex = offset; string token = GetPreviousToken (ref tokenIndex, false); // check propose name, for context <variable name> <ctrl+space> (but only in control space context) //IType isAsType = null; var isAsExpression = GetExpressionAt (offset); if (controlSpace && isAsExpression != null && isAsExpression.Item2 is VariableDeclarationStatement && token != "new") { var parent = isAsExpression.Item2 as VariableDeclarationStatement; var proposeNameList = new CompletionDataWrapper (this); foreach (var possibleName in GenerateNameProposals (parent.Type)) { if (possibleName.Length > 0) proposeNameList.Result.Add (factory.CreateLiteralCompletionData (possibleName.ToString ())); } AutoSelect = false; AutoCompleteEmptyMatch = false; return proposeNameList.Result; } // int tokenIndex = offset; // string token = GetPreviousToken (ref tokenIndex, false); // if (result.ExpressionContext == ExpressionContext.ObjectInitializer) { // resolver = CreateResolver (); // ExpressionContext exactContext = new NewCSharpExpressionFinder (dom).FindExactContextForObjectInitializer (document, 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 ",": int cpos; if (!GetParameterCompletionCommandOffset (out cpos)) break; int currentParameter = GetCurrentParameterIndex (cpos, 0) - 1; if (currentParameter < 0) return null; invoke = GetInvocationBeforeCursor (token == "("); if (invoke == null) return null; invocationResult = ResolveExpression (invoke.Item1, invoke.Item2, invoke.Item3); if (invocationResult == null) return null; methodGroup = invocationResult.Item1 as MethodGroupResolveResult; if (methodGroup != null) return CreateParameterCompletion (methodGroup, invocationResult.Item2, invoke.Item2, currentParameter, controlSpace); return null; case "=": case "==": GetPreviousToken (ref tokenIndex, false); var expressionOrVariableDeclaration = GetExpressionAt (tokenIndex); if (expressionOrVariableDeclaration == null) return null; resolveResult = ResolveExpression (expressionOrVariableDeclaration.Item1, expressionOrVariableDeclaration.Item2, expressionOrVariableDeclaration.Item3); if (resolveResult == null) return null; if (resolveResult.Item1.Type.Kind == TypeKind.Enum) { var wrapper = new CompletionDataWrapper (this); AddContextCompletion (wrapper, resolveResult.Item2, expressionOrVariableDeclaration.Item2); AddEnumMembers (wrapper, resolveResult.Item1.Type, resolveResult.Item2); AutoCompleteEmptyMatch = false; return wrapper.Result; } // // if (resolvedType.FullName == DomReturnType.Bool.FullName) { // CompletionDataList completionList = new ProjectDomCompletionDataList (); // CompletionDataCollector cdc = new CompletionDataCollector (this, dom, completionList, Document.CompilationUnit, resolver.CallingType, location); // completionList.AutoCompleteEmptyMatch = false; // cdc.Add ("true", "md-keyword"); // cdc.Add ("false", "md-keyword"); // resolver.AddAccessibleCodeCompletionData (result.ExpressionContext, cdc); // return completionList; // } // if (resolvedType.ClassType == ClassType.Delegate && token == "=") { // CompletionDataList completionList = new ProjectDomCompletionDataList (); // string parameterDefinition = AddDelegateHandlers (completionList, resolvedType); // string varName = GetPreviousMemberReferenceExpression (tokenIndex); // completionList.Add (new EventCreationCompletionData (document, varName, resolvedType, null, parameterDefinition, resolver.CallingMember, resolvedType)); // // CompletionDataCollector cdc = new CompletionDataCollector (this, dom, completionList, Document.CompilationUnit, resolver.CallingType, location); // resolver.AddAccessibleCodeCompletionData (result.ExpressionContext, cdc); // foreach (var data in completionList) { // if (data is MemberCompletionData) // ((MemberCompletionData)data).IsDelegateExpected = true; // } // return completionList; // } return null; case "+=": case "-=": GetPreviousToken (ref tokenIndex, false); expressionOrVariableDeclaration = GetExpressionAt (tokenIndex); if (expressionOrVariableDeclaration == null) return null; resolveResult = ResolveExpression (expressionOrVariableDeclaration.Item1, expressionOrVariableDeclaration.Item2, expressionOrVariableDeclaration.Item3); if (resolveResult == null) return null; var mrr = resolveResult.Item1 as MemberResolveResult; if (mrr != null) { var evt = mrr.Member as IEvent; if (evt == null) return null; var delegateType = evt.ReturnType; if (delegateType.Kind != TypeKind.Delegate) return null; var wrapper = new CompletionDataWrapper (this); if (currentType != null) { // bool includeProtected = DomType.IncludeProtected (dom, typeFromDatabase, resolver.CallingType); foreach (var method in currentType.Methods) { if (MatchDelegate (delegateType, method) /*&& method.IsAccessibleFrom (dom, resolver.CallingType, resolver.CallingMember, includeProtected) &&*/) { wrapper.AddMember (method); // data.SetText (data.CompletionText + ";"); } } } if (token == "+=") { string parameterDefinition = AddDelegateHandlers (wrapper, delegateType); string varName = GetPreviousMemberReferenceExpression (tokenIndex); wrapper.Result.Add (factory.CreateEventCreationCompletionData (varName, delegateType, evt, parameterDefinition, currentMember, currentType)); } return wrapper.Result; } return null; case ":": /* Breaks constructor initializer case: * if (currentMember == null) { var wrapper = new CompletionDataWrapper (this); AddTypesAndNamespaces (wrapper, GetState (), null, t => currentType != null ? !currentType.Equals (t) : true); return wrapper.Result; }*/ return null; } var keywordCompletion = HandleKeywordCompletion (tokenIndex, token); if (keywordCompletion == null && controlSpace) goto default; return keywordCompletion; // Automatic completion default: if (IsInsideCommentOrString ()) return null; if (IsInLinqContext (offset)) { if (!controlSpace && !(char.IsLetter (completionChar) || completionChar == '_')) return null; tokenIndex = offset; token = GetPreviousToken (ref tokenIndex, false); // token last typed if (!char.IsWhiteSpace (completionChar) && !linqKeywords.Contains (token)) token = GetPreviousToken (ref tokenIndex, false); // token last typed if (linqKeywords.Contains (token)) { if (token == "from") // after from no auto code completion. return null; return DefaultControlSpaceItems (); } var dataList = new CompletionDataWrapper (this); AddKeywords (dataList, linqKeywords); return dataList.Result; } if (currentType != null && currentType.Kind == TypeKind.Enum) return HandleEnumContext (); var contextList = new CompletionDataWrapper (this); var identifierStart = GetExpressionAtCursor (); if (identifierStart != null && identifierStart.Item2 is TypeParameterDeclaration) return null; if (identifierStart != null && identifierStart.Item2 is VariableInitializer && location <= ((VariableInitializer)identifierStart.Item2).NameToken.EndLocation) { return controlSpace ? HandleAccessorContext () ?? DefaultControlSpaceItems (identifierStart) : null; } if (!(char.IsLetter (completionChar) || completionChar == '_') && (!controlSpace || identifierStart == null || !(identifierStart.Item2 is ArrayInitializerExpression))) { return controlSpace ? HandleAccessorContext () ?? DefaultControlSpaceItems (identifierStart) : null; } char prevCh = offset > 2 ? document.GetCharAt (offset - 2) : ';'; char nextCh = offset < document.TextLength ? document.GetCharAt (offset) : ' '; const string allowedChars = ";,[](){}+-*/%^?:&|~!<>="; if (!Char.IsWhiteSpace (nextCh) && allowedChars.IndexOf (nextCh) < 0) return null; if (!(Char.IsWhiteSpace (prevCh) || allowedChars.IndexOf (prevCh) >= 0)) return null; // Do not pop up completion on identifier identifier (should be handled by keyword completion). tokenIndex = offset - 1; token = GetPreviousToken (ref tokenIndex, false); if (token == "class" || token == "interface" || token == "struct" || token == "enum" || token == "namespace") // after these always follows a name return null; int prevTokenIndex = tokenIndex; var prevToken2 = GetPreviousToken (ref prevTokenIndex, false); if (prevToken2 == "delegate") // after these always follows a name return null; if (identifierStart == null && !string.IsNullOrEmpty (token) && !(IsInsideComment (tokenIndex) || IsInsideString (tokenIndex)) && (prevToken2 == ";" || prevToken2 == "{" || prevToken2 == "}")) { char last = token [token.Length - 1]; if (char.IsLetterOrDigit (last) || last == '_' || token == ">") { return HandleKeywordCompletion (tokenIndex, token); } } if (identifierStart == null) { var accCtx = HandleAccessorContext (); if (accCtx != null) return accCtx; return DefaultControlSpaceItems (null, controlSpace); } CppResolver csResolver; AstNode n = identifierStart.Item2; if (n != null && n.Parent is AnonymousTypeCreateExpression) { AutoSelect = false; } // Handle foreach (type name _ if (n is IdentifierExpression) { var prev = n.GetPrevNode () as ForeachStatement; if (prev != null && prev.InExpression.IsNull) { if (controlSpace) { contextList.AddCustom ("in"); return contextList.Result; } return null; } } if (n != null && n.Parent is InvocationExpression) { var invokeParent = (InvocationExpression)n.Parent; var invokeResult = ResolveExpression (identifierStart.Item1, invokeParent.Target, identifierStart.Item3); var mgr = invokeResult != null ? invokeResult.Item1 as MethodGroupResolveResult : null; if (mgr != null) { int idx = 0; foreach (var arg in invokeParent.Arguments) { if (arg == n) break; idx++; } foreach (var method in mgr.Methods) { if (idx < method.Parameters.Count && method.Parameters[idx].Type.Kind == TypeKind.Delegate) { AutoSelect = false; AutoCompleteEmptyMatch = false; } foreach (var p in method.Parameters) { contextList.AddVariable (p); } } idx++; foreach (var list in mgr.GetExtensionMethods ()) { foreach (var method in list) { if (idx < method.Parameters.Count && method.Parameters[idx].Type.Kind == TypeKind.Delegate) { AutoSelect = false; AutoCompleteEmptyMatch = false; } } } } } if (n != null && n.Parent is ObjectCreateExpression) { var invokeResult = ResolveExpression (identifierStart.Item1, n.Parent, identifierStart.Item3); var mgr = invokeResult != null ? invokeResult.Item1 as ResolveResult : null; if (mgr != null) { foreach (var constructor in mgr.Type.GetConstructors ()) { foreach (var p in constructor.Parameters) { contextList.AddVariable (p); } } } } if (n is IdentifierExpression) { var bop = n.Parent as BinaryOperatorExpression; Expression evaluationExpr = null; if (bop != null && bop.Right == n && (bop.Operator == BinaryOperatorType.Equality || bop.Operator == BinaryOperatorType.InEquality)) { evaluationExpr = bop.Left; } // check for compare to enum case if (evaluationExpr != null) { resolveResult = ResolveExpression (identifierStart.Item1, evaluationExpr, identifierStart.Item3); if (resolveResult != null && resolveResult.Item1.Type.Kind == TypeKind.Enum) { var wrapper = new CompletionDataWrapper (this); AddContextCompletion (wrapper, resolveResult.Item2, evaluationExpr); AddEnumMembers (wrapper, resolveResult.Item1.Type, resolveResult.Item2); AutoCompleteEmptyMatch = false; return wrapper.Result; } } } if (n is Identifier && n.Parent is ForeachStatement) { if (controlSpace) return DefaultControlSpaceItems (); return null; } if (n is ArrayInitializerExpression) { // check for new [] {...} expression -> no need to resolve the type there var parent = n.Parent as ArrayCreateExpression; if (parent != null && parent.Type.IsNull) return DefaultControlSpaceItems (); var initalizerResult = ResolveExpression (identifierStart.Item1, n.Parent, identifierStart.Item3); var concreteNode = identifierStart.Item3.GetNodeAt<IdentifierExpression> (location); // check if we're on the right side of an initializer expression if (concreteNode != null && concreteNode.Parent != null && concreteNode.Parent.Parent != null && concreteNode.Identifier != "a" && concreteNode.Parent.Parent is NamedExpression) { return DefaultControlSpaceItems (); } if (initalizerResult != null && initalizerResult.Item1.Type.Kind != TypeKind.Unknown) { foreach (var property in initalizerResult.Item1.Type.GetProperties ()) { if (!property.IsPublic) continue; contextList.AddMember (property); } foreach (var field in initalizerResult.Item1.Type.GetFields ()) { if (!field.IsPublic) continue; contextList.AddMember (field); } return contextList.Result; } return DefaultControlSpaceItems (); } if (n != null/* && !(identifierStart.Item2 is TypeDeclaration)*/) { csResolver = new CppResolver (ctx); var nodes = new List<AstNode> (); nodes.Add (n); if (n.Parent is ICSharpCode.NRefactory.Cpp.Attribute) nodes.Add (n.Parent); var astResolver = new CppAstResolver (csResolver, identifierStart.Item3, identifierStart.Item1); astResolver.ApplyNavigator (new NodeListResolveVisitorNavigator (nodes)); try { csResolver = astResolver.GetResolverStateBefore (n); } catch (Exception) { csResolver = GetState (); } // add attribute properties. if (n.Parent is ICSharpCode.NRefactory.Cpp.Attribute) { var resolved = astResolver.Resolve (n.Parent); if (resolved != null && resolved.Type != null) { foreach (var property in resolved.Type.GetProperties (p => p.Accessibility == Accessibility.Public)) { contextList.AddMember (property); } foreach (var field in resolved.Type.GetFields (p => p.Accessibility == Accessibility.Public)) { contextList.AddMember (field); } } } } else { csResolver = GetState (); } // identifier has already started with the first letter offset--; AddContextCompletion (contextList, csResolver, identifierStart.Item2); return contextList.Result; // if (stub.Parent is BlockStatement) // result = FindExpression (dom, completionContext, -1); // if (result == null) // return null; // else if (result.ExpressionContext != ExpressionContext.IdentifierExpected) { // triggerWordLength = 1; // bool autoSelect = true; // IType returnType = null; // if ((prevCh == ',' || prevCh == '(') && GetParameterCompletionCommandOffset (out cpos)) { // ctx = CompletionWidget.CreateCodeCompletionContext (cpos); // NRefactoryParameterDataProvider dataProvider = ParameterCompletionCommand (ctx) as NRefactoryParameterDataProvider; // if (dataProvider != null) { // int i = dataProvider.GetCurrentParameterIndex (CompletionWidget, ctx) - 1; // foreach (var method in dataProvider.Methods) { // if (i < method.Parameters.Count) { // returnType = dom.GetType (method.Parameters [i].ReturnType); // autoSelect = returnType == null || returnType.ClassType != ClassType.Delegate; // break; // } // } // } // } // // Bug 677531 - Auto-complete doesn't always highlight generic parameter in method signature // //if (result.ExpressionContext == ExpressionContext.TypeName) // // autoSelect = false; // CompletionDataList dataList = CreateCtrlSpaceCompletionData (completionContext, result); // AddEnumMembers (dataList, returnType); // dataList.AutoSelect = autoSelect; // return dataList; // } else { // result = FindExpression (dom, completionContext, 0); // tokenIndex = offset; // // // 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 != null && possibleForeachToken != "(") { // possibleForeachToken = GetPreviousToken (ref tokenIndex, false); // } // } else { // possibleForeachToken = GetPreviousToken (ref tokenIndex, false); // ( // if (possibleForeachToken == ".") // while (possibleForeachToken != null && 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; // // return CreateCtrlSpaceCompletionData (completionContext, result); // } // break; } return null; }
string AddDelegateHandlers (CompletionDataWrapper completionList, IType delegateType, bool addSemicolon = true, bool addDefault = true) { IMethod delegateMethod = delegateType.GetDelegateInvokeMethod (); var thisLineIndent = GetLineIndent (location.Line); string delegateEndString = EolMarker + thisLineIndent + "}" + (addSemicolon ? ";" : ""); bool containsDelegateData = completionList.Result.Any (d => d.DisplayText.StartsWith ("delegate(")); if (addDefault) completionList.AddCustom ("delegate", "Creates anonymous delegate.", "delegate {" + EolMarker + thisLineIndent + IndentString + "|" + delegateEndString); var sb = new StringBuilder ("("); var sbWithoutTypes = new StringBuilder ("("); for (int k = 0; k < delegateMethod.Parameters.Count; k++) { if (k > 0) { sb.Append (", "); sbWithoutTypes.Append (", "); } var parameterType = delegateMethod.Parameters [k].Type; sb.Append (GetShortType (parameterType, GetState ())); sb.Append (" "); sb.Append (delegateMethod.Parameters [k].Name); sbWithoutTypes.Append (delegateMethod.Parameters [k].Name); } sb.Append (")"); sbWithoutTypes.Append (")"); completionList.AddCustom ("delegate" + sb, "Creates anonymous delegate.", "delegate" + sb + " {" + EolMarker + thisLineIndent + IndentString + "|" + delegateEndString); if (!completionList.Result.Any (data => data.DisplayText == sbWithoutTypes.ToString ())) completionList.AddCustom (sbWithoutTypes.ToString (), "Creates lambda expression.", sbWithoutTypes + " => |" + (addSemicolon ? ";" : "")); /* TODO:Make factory method out of it. // It's needed to temporarly disable inserting auto matching bracket because the anonymous delegates are selectable with '(' // otherwise we would end up with () => ) if (!containsDelegateData) { var savedValue = MonoDevelop.SourceEditor.DefaultSourceEditorOptions.Instance.AutoInsertMatchingBracket; MonoDevelop.SourceEditor.DefaultSourceEditorOptions.Instance.AutoInsertMatchingBracket = false; completionList.Result.CompletionListClosed += delegate { MonoDevelop.SourceEditor.DefaultSourceEditorOptions.Instance.AutoInsertMatchingBracket = savedValue; }; }*/ return sb.ToString (); }
static void AddKeywords (CompletionDataWrapper wrapper, IEnumerable<string> keywords) { foreach (string keyword in keywords) { wrapper.AddCustom (keyword); } }