diff options
author | Mike Krüger <mkrueger@xamarin.com> | 2011-11-02 15:44:00 +0400 |
---|---|---|
committer | Mike Krüger <mkrueger@xamarin.com> | 2011-11-02 15:44:00 +0400 |
commit | ed16848a5761e4b5f2cb9d52b22f12d5a537966e (patch) | |
tree | c9dd6d370fbff2946d01af5e237dce076b7b2974 /main/contrib | |
parent | 7599c630af310f5900d3166083a140fbd5efc640 (diff) |
[NRefactory] Synced with nrefactory.
Diffstat (limited to 'main/contrib')
11 files changed, 2771 insertions, 2671 deletions
diff --git a/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index 00386f7827..fd7a51b823 100644 --- a/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -1,2014 +1,2086 @@ -//
-// CSharpCompletionEngine.cs
-//
-// Author:
-// Mike Krüger <mkrueger@xamarin.com>
-//
-// Copyright (c) 2011 Xamarin Inc. (http://xamarin.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-using ICSharpCode.NRefactory.Completion;
-using ICSharpCode.NRefactory.CSharp.Refactoring;
-using ICSharpCode.NRefactory.CSharp.Resolver;
-using ICSharpCode.NRefactory.Editor;
-using ICSharpCode.NRefactory.Semantics;
-using ICSharpCode.NRefactory.TypeSystem;
-
-namespace ICSharpCode.NRefactory.CSharp.Completion
-{
- public class CSharpCompletionEngine : CSharpCompletionEngineBase
- {
- internal ICompletionDataFactory factory;
-
- #region Additional input properties
- public CSharpFormattingOptions FormattingPolicy { get; set; }
- public string EolMarker { get; set; }
- public string IndentString { get; set; }
- #endregion
-
- #region Result properties
- public bool AutoCompleteEmptyMatch;
- public bool AutoSelect;
- public string DefaultCompletionString;
- #endregion
-
- public CSharpCompletionEngine (IDocument document, ICompletionDataFactory factory)
- {
- this.document = document;
- this.factory = factory;
- }
-
- public IEnumerable<ICompletionData> GetCompletionData (int offset, bool controlSpace)
- {
- this.AutoCompleteEmptyMatch = true;
- this.AutoSelect = true;
- this.DefaultCompletionString = null;
- SetOffset (offset);
- if (offset > 0) {
- char lastChar = document.GetCharAt (offset - 1);
- var result = MagicKeyCompletion (lastChar, controlSpace) ?? Enumerable.Empty<ICompletionData> ();
- if (controlSpace && char.IsWhiteSpace (lastChar)) {
- offset -= 2;
- while (offset >= 0 && char.IsWhiteSpace (document.GetCharAt (offset)))
- offset--;
- if (offset > 0) {
- var nonWsResult = MagicKeyCompletion (document.GetCharAt (offset), controlSpace);
- if (nonWsResult != null)
- result = result.Concat (nonWsResult);
- }
- }
-
- return result;
- }
- return Enumerable.Empty<ICompletionData> ();
- }
-
- IEnumerable<string> GenerateNameProposals (AstType type)
- {
- if (type is PrimitiveType) {
- var pt = (PrimitiveType)type;
- Console.WriteLine (pt.Keyword);
- switch (pt.Keyword) {
- case "object":
- yield return "o";
- yield return "obj";
- break;
- case "bool":
- yield return "b";
- yield return "pred";
- break;
- case "double":
- case "float":
- case "decimal":
- yield return "d";
- yield return "f";
- yield return "m";
- break;
- default:
- yield return "i";
- yield return "j";
- yield return "k";
- break;
- }
- yield break;
- }
-
- var names = new List<string> ();
- int offset1 = document.GetOffset (type.StartLocation);
- int offset2 = document.GetOffset (type.EndLocation);
-
- string name = document.GetText (offset1, offset2 - offset1);
- 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));
-
- var 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]);
- }
- yield return possibleName.ToString ();
- }
- }
-
- 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);
- 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.Resolve (ctx);
- if (!delegateType.IsDelegate ())
- return null;
-
- var wrapper = new CompletionDataWrapper (this);
- if (currentType != null) {
-// bool includeProtected = DomType.IncludeProtected (dom, typeFromDatabase, resolver.CallingType);
- foreach (var method in currentType.GetMethods (ctx)) {
- 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 ":":
- 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)) {
- tokenIndex = offset;
- 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;
- }
-
- var contextList = new CompletionDataWrapper (this);
-
- var identifierStart = GetExpressionAtCursor ();
- if (!(char.IsLetter (completionChar) || completionChar == '_') && (!controlSpace || identifierStart == null || !(identifierStart.Item2 is ArrayInitializerExpression))) {
- return controlSpace ? HandleAccessorContext () ?? DefaultControlSpaceItems () : null;
- }
-
- char prevCh = offset > 2 ? document.GetCharAt (offset - 2) : '\0';
- 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 (identifierStart == null && !string.IsNullOrEmpty (token) && !(IsInsideComment (tokenIndex) || IsInsideString (tokenIndex))) {
- char last = token [token.Length - 1];
- if (char.IsLetterOrDigit (last) || last == '_' || token == ">") {
- return null;
- }
- }
- if (identifierStart == null)
- return HandleAccessorContext () ?? DefaultControlSpaceItems ();
-
- CSharpResolver csResolver;
- AstNode n = identifierStart.Item2;
- if (n is ArrayInitializerExpression) {
- 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) {
-
- foreach (var property in initalizerResult.Item1.Type.GetProperties (ctx)) {
- if (!property.IsPublic)
- continue;
- contextList.AddMember (property);
- }
- foreach (var field in initalizerResult.Item1.Type.GetFields (ctx)){
- if (!field.IsPublic)
- continue;
- contextList.AddMember (field);
- }
- return contextList.Result;
- }
- return null;
- }
- if (n != null/* && !(identifierStart.Item2 is TypeDeclaration)*/) {
- csResolver = new CSharpResolver (ctx, System.Threading.CancellationToken.None);
- var nodes = new List<AstNode> ();
- nodes.Add (n);
- if (n.Parent is ICSharpCode.NRefactory.CSharp.Attribute)
- nodes.Add (n.Parent);
- var navigator = new NodeListResolveVisitorNavigator (nodes);
- var visitor = new ResolveVisitor (csResolver, identifierStart.Item1, navigator);
- visitor.Scan (identifierStart.Item3);
- try {
- csResolver = visitor.GetResolverStateBefore (n);
- } catch (Exception) {
- csResolver = GetState ();
- }
- // add attribute properties.
- if (n.Parent is ICSharpCode.NRefactory.CSharp.Attribute) {
- var resolved = visitor.GetResolveResult (n.Parent);
- if (resolved != null && resolved.Type != null) {
- foreach (var property in resolved.Type.GetProperties (ctx).Where (p => p.Accessibility == Accessibility.Public)) {
- contextList.AddMember (property);
- }
- foreach (var field in resolved.Type.GetFields (ctx).Where (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;
- }
-
- bool IsInLinqContext (int offset)
- {
- string token;
- while (null != (token = GetPreviousToken (ref offset, true))) {
- if (token == "from")
- return true;
- if (token == ";")
- return false;
- }
- return false;
- }
-
- IEnumerable<ICompletionData> HandleAccessorContext ()
- {
- var unit = ParseStub ("get; }", false);
- var node = unit.GetNodeAt (location, cn => !(cn is CSharpTokenNode));
- 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> DefaultControlSpaceItems ()
- {
- var wrapper = new CompletionDataWrapper (this);
- while (offset > 0 && char.IsWhiteSpace (document.GetCharAt (offset))) {
- offset--;
- }
- location = document.GetLocation (offset);
- var xp = GetExpressionAtCursor ();
-
- AstNode node;
- Tuple<ResolveResult, CSharpResolver> rr;
- if (xp != null) {
- node = xp.Item2;
- rr = ResolveExpression (xp.Item1, node, xp.Item3);
- } else {
- node = Unit.GetNodeAt (location);
- rr = ResolveExpression (CSharpParsedFile, node, Unit);
- }
-
- AddContextCompletion (wrapper, rr != null && (node is Expression) ? rr.Item2 : GetState (), node);
-
- return wrapper.Result;
- }
-
- void AddContextCompletion (CompletionDataWrapper wrapper, CSharpResolver state, AstNode node)
- {
- if (state == null)
- return;
- foreach (var variable in state.LocalVariables) {
- wrapper.AddVariable (variable);
- }
- if (state.CurrentMember is IParameterizedMember) {
- var param = (IParameterizedMember)state.CurrentMember;
- foreach (var p in param.Parameters) {
- wrapper.AddVariable (p);
- }
- }
-
- if (state.CurrentMember is IMethod) {
- var method = (IMethod)state.CurrentMember;
- foreach (var p in method.TypeParameters) {
- wrapper.AddTypeParameter (p);
- }
- }
- Predicate<ITypeDefinition> typePred = null;
- if (node is Attribute) {
- var attribute = ctx.GetTypeDefinition ("System", "Attribute", 0, StringComparer.Ordinal);
- typePred = t => t.GetAllBaseTypeDefinitions (ctx).Any (bt => bt.Equals (attribute));
- }
- AddTypesAndNamespaces (wrapper, state, node, typePred);
-
- wrapper.Result.Add (factory.CreateLiteralCompletionData ("global"));
- if (state.CurrentMember != null) {
- AddKeywords (wrapper, statementStartKeywords);
- AddKeywords (wrapper, expressionLevelKeywords);
- } else if (state.CurrentTypeDefinition != null) {
- AddKeywords (wrapper, typeLevelKeywords);
- } else {
- AddKeywords (wrapper, globalLevelKeywords);
- }
-
- if (IsInSwitchContext(node)) {
- wrapper.AddCustom ("case");
- wrapper.AddCustom ("default");
- }
-
- AddKeywords (wrapper, primitiveTypesKeywords);
- wrapper.Result.AddRange (factory.CreateCodeTemplateCompletionData ());
- }
-
- static bool IsInSwitchContext(AstNode node)
- {
- var n = node;
- while (n != null && !(n is MemberDeclaration)) {
- if (n is SwitchStatement)
- return true;
- if (n is BlockStatement)
- return false;
- n = n.Parent;
- }
- return false;
- }
-
- void AddTypesAndNamespaces (CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, Predicate<ITypeDefinition> typePred = null, Predicate<IMember> memberPred = null)
- {
- var currentType = state.CurrentTypeDefinition ?? this.currentType;
- var currentMember = state.CurrentMember ?? this.currentMember;
- if (currentType != null) {
- for (var ct = currentType; ct != null; ct = ct.DeclaringTypeDefinition) {
- foreach (var nestedType in ct.NestedTypes) {
- if (typePred == null || typePred (nestedType)) {
- string name = nestedType.Name;
- if (node is Attribute && name.EndsWith ("Attribute") && name.Length > "Attribute".Length)
- name = name.Substring (0, name.Length - "Attribute".Length);
- wrapper.AddType (nestedType, name);
- }
- }
- }
- if (currentMember != null) {
- foreach (var member in currentType.Resolve (ctx).GetMembers (ctx)) {
- if (memberPred == null || memberPred (member))
- wrapper.AddMember (member);
- }
- }
- foreach (var p in currentType.TypeParameters) {
- wrapper.AddTypeParameter (p);
- }
- }
-
- for (var n = state.CurrentUsingScope; n != null; n = n.Parent) {
- foreach (var pair in n.UsingAliases) {
- wrapper.AddNamespace ("", pair.Key);
- }
-
- foreach (var u in n.Usings) {
- var ns = u.ResolveNamespace (ctx);
- if (ns == null)
- continue;
- foreach (var type in ctx.GetTypes (ns.NamespaceName, StringComparer.Ordinal)) {
- if (typePred == null || typePred (type)) {
- string name = type.Name;
- if (node is Attribute && name.EndsWith ("Attribute") && name.Length > "Attribute".Length)
- name = name.Substring (0, name.Length - "Attribute".Length);
- wrapper.AddType (type, name);
- }
- }
- }
-
- foreach (var type in ctx.GetTypes (n.NamespaceName, StringComparer.Ordinal)) {
- if (typePred == null || typePred (type)) {
- wrapper.AddType (type, type.Name);
- }
- }
-
- foreach (var curNs in ctx.GetNamespaces ().Where (sn => sn.StartsWith (n.NamespaceName) && sn != n.NamespaceName)) {
- wrapper.AddNamespace (n.NamespaceName, curNs);
- }
- }
- }
-
- 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.IsDerivedFrom (isAsType.GetDefinition (), ctx));
- 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;
- var overrideCls = CSharpParsedFile.GetInnermostTypeDefinition (location);
-
- if (overrideCls != null && (overrideCls.Kind == TypeKind.Class || overrideCls.Kind == TypeKind.Struct)) {
- string modifiers = document.GetText (firstMod, wordStart - firstMod);
- return GetOverrideCompletionData (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;
-// }
-// if (!IsLineEmptyUpToEol ())
-// return null;
-//
-// overrideCls = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new TextLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
-// if (overrideCls != null && (overrideCls.ClassType == ClassType.Class || overrideCls.ClassType == ClassType.Struct)) {
-// string modifiers = document.GetTextBetween (firstMod, wordStart);
-// return GetPartialCompletionData (completionContext, overrideCls, modifiers);
-// }
-// return null;
-//
- case "public":
- case "protected":
- case "private":
- case "internal":
- case "sealed":
- case "static":
- wrapper = new CompletionDataWrapper (this);
- var 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 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 (stateTracker.Engine.IsInsidePreprocessorDirective)
-// return GetDefineCompletionData ();
-// 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;
- }
-
- bool IsLineEmptyUpToEol ()
- {
- var line = document.GetLineByNumber (location.Line);
- for (int j = offset; j < line.EndOffset; j++) {
- char ch = document.GetCharAt (j);
- if (!char.IsWhiteSpace (ch))
- return false;
- }
- return true;
- }
- string GetLineIndent (int lineNr)
- {
- var line = document.GetLineByNumber (lineNr);
- for (int j = offset; j < line.EndOffset; j++) {
- char ch = document.GetCharAt (j);
- if (!char.IsWhiteSpace (ch))
- return document.GetText (line.Offset, j - line.Offset - 1);
- }
- return "";
- }
-
- IEnumerable<ICompletionData> CreateTypeCompletionData (IType hintType, AstType hintTypeAst)
- {
- var wrapper = new CompletionDataWrapper (this);
- var state = GetState ();
- Predicate<ITypeDefinition> pred = null;
- if (hintType != null) {
- if (!hintType.Equals (SharedTypes.UnknownType)) {
- var lookup = new MemberLookup (ctx, currentType, ProjectContent);
- pred = t => {
- // check if type is in inheritance tree.
- if (hintType.GetDefinition () != null && !t.IsDerivedFrom (hintType.GetDefinition (), ctx))
- return false;
- // check for valid constructors
- if (t.Methods.Count (m => m.IsConstructor) == 0)
- return true;
- bool isProtectedAllowed = currentType != null ? currentType.IsDerivedFrom (t, ctx) : false;
- return t.Methods.Any (m => m.IsConstructor && lookup.IsAccessible (m, isProtectedAllowed));
- };
- DefaultCompletionString = GetShortType (hintType, GetState ());
- wrapper.AddType (hintType, DefaultCompletionString);
- } else {
- DefaultCompletionString = hintTypeAst.ToString ();
- wrapper.AddType (hintType, DefaultCompletionString);
- }
- }
- AddTypesAndNamespaces (wrapper, state, null, pred, m => false);
- AddKeywords (wrapper, primitiveTypesKeywords.Where (k => k != "void"));
- AutoCompleteEmptyMatch = true;
- return wrapper.Result;
- }
-
- IEnumerable<ICompletionData> GetOverrideCompletionData (ITypeDefinition type, string modifiers)
- {
- var wrapper = new CompletionDataWrapper (this);
- var alreadyInserted = new Dictionary<string, bool> ();
- bool addedVirtuals = false;
-
- int declarationBegin = offset;
- int j = declarationBegin;
- for (int i = 0; i < 3; i++) {
- switch (GetPreviousToken (ref j, true)) {
- case "public":
- case "protected":
- case "private":
- case "internal":
- case "sealed":
- case "override":
- declarationBegin = j;
- break;
- case "static":
- return null; // don't add override completion for static members
- }
- }
- foreach (var baseType in type.GetAllBaseTypeDefinitions (ctx)) {
- AddVirtuals (alreadyInserted, wrapper, type, modifiers, baseType, declarationBegin);
- addedVirtuals = true;
- }
- if (!addedVirtuals)
- AddVirtuals (alreadyInserted, wrapper, type, modifiers, ctx.GetTypeDefinition (typeof(object)), declarationBegin);
- return wrapper.Result;
- }
-
- static string GetNameWithParamCount (IMember member)
- {
- var e = member as IMethod;
- if (e == null || e.TypeParameters.Count == 0)
- return member.Name;
- return e.Name + "`" + e.TypeParameters.Count;
- }
-
- void AddVirtuals (Dictionary<string, bool> alreadyInserted, CompletionDataWrapper col, ITypeDefinition type, string modifiers, ITypeDefinition curType, int declarationBegin)
- {
- if (curType == null)
- return;
- foreach (var m in curType.Methods.Where (m => !m.IsConstructor && !m.IsDestructor).Cast<IMember> ().Concat (curType.Properties.Cast<IMember> ())) {
- if (m.IsSynthetic || curType.Kind != TypeKind.Interface && !(m.IsVirtual || m.IsOverride || m.IsAbstract))
- continue;
- // filter out the "Finalize" methods, because finalizers should be done with destructors.
- if (m is IMethod && m.Name == "Finalize")
- continue;
-
- var data = factory.CreateNewOverrideCompletionData (declarationBegin, type, m);
- string text = GetNameWithParamCount (m);
-
- // check if the member is already implemented
- bool foundMember = type.Members.Any (cm => GetNameWithParamCount (cm) == text);
- if (!foundMember && !alreadyInserted.ContainsKey (text)) {
- alreadyInserted [text] = true;
- data.CompletionCategory = col.GetCompletionCategory (curType);
- col.Add (data);
- }
- }
- }
-
- static void AddKeywords (CompletionDataWrapper wrapper, IEnumerable<string> keywords)
- {
- foreach (string keyword in keywords) {
- wrapper.AddCustom (keyword);
- }
- }
-
- public string GetPreviousMemberReferenceExpression (int tokenIndex)
- {
- string result = GetPreviousToken (ref tokenIndex, false);
- result = GetPreviousToken (ref tokenIndex, false);
- if (result != ".") {
- result = null;
- } else {
- var names = new List<string> ();
- while (result == ".") {
- result = GetPreviousToken (ref tokenIndex, false);
- if (result == "this") {
- names.Add ("handle");
- } else if (result != null) {
- string trimmedName = result.Trim ();
- if (trimmedName.Length == 0)
- break;
- names.Insert (0, trimmedName);
- }
- result = GetPreviousToken (ref tokenIndex, false);
- }
- result = String.Join ("", names.ToArray ());
- foreach (char ch in result) {
- if (!char.IsLetterOrDigit (ch) && ch != '_') {
- result = "";
- break;
- }
- }
- }
- return result;
- }
-
- bool MatchDelegate (IType delegateType, IMethod method)
- {
- var delegateMethod = delegateType.GetDelegateInvokeMethod ();
- if (delegateMethod == null || delegateMethod.Parameters.Count != method.Parameters.Count)
- return false;
-
- for (int i = 0; i < delegateMethod.Parameters.Count; i++) {
- if (!delegateMethod.Parameters [i].Type.Resolve (ctx).Equals (method.Parameters [i].Type.Resolve (ctx)))
- return false;
- }
- return true;
- }
-
- 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.Resolve (ctx);
- 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 ();
- }
-
- bool IsAccessibleFrom (IEntity member, ITypeDefinition calledType, IMember currentMember, bool includeProtected)
- {
- if (currentMember == null)
- return member.IsStatic || member.IsPublic;
-// if (currentMember is MonoDevelop.Projects.Dom.BaseResolveResult.BaseMemberDecorator)
-// return member.IsPublic | member.IsProtected;
- // if (member.IsStatic && !IsStatic)
- // return false;
- if (member.IsPublic || calledType != null && calledType.Kind == TypeKind.Interface && !member.IsProtected)
- return true;
- if (member.DeclaringTypeDefinition != null) {
- if (member.DeclaringTypeDefinition.Kind == TypeKind.Interface)
- return IsAccessibleFrom (member.DeclaringTypeDefinition, calledType, currentMember, includeProtected);
-
- if (member.IsProtected && !(member.DeclaringTypeDefinition.IsProtectedOrInternal && !includeProtected))
- return includeProtected;
- }
- if (member.IsInternal || member.IsProtectedAndInternal || member.IsProtectedOrInternal) {
- var type1 = member is ITypeDefinition ? (ITypeDefinition)member : member.DeclaringTypeDefinition;
- var type2 = currentMember is ITypeDefinition ? (ITypeDefinition)currentMember : currentMember.DeclaringTypeDefinition;
- bool result;
- // easy case, projects are the same
- if (type1.ProjectContent == type2.ProjectContent) {
- result = true;
- } else if (type1.ProjectContent != null) {
- // maybe type2 hasn't project dom set (may occur in some cases), check if the file is in the project
- //TODO !!
-// result = type1.ProjectContent.Annotation<MonoDevelop.Projects.Project> ().GetProjectFile (type2.Region.FileName) != null;
- result = false;
- } else if (type2.ProjectContent != null) {
- //TODO!!
-// result = type2.ProjectContent.Annotation<MonoDevelop.Projects.Project> ().GetProjectFile (type1.Region.FileName) != null;
- result = false;
- } else {
- // should never happen !
- result = true;
- }
- return member.IsProtectedAndInternal ? includeProtected && result : result;
- }
-
- if (!(currentMember is IType) && (currentMember.DeclaringTypeDefinition == null || member.DeclaringTypeDefinition == null))
- return false;
-
- // inner class
- var declaringType = currentMember.DeclaringTypeDefinition;
- while (declaringType != null) {
- if (declaringType.ReflectionName == currentMember.DeclaringType.ReflectionName)
- return true;
- declaringType = declaringType.DeclaringTypeDefinition;
- }
-
-
- return currentMember.DeclaringTypeDefinition != null && member.DeclaringTypeDefinition.FullName == currentMember.DeclaringTypeDefinition.FullName;
- }
-
- IEnumerable<ICompletionData> CreateTypeAndNamespaceCompletionData (TextLocation location, ResolveResult resolveResult, AstNode resolvedNode, CSharpResolver state)
- {
- if (resolveResult == null || resolveResult.IsError)
- return null;
- var result = new CompletionDataWrapper (this);
-
- if (resolveResult is NamespaceResolveResult) {
- var nr = (NamespaceResolveResult)resolveResult;
- foreach (var cl in ctx.GetTypes (nr.NamespaceName, StringComparer.Ordinal)) {
- result.AddType (cl, cl.Name);
- }
- foreach (var ns in ctx.GetNamespaces ().Where (n => n.Length > nr.NamespaceName.Length && n.StartsWith (nr.NamespaceName))) {
- result.AddNamespace (nr.NamespaceName, ns);
- }
- } else if (resolveResult is TypeResolveResult) {
- var type = resolveResult.Type.Resolve (ctx);
- foreach (var nested in type.GetNestedTypes (ctx)) {
- result.AddType (nested, nested.Name);
- }
- }
- return result.Result;
- }
-
- IEnumerable<ICompletionData> CreateTypeList ()
- {
- foreach (var cl in ctx.GetTypes ("", StringComparer.Ordinal)) {
- yield return factory.CreateTypeCompletionData (cl, cl.Name);
- }
- foreach (var ns in ctx.GetNamespaces ()) {
- string name = ns;
- int idx = name.IndexOf (".");
- if (idx >= 0)
- name = name.Substring (0, idx);
- yield return factory.CreateNamespaceCompletionData (name);
- }
- }
-
- public ITypeDefinition GetTypeFromContext (ITypeDefinition type)
- {
- if (type == null || type.DeclaringType != null)
- return type;
- var result = ctx.GetTypeDefinition (type.Namespace, type.Name, type.TypeParameterCount, StringComparer.Ordinal) ?? type;
- if (result.GetParts ().Count == 1)
- return type;
-// Console.WriteLine ("result:"+ result);
- return result;
- }
-
- IEnumerable<ICompletionData> CreateParameterCompletion (MethodGroupResolveResult resolveResult, CSharpResolver state, AstNode invocation, int parameter, bool controlSpace)
- {
- var result = new CompletionDataWrapper (this);
- var addedEnums = new HashSet<string> ();
- var addedDelegates = new HashSet<string> ();
-
- foreach (var method in resolveResult.Methods) {
- if (method.Parameters.Count <= parameter)
- continue;
- var resolvedType = method.Parameters [parameter].Type.Resolve (ctx);
- if (resolvedType.Kind == TypeKind.Enum) {
- if (addedEnums.Contains (resolvedType.ReflectionName))
- continue;
- addedEnums.Add (resolvedType.ReflectionName);
- AddEnumMembers (result, resolvedType, state);
- } else if (resolvedType.Kind == TypeKind.Delegate) {
-// if (addedDelegates.Contains (resolvedType.DecoratedFullName))
-// continue;
-// addedDelegates.Add (resolvedType.DecoratedFullName);
-// string parameterDefinition = AddDelegateHandlers (completionList, resolvedType, false, addedDelegates.Count == 1);
-// string varName = "Handle" + method.Parameters [parameter].ReturnType.Name + method.Parameters [parameter].Name;
-// result.Add (new EventCreationCompletionData (document, varName, resolvedType, null, parameterDefinition, resolver.Unit.GetMemberAt (location), resolvedType) { AddSemicolon = false });
-
- }
- }
- if (!controlSpace) {
- if (addedEnums.Count + addedDelegates.Count == 0)
- return Enumerable.Empty<ICompletionData> ();
- AutoCompleteEmptyMatch = false;
- AutoSelect = false;
- }
- AddContextCompletion (result, state, invocation);
-
-// resolver.AddAccessibleCodeCompletionData (ExpressionContext.MethodBody, cdc);
-// if (addedDelegates.Count > 0) {
-// foreach (var data in result.Result) {
-// if (data is MemberCompletionData)
-// ((MemberCompletionData)data).IsDelegateExpected = true;
-// }
-// }
- return result.Result;
- }
-
- string GetShortType (IType type, CSharpResolver state)
- {
- var builder = new TypeSystemAstBuilder (state);
- var shortType = builder.ConvertType (type);
- using (var w = new System.IO.StringWriter ()) {
- var visitor = new CSharpOutputVisitor (w, FormattingPolicy);
- shortType.AcceptVisitor (visitor, null);
- return w.ToString ();
- }
- }
-
- void AddEnumMembers (CompletionDataWrapper completionList, IType resolvedType, CSharpResolver state)
- {
- if (resolvedType.Kind != TypeKind.Enum)
- return;
- string typeString = GetShortType (resolvedType, state);
- if (typeString.Contains ("."))
- completionList.AddType (resolvedType, typeString);
- foreach (var field in resolvedType.GetFields (ctx)) {
- if (field.IsConst || field.IsStatic)
- completionList.Result.Add (factory.CreateEntityCompletionData (field, typeString + "." + field.Name));
- }
- DefaultCompletionString = typeString;
- }
-
- IEnumerable<ICompletionData> CreateCompletionData (TextLocation location, ResolveResult resolveResult, AstNode resolvedNode, CSharpResolver state)
- {
- if (resolveResult == null /*|| resolveResult.IsError*/)
- return null;
- if (resolveResult is NamespaceResolveResult) {
- var nr = (NamespaceResolveResult)resolveResult;
- var namespaceContents = new CompletionDataWrapper (this);
- foreach (var cl in ctx.GetTypes (nr.NamespaceName, StringComparer.Ordinal)) {
- namespaceContents.AddType (cl, cl.Name);
- }
- foreach (var ns in ctx.GetNamespaces ().Where (n => n.Length > nr.NamespaceName.Length && n.StartsWith (nr.NamespaceName))) {
- namespaceContents.AddNamespace (nr.NamespaceName, ns);
- }
-
- return namespaceContents.Result;
- }
-
- IType type = GetTypeFromContext (resolveResult.Type.GetDefinition ()) ?? resolveResult.Type;
- var typeDef = resolveResult.Type.GetDefinition ();
- var lookup = new MemberLookup (ctx, currentType, ProjectContent);
- var result = new CompletionDataWrapper (this);
- bool isProtectedAllowed = false;
- bool includeStaticMembers = false;
-
- if (resolveResult is LocalResolveResult) {
- isProtectedAllowed = currentType != null && typeDef != null ? typeDef.GetAllBaseTypeDefinitions (ctx).Any (bt => bt.Equals (currentType)) : false;
- if (resolvedNode is IdentifierExpression) {
- var mrr = (LocalResolveResult)resolveResult;
- includeStaticMembers = mrr.Variable.Name == mrr.Type.Name;
- }
- } else {
- isProtectedAllowed = currentType != null && typeDef != null ? currentType.GetAllBaseTypeDefinitions (ctx).Any (bt => bt.Equals (typeDef)) : false;
- }
- if (resolveResult is TypeResolveResult && type.Kind == TypeKind.Enum) {
- foreach (var field in type.GetFields (ctx)) {
- result.AddMember (field);
- }
- foreach (var m in type.GetMethods (ctx)) {
- if (m.Name == "TryParse")
- result.AddMember (m);
- }
- return result.Result;
- }
-
- if (resolveResult is MemberResolveResult && resolvedNode is IdentifierExpression) {
- var mrr = (MemberResolveResult)resolveResult;
- includeStaticMembers = mrr.Member.Name == mrr.Type.Name;
- }
-
-// Console.WriteLine ("type:" + type +"/"+type.GetType ());
-// Console.WriteLine ("IS PROT ALLOWED:" + isProtectedAllowed);
-// Console.WriteLine (resolveResult);
-// Console.WriteLine (currentMember != null ? currentMember.IsStatic : "currentMember == null");
- if (resolvedNode.Annotation<ObjectCreateExpression> () == null) { //tags the created expression as part of an object create expression.
- foreach (var member in type.GetMembers (ctx)) {
- if (!lookup.IsAccessible (member, isProtectedAllowed)) {
- // Console.WriteLine ("skip access: " + member.FullName);
- continue;
- }
- if (resolvedNode is BaseReferenceExpression && member.IsAbstract)
- continue;
-
- if (!includeStaticMembers && member.IsStatic && !(resolveResult is TypeResolveResult)) {
- // Console.WriteLine ("skip static member: " + member.FullName);
- continue;
- }
- if (!member.IsStatic && (resolveResult is TypeResolveResult)) {
- // Console.WriteLine ("skip non static member: " + member.FullName);
- continue;
- }
- // Console.WriteLine ("add : "+ member.FullName + " --- " + member.IsStatic);
- result.AddMember (member);
- }
- }
-
- if (resolveResult is TypeResolveResult || includeStaticMembers) {
- foreach (var nested in type.GetNestedTypes (ctx)) {
- result.AddType (nested, nested.Name);
- }
-
- } else {
- var baseTypes = new List<IType> (type.GetAllBaseTypes (ctx));
- var conv = new Conversions (ctx);
- for (var n = state.CurrentUsingScope; n != null; n = n.Parent) {
- AddExtensionMethods (result, conv, baseTypes, n.NamespaceName);
- foreach (var u in n.Usings) {
- var ns = u.ResolveNamespace (ctx);
- if (ns == null)
- continue;
- AddExtensionMethods (result, conv, baseTypes, ns.NamespaceName);
- }
- }
- }
-
-// IEnumerable<object> objects = resolveResult.CreateResolveResult (dom, resolver != null ? resolver.CallingMember : null);
-// CompletionDataCollector col = new CompletionDataCollector (this, dom, result, Document.CompilationUnit, resolver != null ? resolver.CallingType : null, location);
-// col.HideExtensionParameter = !resolveResult.StaticResolve;
-// col.NamePrefix = expressionResult.Expression;
-// bool showOnlyTypes = expressionResult.Contexts.Any (ctx => ctx == ExpressionContext.InheritableType || ctx == ExpressionContext.Constraints);
-// if (objects != null) {
-// foreach (object obj in objects) {
-// if (expressionResult.ExpressionContext != null && expressionResult.ExpressionContext.FilterEntry (obj))
-// continue;
-// if (expressionResult.ExpressionContext == ExpressionContext.NamespaceNameExcepted && !(obj is Namespace))
-// continue;
-// if (showOnlyTypes && !(obj is IType))
-// continue;
-// CompletionData data = col.Add (obj);
-// if (data != null && expressionResult.ExpressionContext == ExpressionContext.Attribute && data.CompletionText != null && data.CompletionText.EndsWith ("Attribute")) {
-// string newText = data.CompletionText.Substring (0, data.CompletionText.Length - "Attribute".Length);
-// data.SetText (newText);
-// }
-// }
-// }
-
- return result.Result;
- }
-
- void AddExtensionMethods (CompletionDataWrapper result, Conversions conv, List<IType> baseTypes, string namespaceName)
- {
- foreach (var typeDefinition in ctx.GetTypes (namespaceName, StringComparer.Ordinal).Where (t => t.IsStatic && t.HasExtensionMethods)) {
- foreach (var m in typeDefinition.Methods.Where (m => m.IsExtensionMethod )) {
- var pt = m.Parameters.First ().Type.Resolve (ctx);
- string reflectionName = pt is ParameterizedType ? ((ParameterizedType)pt).GetDefinition ().ReflectionName : pt.ReflectionName;
- if (baseTypes.Any (bt => (bt is ParameterizedType ? ((ParameterizedType)bt).GetDefinition ().ReflectionName : bt.ReflectionName) == reflectionName)) {
- result.AddMember (m);
- }
- }
- }
- }
- IEnumerable<ICompletionData> CreateCaseCompletionData (TextLocation location)
- {
- var unit = ParseStub ("a: break;");
- if (unit == null)
- return null;
- var s = unit.GetNodeAt<SwitchStatement> (location);
- if (s == null)
- return null;
-
- var offset = document.GetOffset (s.Expression.StartLocation);
- var expr = GetExpressionAt (offset);
- if (expr == null)
- return null;
-
- var resolveResult = ResolveExpression (expr.Item1, expr.Item2, expr.Item3);
- if (resolveResult == null || resolveResult.Item1.Type.Kind != TypeKind.Enum)
- return null;
- var wrapper = new CompletionDataWrapper (this);
- AddEnumMembers (wrapper, resolveResult.Item1.Type, resolveResult.Item2);
- AutoCompleteEmptyMatch = false;
- return wrapper.Result;
- }
-
- #region Parsing methods
- Tuple<CSharpParsedFile, AstNode, CompilationUnit> GetExpressionBeforeCursor ()
- {
- CompilationUnit baseUnit;
- if (currentMember == null) {
- baseUnit = ParseStub ("st {}", false);
- var type = baseUnit.GetNodeAt<MemberType> (location);
- if (type == null) {
- baseUnit = ParseStub ("a;", false);
- type = baseUnit.GetNodeAt<MemberType> (location);
- }
- if (type != null) {
- // insert target type into compilation unit, to respect the
- var target = type.Target;
- target.Remove ();
- var node = Unit.GetNodeAt (location) ?? Unit;
- node.AddChild (target, AstNode.Roles.Type);
- return Tuple.Create (CSharpParsedFile, (AstNode)target, Unit);
- }
- }
-
- if (currentMember == null && currentType == null) {
- return null;
- }
- baseUnit = ParseStub ("a()");
-
- // Hack for handle object initializer continuation expressions
- if (baseUnit.GetNodeAt (location) is AttributedNode) {
- baseUnit = ParseStub ("a()};");
- }
-
- var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
- var mref = baseUnit.GetNodeAt<MemberReferenceExpression> (location);
-
- if (mref == null){
- var invoke = baseUnit.GetNodeAt<InvocationExpression> (location);
- if (invoke != null)
- mref = invoke.Target as MemberReferenceExpression;
- }
- Expression expr = null;
- if (mref != null) {
- expr = mref.Target.Clone ();
- mref.Parent.ReplaceWith (expr);
- } else {
- Expression tref = baseUnit.GetNodeAt<TypeReferenceExpression> (location);
- var memberType = tref != null ? ((TypeReferenceExpression)tref).Type as MemberType : null;
- if (memberType == null) {
- memberType = baseUnit.GetNodeAt<MemberType> (location);
- if (memberType != null) {
- tref = baseUnit.GetNodeAt<Expression> (location);
- if (tref == null)
- return null;
- }
- if (tref is ObjectCreateExpression) {
- expr = new TypeReferenceExpression (memberType.Target.Clone ());
- expr.AddAnnotation (new ObjectCreateExpression ());
- }
- }
-
- if (memberType == null)
- return null;
- if (expr == null)
- expr = new TypeReferenceExpression (memberType.Target.Clone ());
- tref.ReplaceWith (expr);
- }
-
- var member = Unit.GetNodeAt<AttributedNode> (memberLocation);
- var member2 = baseUnit.GetNodeAt<AttributedNode> (memberLocation);
- member2.Remove ();
- member.ReplaceWith (member2);
- var tsvisitor = new TypeSystemConvertVisitor (ProjectContent, this.CSharpParsedFile.FileName);
- Unit.AcceptVisitor (tsvisitor, null);
- return Tuple.Create (tsvisitor.ParsedFile, (AstNode)expr, Unit);
- }
-
- Tuple<CSharpParsedFile, AstNode, CompilationUnit> GetExpressionAtCursor ()
- {
-// if (currentMember == null && currentType == null)
-// return null;
-
- TextLocation memberLocation;
- if (currentMember != null) {
- memberLocation = currentMember.Region.Begin;
- } else if (currentType != null) {
- memberLocation = currentType.Region.Begin;
- } else {
- memberLocation = location;
- }
-
- var baseUnit = ParseStub ("");
- var tmpUnit = baseUnit;
- AstNode expr = baseUnit.GetNodeAt<IdentifierExpression> (location.Line, location.Column - 1);
- if (expr == null)
- expr = baseUnit.GetNodeAt<Attribute> (location.Line, location.Column - 1);
-
- if (expr == null) {
- baseUnit = ParseStub ("()");
- expr = baseUnit.GetNodeAt<IdentifierExpression> (location.Line, location.Column - 1);
- }
-
- // try initializer expression
- if (expr == null) {
- baseUnit = ParseStub ("a = b};", false);
- expr = baseUnit.GetNodeAt<ArrayInitializerExpression> (location.Line, location.Column - 1);
- }
-
- // try statement
- if (expr == null) {
- expr = tmpUnit.GetNodeAt<SwitchStatement> (location.Line, location.Column - 1);
- baseUnit = tmpUnit;
- }
-
- if (expr == null) {
- var forStmt = tmpUnit.GetNodeAt<ForStatement> (location.Line, location.Column - 3);
- expr = forStmt;
- if (forStmt != null && forStmt.EmbeddedStatement.IsNull) {
- var id = new IdentifierExpression ("stub");
- forStmt.EmbeddedStatement = new BlockStatement () { Statements = { new ExpressionStatement (id) }};
- expr = id;
- }
- baseUnit = tmpUnit;
- }
-
- if (expr == null)
- return null;
- var member = Unit.GetNodeAt<AttributedNode> (memberLocation);
- var member2 = baseUnit.GetNodeAt<AttributedNode> (memberLocation);
- if (member != null && member2 != null) {
- member2.Remove ();
-
- if (member is TypeDeclaration) {
- member.AddChild (member2, TypeDeclaration.MemberRole);
- } else {
- member.ReplaceWith (member2);
- }
- } else {
- var tsvisitor2 = new TypeSystemConvertVisitor (ProjectContent, CSharpParsedFile.FileName);
- Unit.AcceptVisitor (tsvisitor2, null);
- return Tuple.Create (tsvisitor2.ParsedFile, expr, baseUnit);
- }
- var tsvisitor = new TypeSystemConvertVisitor (ProjectContent, CSharpParsedFile.FileName);
- Unit.AcceptVisitor (tsvisitor, null);
- return Tuple.Create (tsvisitor.ParsedFile, expr, Unit);
- }
-
- Tuple<CSharpParsedFile, AstNode, CompilationUnit> GetExpressionAt (int offset)
- {
- var parser = new CSharpParser ();
- string text = this.document.GetText (0, this.offset);
- var sb = new StringBuilder (text);
- sb.Append ("a;");
- AppendMissingClosingBrackets (sb, text, false);
- var stream = new System.IO.StringReader (sb.ToString ());
- var completionUnit = parser.Parse (stream, 0);
- stream.Close ();
- var loc = document.GetLocation (offset);
-
- var expr = completionUnit.GetNodeAt (loc, n => n is Expression || n is VariableDeclarationStatement);
- if (expr == null)
- return null;
- var tsvisitor = new TypeSystemConvertVisitor (ProjectContent, CSharpParsedFile.FileName);
- completionUnit.AcceptVisitor (tsvisitor, null);
-
- return Tuple.Create (tsvisitor.ParsedFile, expr, completionUnit);
- }
-
-
- Tuple<CSharpParsedFile, AstNode, CompilationUnit> GetNewExpressionAt (int offset)
- {
- var parser = new CSharpParser ();
- string text = this.document.GetText (0, this.offset);
- var sb = new StringBuilder (text);
- sb.Append ("a ();");
- AppendMissingClosingBrackets (sb, text, false);
- var stream = new System.IO.StringReader (sb.ToString ());
- var completionUnit = parser.Parse (stream, 0);
- stream.Close ();
- var loc = document.GetLocation (offset);
-
- var expr = completionUnit.GetNodeAt (loc, n => n is Expression);
- if (expr == null)
- return null;
- var tsvisitor = new TypeSystemConvertVisitor (ProjectContent, CSharpParsedFile.FileName);
- completionUnit.AcceptVisitor (tsvisitor, null);
-
- return Tuple.Create (tsvisitor.ParsedFile, expr, completionUnit);
- }
-
-
- #endregion
-
- #region Helper methods
- string GetPreviousToken (ref int i, bool allowLineChange)
- {
- char c;
- if (i <= 0)
- return null;
-
- do {
- c = document.GetCharAt (--i);
- } while (i > 0 && char.IsWhiteSpace (c) && (allowLineChange ? true : c != '\n'));
-
- if (i == 0)
- return null;
-
- if (!char.IsLetterOrDigit (c))
- return new string (c, 1);
-
- int endOffset = i + 1;
-
- do {
- c = document.GetCharAt (i - 1);
- if (!(char.IsLetterOrDigit (c) || c == '_'))
- break;
-
- i--;
- } while (i > 0);
-
- return document.GetText (i, endOffset - i);
- }
-
- bool GetParameterCompletionCommandOffset (out int cpos)
- {
- // Start calculating the parameter offset from the beginning of the
- // current member, instead of the beginning of the file.
- cpos = offset - 1;
- IMember mem = currentMember;
- if (mem == null || (mem is IType))
- return false;
- int startPos = document.GetOffset (mem.Region.BeginLine, mem.Region.BeginColumn);
- int parenDepth = 0;
- int chevronDepth = 0;
- while (cpos > startPos) {
- char c = document.GetCharAt (cpos);
- if (c == ')')
- parenDepth++;
- if (c == '>')
- chevronDepth++;
- if (parenDepth == 0 && c == '(' || chevronDepth == 0 && c == '<') {
- int p = GetCurrentParameterIndex (cpos + 1, startPos);
- if (p != -1) {
- cpos++;
- return true;
- } else {
- return false;
- }
- }
- if (c == '(')
- parenDepth--;
- if (c == '<')
- chevronDepth--;
- cpos--;
- }
- return false;
- }
-
- int GetCurrentParameterIndex (int offset, int memberStart)
- {
- int cursor = this.offset;
- int i = offset;
-
- if (i > cursor)
- return -1;
- if (i == cursor)
- return 1; // parameters are 1 based
- int index = memberStart + 1;
- int parentheses = 0;
- int bracket = 0;
- bool insideQuote = false, insideString = false, insideSingleLineComment = false, insideMultiLineComment = false;
- do {
- char c = document.GetCharAt (i - 1);
- switch (c) {
- case '\\':
- if (insideString || insideQuote)
- i++;
- break;
- case '\'':
- if (!insideString && !insideSingleLineComment && !insideMultiLineComment)
- insideQuote = !insideQuote;
- break;
- case '"':
- if (!insideQuote && !insideSingleLineComment && !insideMultiLineComment)
- insideString = !insideString;
- break;
- case '/':
- if (!insideQuote && !insideString && !insideMultiLineComment) {
- if (document.GetCharAt (i) == '/')
- insideSingleLineComment = true;
- if (document.GetCharAt (i) == '*')
- insideMultiLineComment = true;
- }
- break;
- case '*':
- if (insideMultiLineComment && document.GetCharAt (i) == '/')
- insideMultiLineComment = false;
- break;
- case '\n':
- case '\r':
- insideSingleLineComment = false;
- break;
- case '{':
- if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment)
- bracket++;
- break;
- case '}':
- if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment)
- bracket--;
- break;
- case '(':
- if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment)
- parentheses++;
- break;
- case ')':
- if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment)
- parentheses--;
- break;
- case ',':
- if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment && parentheses == 1 && bracket == 0)
- index++;
- break;
- }
- i++;
- } while (i <= cursor && parentheses >= 0);
-
- return parentheses != 1 || bracket > 0 ? -1 : index;
- }
-
- CSharpResolver GetState ()
- {
- var state = new CSharpResolver (ctx, System.Threading.CancellationToken.None);
-
- state.CurrentMember = CSharpParsedFile.GetMember (location);
- state.CurrentTypeDefinition = CSharpParsedFile.GetInnermostTypeDefinition (location);
- state.CurrentUsingScope = CSharpParsedFile.GetUsingScope (location);
- if (state.CurrentMember != null) {
- var node = Unit.GetNodeAt (location);
- if (node == null)
- return state;
- var navigator = new NodeListResolveVisitorNavigator (new[] { node });
- var visitor = new ResolveVisitor (state, CSharpParsedFile, navigator);
- Unit.AcceptVisitor (visitor, null);
- try {
- var newState = visitor.GetResolverStateBefore (node);
- if (newState != null)
- state = newState;
- } catch (Exception) {
- }
- }
-
- return state;
- }
- #endregion
-
- #region Preprocessor
-
- IEnumerable<ICompletionData> GetDirectiveCompletionData ()
- {
- yield return factory.CreateLiteralCompletionData ("if");
- yield return factory.CreateLiteralCompletionData ("else");
- yield return factory.CreateLiteralCompletionData ("elif");
- yield return factory.CreateLiteralCompletionData ("endif");
- yield return factory.CreateLiteralCompletionData ("define");
- yield return factory.CreateLiteralCompletionData ("undef");
- yield return factory.CreateLiteralCompletionData ("warning");
- yield return factory.CreateLiteralCompletionData ("error");
- yield return factory.CreateLiteralCompletionData ("pragma");
- yield return factory.CreateLiteralCompletionData ("line");
- yield return factory.CreateLiteralCompletionData ("line hidden");
- yield return factory.CreateLiteralCompletionData ("line default");
- yield return factory.CreateLiteralCompletionData ("region");
- yield return factory.CreateLiteralCompletionData ("endregion");
- }
- #endregion
-
- #region Xml Comments
- static readonly List<string> commentTags = new List<string> (new string[] { "c", "code", "example", "exception", "include", "list", "listheader", "item", "term", "description", "para", "param", "paramref", "permission", "remarks", "returns", "see", "seealso", "summary", "value" });
-
- IEnumerable<ICompletionData> GetXmlDocumentationCompletionData ()
- {
- yield return factory.CreateLiteralCompletionData ("c", "Set text in a code-like font");
- yield return factory.CreateLiteralCompletionData ("code", "Set one or more lines of source code or program output");
- yield return factory.CreateLiteralCompletionData ("example", "Indicate an example");
- yield return factory.CreateLiteralCompletionData ("exception", "Identifies the exceptions a method can throw", "exception cref=\"|\"></exception>");
- yield return factory.CreateLiteralCompletionData ("include", "Includes comments from a external file", "include file=\"|\" path=\"\">");
- yield return factory.CreateLiteralCompletionData ("list", "Create a list or table", "list type=\"|\">");
- yield return factory.CreateLiteralCompletionData ("listheader", "Define the heading row");
- yield return factory.CreateLiteralCompletionData ("item", "Defines list or table item");
-
- yield return factory.CreateLiteralCompletionData ("term", "A term to define");
- yield return factory.CreateLiteralCompletionData ("description", "Describes a list item");
- yield return factory.CreateLiteralCompletionData ("para", "Permit structure to be added to text");
-
- yield return factory.CreateLiteralCompletionData ("param", "Describe a parameter for a method or constructor", "param name=\"|\">");
- yield return factory.CreateLiteralCompletionData ("paramref", "Identify that a word is a parameter name", "paramref name=\"|\"/>");
-
- yield return factory.CreateLiteralCompletionData ("permission", "Document the security accessibility of a member", "permission cref=\"|\"");
- yield return factory.CreateLiteralCompletionData ("remarks", "Describe a type");
- yield return factory.CreateLiteralCompletionData ("returns", "Describe the return value of a method");
- yield return factory.CreateLiteralCompletionData ("see", "Specify a link", "see cref=\"|\"/>");
- yield return factory.CreateLiteralCompletionData ("seealso", "Generate a See Also entry", "seealso cref=\"|\"/>");
- yield return factory.CreateLiteralCompletionData ("summary", "Describe a member of a type");
- yield return factory.CreateLiteralCompletionData ("typeparam", "Describe a type parameter for a generic type or method");
- yield return factory.CreateLiteralCompletionData ("typeparamref", "Identify that a word is a type parameter name");
- yield return factory.CreateLiteralCompletionData ("value", "Describe a property");
- }
- #endregion
-
- #region Keywords
- static string[] expressionLevelKeywords = new string [] { "as", "is", "else", "out", "ref", "null", "delegate", "default"};
-
- static string[] primitiveTypesKeywords = new string [] { "void", "object", "bool", "byte", "sbyte", "char", "short", "int", "long", "ushort", "uint", "ulong", "float", "double", "decimal", "string"};
-
- static string[] statementStartKeywords = new string [] { "base", "new", "sizeof", "this",
- "true", "false", "typeof", "checked", "unchecked", "from", "break", "checked",
- "unchecked", "const", "continue", "do", "finally", "fixed", "for", "foreach",
- "goto", "if", "lock", "return", "stackalloc", "switch", "throw", "try", "unsafe",
- "using", "while", "yield", "dynamic", "var" };
-
- static string[] globalLevelKeywords = new string [] {
- "namespace", "using", "extern", "public", "internal",
- "class", "interface", "struct", "enum", "delegate",
- "abstract", "sealed", "static", "unsafe", "partial"
- };
-
- static string[] accessorModifierKeywords = new string [] {
- "public", "internal", "protected", "private"
- };
-
- static string[] typeLevelKeywords = new string [] {
- "public", "internal", "protected", "private",
- "class", "interface", "struct", "enum", "delegate",
- "abstract", "sealed", "static", "unsafe", "partial",
- "const", "event", "extern", "fixed","new",
- "operator", "explicit", "implicit",
- "override", "readonly", "virtual", "volatile"
- };
- static string[] linqKeywords = new string[] { "from", "where", "select", "group", "into", "orderby", "join", "let", "in", "on", "equals", "by", "ascending", "descending" };
- #endregion
- }
-}
-
+// +// CSharpCompletionEngine.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// Copyright (c) 2011 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using ICSharpCode.NRefactory.Completion; +using ICSharpCode.NRefactory.CSharp.Refactoring; +using ICSharpCode.NRefactory.CSharp.Resolver; +using ICSharpCode.NRefactory.Editor; +using ICSharpCode.NRefactory.Semantics; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.CSharp.Completion +{ + public class CSharpCompletionEngine : CSharpCompletionEngineBase + { + internal ICompletionDataFactory factory; + + #region Additional input properties + public CSharpFormattingOptions FormattingPolicy { get; set; } + public string EolMarker { get; set; } + public string IndentString { get; set; } + #endregion + + #region Result properties + public bool AutoCompleteEmptyMatch; + public bool AutoSelect; + public string DefaultCompletionString; + #endregion + + public CSharpCompletionEngine (IDocument document, ICompletionDataFactory factory) + { + this.document = document; + this.factory = factory; + } + + public IEnumerable<ICompletionData> GetCompletionData (int offset, bool controlSpace) + { + this.AutoCompleteEmptyMatch = true; + this.AutoSelect = true; + this.DefaultCompletionString = null; + SetOffset (offset); + if (offset > 0) { + char lastChar = document.GetCharAt (offset - 1); + var result = MagicKeyCompletion (lastChar, controlSpace) ?? Enumerable.Empty<ICompletionData> (); + if (controlSpace && char.IsWhiteSpace (lastChar)) { + offset -= 2; + while (offset >= 0 && char.IsWhiteSpace (document.GetCharAt (offset))) + offset--; + if (offset > 0) { + var nonWsResult = MagicKeyCompletion (document.GetCharAt (offset), controlSpace); + if (nonWsResult != null) + result = result.Concat (nonWsResult); + } + } + + return result; + } + return Enumerable.Empty<ICompletionData> (); + } + + IEnumerable<string> GenerateNameProposals (AstType type) + { + if (type is PrimitiveType) { + var pt = (PrimitiveType)type; + Console.WriteLine (pt.Keyword); + switch (pt.Keyword) { + case "object": + yield return "o"; + yield return "obj"; + break; + case "bool": + yield return "b"; + yield return "pred"; + break; + case "double": + case "float": + case "decimal": + yield return "d"; + yield return "f"; + yield return "m"; + break; + default: + yield return "i"; + yield return "j"; + yield return "k"; + break; + } + yield break; + } + + var names = new List<string> (); + int offset1 = document.GetOffset (type.StartLocation); + int offset2 = document.GetOffset (type.EndLocation); + + string name = document.GetText (offset1, offset2 - offset1); + 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)); + + var 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]); + } + yield return possibleName.ToString (); + } + } + + 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); + 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.Resolve (ctx); + if (!delegateType.IsDelegate ()) + return null; + + var wrapper = new CompletionDataWrapper (this); + if (currentType != null) { +// bool includeProtected = DomType.IncludeProtected (dom, typeFromDatabase, resolver.CallingType); + foreach (var method in currentType.GetMethods (ctx)) { + 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 ":": + 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)) { + tokenIndex = offset; + 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; + } + + var contextList = new CompletionDataWrapper (this); + + var identifierStart = GetExpressionAtCursor (); + if (!(char.IsLetter (completionChar) || completionChar == '_') && (!controlSpace || identifierStart == null || !(identifierStart.Item2 is ArrayInitializerExpression))) { + return controlSpace ? HandleAccessorContext () ?? DefaultControlSpaceItems () : null; + } + + char prevCh = offset > 2 ? document.GetCharAt (offset - 2) : '\0'; + 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 (identifierStart == null && !string.IsNullOrEmpty (token) && !(IsInsideComment (tokenIndex) || IsInsideString (tokenIndex))) { + char last = token [token.Length - 1]; + if (char.IsLetterOrDigit (last) || last == '_' || token == ">") { + return null; + } + } + if (identifierStart == null) + return HandleAccessorContext () ?? DefaultControlSpaceItems (); + + CSharpResolver csResolver; + AstNode n = identifierStart.Item2; + if (n is ArrayInitializerExpression) { + 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) { + + foreach (var property in initalizerResult.Item1.Type.GetProperties (ctx)) { + if (!property.IsPublic) + continue; + contextList.AddMember (property); + } + foreach (var field in initalizerResult.Item1.Type.GetFields (ctx)){ + if (!field.IsPublic) + continue; + contextList.AddMember (field); + } + return contextList.Result; + } + return null; + } + if (n != null/* && !(identifierStart.Item2 is TypeDeclaration)*/) { + csResolver = new CSharpResolver (ctx, System.Threading.CancellationToken.None); + var nodes = new List<AstNode> (); + nodes.Add (n); + if (n.Parent is ICSharpCode.NRefactory.CSharp.Attribute) + nodes.Add (n.Parent); + var navigator = new NodeListResolveVisitorNavigator (nodes); + var visitor = new ResolveVisitor (csResolver, identifierStart.Item1, navigator); + visitor.Scan (identifierStart.Item3); + try { + csResolver = visitor.GetResolverStateBefore (n); + } catch (Exception) { + csResolver = GetState (); + } + // add attribute properties. + if (n.Parent is ICSharpCode.NRefactory.CSharp.Attribute) { + var resolved = visitor.GetResolveResult (n.Parent); + if (resolved != null && resolved.Type != null) { + foreach (var property in resolved.Type.GetProperties (ctx).Where (p => p.Accessibility == Accessibility.Public)) { + contextList.AddMember (property); + } + foreach (var field in resolved.Type.GetFields (ctx).Where (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; + } + + bool IsInLinqContext (int offset) + { + string token; + while (null != (token = GetPreviousToken (ref offset, true))) { + if (token == "from") + return true; + if (token == ";") + return false; + } + return false; + } + + IEnumerable<ICompletionData> HandleAccessorContext () + { + var unit = ParseStub ("get; }", false); + var node = unit.GetNodeAt (location, cn => !(cn is CSharpTokenNode)); + 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> DefaultControlSpaceItems () + { + var wrapper = new CompletionDataWrapper (this); + while (offset > 0 && char.IsWhiteSpace (document.GetCharAt (offset))) { + offset--; + } + location = document.GetLocation (offset); + var xp = GetExpressionAtCursor (); + + AstNode node; + Tuple<ResolveResult, CSharpResolver> rr; + if (xp != null) { + node = xp.Item2; + rr = ResolveExpression (xp.Item1, node, xp.Item3); + } else { + node = Unit.GetNodeAt (location); + rr = ResolveExpression (CSharpParsedFile, node, Unit); + } + + AddContextCompletion (wrapper, rr != null && (node is Expression) ? rr.Item2 : GetState (), node); + + return wrapper.Result; + } + + void AddContextCompletion (CompletionDataWrapper wrapper, CSharpResolver state, AstNode node) + { + if (state == null) + return; + foreach (var variable in state.LocalVariables) { + wrapper.AddVariable (variable); + } + if (state.CurrentMember is IParameterizedMember) { + var param = (IParameterizedMember)state.CurrentMember; + foreach (var p in param.Parameters) { + wrapper.AddVariable (p); + } + } + + if (state.CurrentMember is IMethod) { + var method = (IMethod)state.CurrentMember; + foreach (var p in method.TypeParameters) { + wrapper.AddTypeParameter (p); + } + } + Predicate<ITypeDefinition> typePred = null; + if (node is Attribute) { + var attribute = ctx.GetTypeDefinition ("System", "Attribute", 0, StringComparer.Ordinal); + typePred = t => t.GetAllBaseTypeDefinitions (ctx).Any (bt => bt.Equals (attribute)); + } + AddTypesAndNamespaces (wrapper, state, node, typePred); + + wrapper.Result.Add (factory.CreateLiteralCompletionData ("global")); + if (state.CurrentMember != null) { + AddKeywords (wrapper, statementStartKeywords); + AddKeywords (wrapper, expressionLevelKeywords); + } else if (state.CurrentTypeDefinition != null) { + AddKeywords (wrapper, typeLevelKeywords); + } else { + AddKeywords (wrapper, globalLevelKeywords); + } + + if (IsInSwitchContext(node)) { + wrapper.AddCustom ("case"); + wrapper.AddCustom ("default"); + } + + AddKeywords (wrapper, primitiveTypesKeywords); + wrapper.Result.AddRange (factory.CreateCodeTemplateCompletionData ()); + } + + static bool IsInSwitchContext(AstNode node) + { + var n = node; + while (n != null && !(n is MemberDeclaration)) { + if (n is SwitchStatement) + return true; + if (n is BlockStatement) + return false; + n = n.Parent; + } + return false; + } + + void AddTypesAndNamespaces (CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, Predicate<ITypeDefinition> typePred = null, Predicate<IMember> memberPred = null) + { + var currentType = state.CurrentTypeDefinition ?? this.currentType; + var currentMember = state.CurrentMember ?? this.currentMember; + if (currentType != null) { + for (var ct = currentType; ct != null; ct = ct.DeclaringTypeDefinition) { + foreach (var nestedType in ct.NestedTypes) { + if (typePred == null || typePred (nestedType)) { + string name = nestedType.Name; + if (node is Attribute && name.EndsWith ("Attribute") && name.Length > "Attribute".Length) + name = name.Substring (0, name.Length - "Attribute".Length); + wrapper.AddType (nestedType, name); + } + } + } + if (currentMember != null) { + foreach (var member in currentType.Resolve (ctx).GetMembers (ctx)) { + if (memberPred == null || memberPred (member)) + wrapper.AddMember (member); + } + } + foreach (var p in currentType.TypeParameters) { + wrapper.AddTypeParameter (p); + } + } + + for (var n = state.CurrentUsingScope; n != null; n = n.Parent) { + foreach (var pair in n.UsingAliases) { + wrapper.AddNamespace ("", pair.Key); + } + + foreach (var u in n.Usings) { + var ns = u.ResolveNamespace (ctx); + if (ns == null) + continue; + foreach (var type in ctx.GetTypes (ns.NamespaceName, StringComparer.Ordinal)) { + if (typePred == null || typePred (type)) { + string name = type.Name; + if (node is Attribute && name.EndsWith ("Attribute") && name.Length > "Attribute".Length) + name = name.Substring (0, name.Length - "Attribute".Length); + wrapper.AddType (type, name); + } + } + } + + foreach (var type in ctx.GetTypes (n.NamespaceName, StringComparer.Ordinal)) { + if (typePred == null || typePred (type)) { + wrapper.AddType (type, type.Name); + } + } + + foreach (var curNs in ctx.GetNamespaces ().Where (sn => sn.StartsWith (n.NamespaceName) && sn != n.NamespaceName)) { + wrapper.AddNamespace (n.NamespaceName, curNs); + } + } + } + + 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.IsDerivedFrom (isAsType.GetDefinition (), ctx)); + 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; + var overrideCls = CSharpParsedFile.GetInnermostTypeDefinition (location); + if (overrideCls != null && (overrideCls.Kind == TypeKind.Class || overrideCls.Kind == TypeKind.Struct)) { + string modifiers = document.GetText (firstMod, wordStart - firstMod); + return GetOverrideCompletionData (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; + } + if (!IsLineEmptyUpToEol ()) + return null; + + overrideCls = CSharpParsedFile.GetInnermostTypeDefinition (location); + if (overrideCls != null && (overrideCls.Kind == TypeKind.Class || overrideCls.Kind == TypeKind.Struct)) { + string modifiers = document.GetText (firstMod, wordStart - firstMod); + return GetPartialCompletionData (overrideCls, modifiers); + } + return null; + + case "public": + case "protected": + case "private": + case "internal": + case "sealed": + case "static": + wrapper = new CompletionDataWrapper (this); + var 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 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 (stateTracker.Engine.IsInsidePreprocessorDirective) +// return GetDefineCompletionData (); +// 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; + } + + bool IsLineEmptyUpToEol () + { + var line = document.GetLineByNumber (location.Line); + for (int j = offset; j < line.EndOffset; j++) { + char ch = document.GetCharAt (j); + if (!char.IsWhiteSpace (ch)) + return false; + } + return true; + } + string GetLineIndent (int lineNr) + { + var line = document.GetLineByNumber (lineNr); + for (int j = offset; j < line.EndOffset; j++) { + char ch = document.GetCharAt (j); + if (!char.IsWhiteSpace (ch)) + return document.GetText (line.Offset, j - line.Offset - 1); + } + return ""; + } + + IEnumerable<ICompletionData> CreateTypeCompletionData (IType hintType, AstType hintTypeAst) + { + var wrapper = new CompletionDataWrapper (this); + var state = GetState (); + Predicate<ITypeDefinition> pred = null; + if (hintType != null) { + if (!hintType.Equals (SharedTypes.UnknownType)) { + var lookup = new MemberLookup (ctx, currentType, ProjectContent); + pred = t => { + // check if type is in inheritance tree. + if (hintType.GetDefinition () != null && !t.IsDerivedFrom (hintType.GetDefinition (), ctx)) + return false; + // check for valid constructors + if (t.Methods.Count (m => m.IsConstructor) == 0) + return true; + bool isProtectedAllowed = currentType != null ? currentType.IsDerivedFrom (t, ctx) : false; + return t.Methods.Any (m => m.IsConstructor && lookup.IsAccessible (m, isProtectedAllowed)); + }; + DefaultCompletionString = GetShortType (hintType, GetState ()); + wrapper.AddType (hintType, DefaultCompletionString); + } else { + DefaultCompletionString = hintTypeAst.ToString (); + wrapper.AddType (hintType, DefaultCompletionString); + } + } + AddTypesAndNamespaces (wrapper, state, null, pred, m => false); + AddKeywords (wrapper, primitiveTypesKeywords.Where (k => k != "void")); + AutoCompleteEmptyMatch = true; + return wrapper.Result; + } + + IEnumerable<ICompletionData> GetOverrideCompletionData (ITypeDefinition type, string modifiers) + { + var wrapper = new CompletionDataWrapper (this); + var alreadyInserted = new Dictionary<string, bool> (); + bool addedVirtuals = false; + + int declarationBegin = offset; + int j = declarationBegin; + for (int i = 0; i < 3; i++) { + switch (GetPreviousToken (ref j, true)) { + case "public": + case "protected": + case "private": + case "internal": + case "sealed": + case "override": + declarationBegin = j; + break; + case "static": + return null; // don't add override completion for static members + } + } + foreach (var baseType in type.GetAllBaseTypeDefinitions (ctx)) { + AddVirtuals (alreadyInserted, wrapper, type, modifiers, baseType, declarationBegin); + addedVirtuals = true; + } + if (!addedVirtuals) + AddVirtuals (alreadyInserted, wrapper, type, modifiers, ctx.GetTypeDefinition (typeof(object)), declarationBegin); + return wrapper.Result; + } + + IEnumerable<ICompletionData> GetPartialCompletionData (ITypeDefinition type, string modifiers) + { + var wrapper = new CompletionDataWrapper (this); + var partialType = GetTypeFromContext (type); + if (partialType != null) { + int declarationBegin = offset; + int j = declarationBegin; + for (int i = 0; i < 3; i++) { + switch (GetPreviousToken (ref j, true)) { + case "public": + case "protected": + case "private": + case "internal": + case "sealed": + case "override": + declarationBegin = j; + break; + case "static": + return null; // don't add override completion for static members + } + } + + var methods = new List<IMethod> (); + // gather all partial methods without implementation + foreach (var part in partialType.GetParts ()) + foreach (var method in part.Methods) { + if (method.IsPartial && method.BodyRegion.IsEmpty) { + methods.Add (method); + } + } + + // now filter all methods that are implemented in the compound class + foreach (var part in partialType.GetParts ()) { + if (part == type) + continue; + for (int i = 0; i < methods.Count; i++) { + var curMethod = methods[i]; + var method = GetImplementation (partialType, curMethod); + if (method != null && !method.BodyRegion.IsEmpty) { + methods.RemoveAt (i); + i--; + continue; + } + } + } + + foreach (var method in methods) { + wrapper.Add (factory.CreateNewOverrideCompletionData (declarationBegin, type, method)); + } + + } + return wrapper.Result; + } + + IMethod GetImplementation (ITypeDefinition type, IMethod method) + { + foreach (var cur in type.Methods) { + if (cur.Name == method.Name && cur.Parameters.Count == method.Parameters.Count && !cur.BodyRegion.IsEmpty) { + bool equal = true; + for (int i = 0; i < cur.Parameters.Count; i++) { + if (!cur.Parameters[i].Type.Resolve (ctx).Equals (method.Parameters[i].Type.Resolve (ctx))) { + equal = false; + break; + } + } + if (equal) + return cur; + } + } + return null; + } + + + static string GetNameWithParamCount (IMember member) + { + var e = member as IMethod; + if (e == null || e.TypeParameters.Count == 0) + return member.Name; + return e.Name + "`" + e.TypeParameters.Count; + } + + void AddVirtuals (Dictionary<string, bool> alreadyInserted, CompletionDataWrapper col, ITypeDefinition type, string modifiers, ITypeDefinition curType, int declarationBegin) + { + if (curType == null) + return; + foreach (var m in curType.Methods.Where (m => !m.IsConstructor && !m.IsDestructor).Cast<IMember> ().Concat (curType.Properties.Cast<IMember> ())) { + if (m.IsSynthetic || curType.Kind != TypeKind.Interface && !(m.IsVirtual || m.IsOverride || m.IsAbstract)) + continue; + // filter out the "Finalize" methods, because finalizers should be done with destructors. + if (m is IMethod && m.Name == "Finalize") + continue; + + var data = factory.CreateNewOverrideCompletionData (declarationBegin, type, m); + string text = GetNameWithParamCount (m); + + // check if the member is already implemented + bool foundMember = type.Members.Any (cm => GetNameWithParamCount (cm) == text); + if (!foundMember && !alreadyInserted.ContainsKey (text)) { + alreadyInserted [text] = true; + data.CompletionCategory = col.GetCompletionCategory (curType); + col.Add (data); + } + } + } + + static void AddKeywords (CompletionDataWrapper wrapper, IEnumerable<string> keywords) + { + foreach (string keyword in keywords) { + wrapper.AddCustom (keyword); + } + } + + public string GetPreviousMemberReferenceExpression (int tokenIndex) + { + string result = GetPreviousToken (ref tokenIndex, false); + result = GetPreviousToken (ref tokenIndex, false); + if (result != ".") { + result = null; + } else { + var names = new List<string> (); + while (result == ".") { + result = GetPreviousToken (ref tokenIndex, false); + if (result == "this") { + names.Add ("handle"); + } else if (result != null) { + string trimmedName = result.Trim (); + if (trimmedName.Length == 0) + break; + names.Insert (0, trimmedName); + } + result = GetPreviousToken (ref tokenIndex, false); + } + result = String.Join ("", names.ToArray ()); + foreach (char ch in result) { + if (!char.IsLetterOrDigit (ch) && ch != '_') { + result = ""; + break; + } + } + } + return result; + } + + bool MatchDelegate (IType delegateType, IMethod method) + { + var delegateMethod = delegateType.GetDelegateInvokeMethod (); + if (delegateMethod == null || delegateMethod.Parameters.Count != method.Parameters.Count) + return false; + + for (int i = 0; i < delegateMethod.Parameters.Count; i++) { + if (!delegateMethod.Parameters [i].Type.Resolve (ctx).Equals (method.Parameters [i].Type.Resolve (ctx))) + return false; + } + return true; + } + + 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.Resolve (ctx); + 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 (); + } + + bool IsAccessibleFrom (IEntity member, ITypeDefinition calledType, IMember currentMember, bool includeProtected) + { + if (currentMember == null) + return member.IsStatic || member.IsPublic; +// if (currentMember is MonoDevelop.Projects.Dom.BaseResolveResult.BaseMemberDecorator) +// return member.IsPublic | member.IsProtected; + // if (member.IsStatic && !IsStatic) + // return false; + if (member.IsPublic || calledType != null && calledType.Kind == TypeKind.Interface && !member.IsProtected) + return true; + if (member.DeclaringTypeDefinition != null) { + if (member.DeclaringTypeDefinition.Kind == TypeKind.Interface) + return IsAccessibleFrom (member.DeclaringTypeDefinition, calledType, currentMember, includeProtected); + + if (member.IsProtected && !(member.DeclaringTypeDefinition.IsProtectedOrInternal && !includeProtected)) + return includeProtected; + } + if (member.IsInternal || member.IsProtectedAndInternal || member.IsProtectedOrInternal) { + var type1 = member is ITypeDefinition ? (ITypeDefinition)member : member.DeclaringTypeDefinition; + var type2 = currentMember is ITypeDefinition ? (ITypeDefinition)currentMember : currentMember.DeclaringTypeDefinition; + bool result; + // easy case, projects are the same + if (type1.ProjectContent == type2.ProjectContent) { + result = true; + } else if (type1.ProjectContent != null) { + // maybe type2 hasn't project dom set (may occur in some cases), check if the file is in the project + //TODO !! +// result = type1.ProjectContent.Annotation<MonoDevelop.Projects.Project> ().GetProjectFile (type2.Region.FileName) != null; + result = false; + } else if (type2.ProjectContent != null) { + //TODO!! +// result = type2.ProjectContent.Annotation<MonoDevelop.Projects.Project> ().GetProjectFile (type1.Region.FileName) != null; + result = false; + } else { + // should never happen ! + result = true; + } + return member.IsProtectedAndInternal ? includeProtected && result : result; + } + + if (!(currentMember is IType) && (currentMember.DeclaringTypeDefinition == null || member.DeclaringTypeDefinition == null)) + return false; + + // inner class + var declaringType = currentMember.DeclaringTypeDefinition; + while (declaringType != null) { + if (declaringType.ReflectionName == currentMember.DeclaringType.ReflectionName) + return true; + declaringType = declaringType.DeclaringTypeDefinition; + } + + + return currentMember.DeclaringTypeDefinition != null && member.DeclaringTypeDefinition.FullName == currentMember.DeclaringTypeDefinition.FullName; + } + + IEnumerable<ICompletionData> CreateTypeAndNamespaceCompletionData (TextLocation location, ResolveResult resolveResult, AstNode resolvedNode, CSharpResolver state) + { + if (resolveResult == null || resolveResult.IsError) + return null; + var result = new CompletionDataWrapper (this); + + if (resolveResult is NamespaceResolveResult) { + var nr = (NamespaceResolveResult)resolveResult; + foreach (var cl in ctx.GetTypes (nr.NamespaceName, StringComparer.Ordinal)) { + result.AddType (cl, cl.Name); + } + foreach (var ns in ctx.GetNamespaces ().Where (n => n.Length > nr.NamespaceName.Length && n.StartsWith (nr.NamespaceName))) { + result.AddNamespace (nr.NamespaceName, ns); + } + } else if (resolveResult is TypeResolveResult) { + var type = resolveResult.Type.Resolve (ctx); + foreach (var nested in type.GetNestedTypes (ctx)) { + result.AddType (nested, nested.Name); + } + } + return result.Result; + } + + IEnumerable<ICompletionData> CreateTypeList () + { + foreach (var cl in ctx.GetTypes ("", StringComparer.Ordinal)) { + yield return factory.CreateTypeCompletionData (cl, cl.Name); + } + foreach (var ns in ctx.GetNamespaces ()) { + string name = ns; + int idx = name.IndexOf ("."); + if (idx >= 0) + name = name.Substring (0, idx); + yield return factory.CreateNamespaceCompletionData (name); + } + } + + public ITypeDefinition GetTypeFromContext (ITypeDefinition type) + { + if (type == null || type.DeclaringType != null) + return type; + var result = ctx.GetTypeDefinition (type.Namespace, type.Name, type.TypeParameterCount, StringComparer.Ordinal) ?? type; + if (result.GetParts ().Count == 1) + return type; +// Console.WriteLine ("result:"+ result); + return result; + } + + IEnumerable<ICompletionData> CreateParameterCompletion (MethodGroupResolveResult resolveResult, CSharpResolver state, AstNode invocation, int parameter, bool controlSpace) + { + var result = new CompletionDataWrapper (this); + var addedEnums = new HashSet<string> (); + var addedDelegates = new HashSet<string> (); + + foreach (var method in resolveResult.Methods) { + if (method.Parameters.Count <= parameter) + continue; + var resolvedType = method.Parameters [parameter].Type.Resolve (ctx); + if (resolvedType.Kind == TypeKind.Enum) { + if (addedEnums.Contains (resolvedType.ReflectionName)) + continue; + addedEnums.Add (resolvedType.ReflectionName); + AddEnumMembers (result, resolvedType, state); + } else if (resolvedType.Kind == TypeKind.Delegate) { +// if (addedDelegates.Contains (resolvedType.DecoratedFullName)) +// continue; +// addedDelegates.Add (resolvedType.DecoratedFullName); +// string parameterDefinition = AddDelegateHandlers (completionList, resolvedType, false, addedDelegates.Count == 1); +// string varName = "Handle" + method.Parameters [parameter].ReturnType.Name + method.Parameters [parameter].Name; +// result.Add (new EventCreationCompletionData (document, varName, resolvedType, null, parameterDefinition, resolver.Unit.GetMemberAt (location), resolvedType) { AddSemicolon = false }); + + } + } + if (!controlSpace) { + if (addedEnums.Count + addedDelegates.Count == 0) + return Enumerable.Empty<ICompletionData> (); + AutoCompleteEmptyMatch = false; + AutoSelect = false; + } + AddContextCompletion (result, state, invocation); + +// resolver.AddAccessibleCodeCompletionData (ExpressionContext.MethodBody, cdc); +// if (addedDelegates.Count > 0) { +// foreach (var data in result.Result) { +// if (data is MemberCompletionData) +// ((MemberCompletionData)data).IsDelegateExpected = true; +// } +// } + return result.Result; + } + + string GetShortType (IType type, CSharpResolver state) + { + var builder = new TypeSystemAstBuilder (state); + var shortType = builder.ConvertType (type); + using (var w = new System.IO.StringWriter ()) { + var visitor = new CSharpOutputVisitor (w, FormattingPolicy); + shortType.AcceptVisitor (visitor, null); + return w.ToString (); + } + } + + void AddEnumMembers (CompletionDataWrapper completionList, IType resolvedType, CSharpResolver state) + { + if (resolvedType.Kind != TypeKind.Enum) + return; + string typeString = GetShortType (resolvedType, state); + if (typeString.Contains (".")) + completionList.AddType (resolvedType, typeString); + foreach (var field in resolvedType.GetFields (ctx)) { + if (field.IsConst || field.IsStatic) + completionList.Result.Add (factory.CreateEntityCompletionData (field, typeString + "." + field.Name)); + } + DefaultCompletionString = typeString; + } + + IEnumerable<ICompletionData> CreateCompletionData (TextLocation location, ResolveResult resolveResult, AstNode resolvedNode, CSharpResolver state) + { + if (resolveResult == null /*|| resolveResult.IsError*/) + return null; + if (resolveResult is NamespaceResolveResult) { + var nr = (NamespaceResolveResult)resolveResult; + var namespaceContents = new CompletionDataWrapper (this); + foreach (var cl in ctx.GetTypes (nr.NamespaceName, StringComparer.Ordinal)) { + namespaceContents.AddType (cl, cl.Name); + } + foreach (var ns in ctx.GetNamespaces ().Where (n => n.Length > nr.NamespaceName.Length && n.StartsWith (nr.NamespaceName))) { + namespaceContents.AddNamespace (nr.NamespaceName, ns); + } + + return namespaceContents.Result; + } + + IType type = GetTypeFromContext (resolveResult.Type.GetDefinition ()) ?? resolveResult.Type; + var typeDef = resolveResult.Type.GetDefinition (); + var lookup = new MemberLookup (ctx, currentType, ProjectContent); + var result = new CompletionDataWrapper (this); + bool isProtectedAllowed = false; + bool includeStaticMembers = false; + + if (resolveResult is LocalResolveResult) { + isProtectedAllowed = currentType != null && typeDef != null ? typeDef.GetAllBaseTypeDefinitions (ctx).Any (bt => bt.Equals (currentType)) : false; + if (resolvedNode is IdentifierExpression) { + var mrr = (LocalResolveResult)resolveResult; + includeStaticMembers = mrr.Variable.Name == mrr.Type.Name; + } + } else { + isProtectedAllowed = currentType != null && typeDef != null ? currentType.GetAllBaseTypeDefinitions (ctx).Any (bt => bt.Equals (typeDef)) : false; + } + if (resolveResult is TypeResolveResult && type.Kind == TypeKind.Enum) { + foreach (var field in type.GetFields (ctx)) { + result.AddMember (field); + } + foreach (var m in type.GetMethods (ctx)) { + if (m.Name == "TryParse") + result.AddMember (m); + } + return result.Result; + } + + if (resolveResult is MemberResolveResult && resolvedNode is IdentifierExpression) { + var mrr = (MemberResolveResult)resolveResult; + includeStaticMembers = mrr.Member.Name == mrr.Type.Name; + } + +// Console.WriteLine ("type:" + type +"/"+type.GetType ()); +// Console.WriteLine ("IS PROT ALLOWED:" + isProtectedAllowed); +// Console.WriteLine (resolveResult); +// Console.WriteLine (currentMember != null ? currentMember.IsStatic : "currentMember == null"); + if (resolvedNode.Annotation<ObjectCreateExpression> () == null) { //tags the created expression as part of an object create expression. + foreach (var member in type.GetMembers (ctx)) { + if (!lookup.IsAccessible (member, isProtectedAllowed)) { + // Console.WriteLine ("skip access: " + member.FullName); + continue; + } + if (resolvedNode is BaseReferenceExpression && member.IsAbstract) + continue; + + if (!includeStaticMembers && member.IsStatic && !(resolveResult is TypeResolveResult)) { + // Console.WriteLine ("skip static member: " + member.FullName); + continue; + } + if (!member.IsStatic && (resolveResult is TypeResolveResult)) { + // Console.WriteLine ("skip non static member: " + member.FullName); + continue; + } + // Console.WriteLine ("add : "+ member.FullName + " --- " + member.IsStatic); + result.AddMember (member); + } + } + + if (resolveResult is TypeResolveResult || includeStaticMembers) { + foreach (var nested in type.GetNestedTypes (ctx)) { + result.AddType (nested, nested.Name); + } + + } else { + var baseTypes = new List<IType> (type.GetAllBaseTypes (ctx)); + var conv = new Conversions (ctx); + for (var n = state.CurrentUsingScope; n != null; n = n.Parent) { + AddExtensionMethods (result, conv, baseTypes, n.NamespaceName); + foreach (var u in n.Usings) { + var ns = u.ResolveNamespace (ctx); + if (ns == null) + continue; + AddExtensionMethods (result, conv, baseTypes, ns.NamespaceName); + } + } + } + +// IEnumerable<object> objects = resolveResult.CreateResolveResult (dom, resolver != null ? resolver.CallingMember : null); +// CompletionDataCollector col = new CompletionDataCollector (this, dom, result, Document.CompilationUnit, resolver != null ? resolver.CallingType : null, location); +// col.HideExtensionParameter = !resolveResult.StaticResolve; +// col.NamePrefix = expressionResult.Expression; +// bool showOnlyTypes = expressionResult.Contexts.Any (ctx => ctx == ExpressionContext.InheritableType || ctx == ExpressionContext.Constraints); +// if (objects != null) { +// foreach (object obj in objects) { +// if (expressionResult.ExpressionContext != null && expressionResult.ExpressionContext.FilterEntry (obj)) +// continue; +// if (expressionResult.ExpressionContext == ExpressionContext.NamespaceNameExcepted && !(obj is Namespace)) +// continue; +// if (showOnlyTypes && !(obj is IType)) +// continue; +// CompletionData data = col.Add (obj); +// if (data != null && expressionResult.ExpressionContext == ExpressionContext.Attribute && data.CompletionText != null && data.CompletionText.EndsWith ("Attribute")) { +// string newText = data.CompletionText.Substring (0, data.CompletionText.Length - "Attribute".Length); +// data.SetText (newText); +// } +// } +// } + + return result.Result; + } + + void AddExtensionMethods (CompletionDataWrapper result, Conversions conv, List<IType> baseTypes, string namespaceName) + { + foreach (var typeDefinition in ctx.GetTypes (namespaceName, StringComparer.Ordinal).Where (t => t.IsStatic && t.HasExtensionMethods)) { + foreach (var m in typeDefinition.Methods.Where (m => m.IsExtensionMethod )) { + var pt = m.Parameters.First ().Type.Resolve (ctx); + string reflectionName = pt is ParameterizedType ? ((ParameterizedType)pt).GetDefinition ().ReflectionName : pt.ReflectionName; + if (baseTypes.Any (bt => (bt is ParameterizedType ? ((ParameterizedType)bt).GetDefinition ().ReflectionName : bt.ReflectionName) == reflectionName)) { + result.AddMember (m); + } + } + } + } + IEnumerable<ICompletionData> CreateCaseCompletionData (TextLocation location) + { + var unit = ParseStub ("a: break;"); + if (unit == null) + return null; + var s = unit.GetNodeAt<SwitchStatement> (location); + if (s == null) + return null; + + var offset = document.GetOffset (s.Expression.StartLocation); + var expr = GetExpressionAt (offset); + if (expr == null) + return null; + + var resolveResult = ResolveExpression (expr.Item1, expr.Item2, expr.Item3); + if (resolveResult == null || resolveResult.Item1.Type.Kind != TypeKind.Enum) + return null; + var wrapper = new CompletionDataWrapper (this); + AddEnumMembers (wrapper, resolveResult.Item1.Type, resolveResult.Item2); + AutoCompleteEmptyMatch = false; + return wrapper.Result; + } + + #region Parsing methods + Tuple<CSharpParsedFile, AstNode, CompilationUnit> GetExpressionBeforeCursor () + { + CompilationUnit baseUnit; + if (currentMember == null) { + baseUnit = ParseStub ("st {}", false); + var type = baseUnit.GetNodeAt<MemberType> (location); + if (type == null) { + baseUnit = ParseStub ("a;", false); + type = baseUnit.GetNodeAt<MemberType> (location); + } + if (type != null) { + // insert target type into compilation unit, to respect the + var target = type.Target; + target.Remove (); + var node = Unit.GetNodeAt (location) ?? Unit; + node.AddChild (target, AstNode.Roles.Type); + return Tuple.Create (CSharpParsedFile, (AstNode)target, Unit); + } + } + + if (currentMember == null && currentType == null) { + return null; + } + baseUnit = ParseStub ("a()"); + + // Hack for handle object initializer continuation expressions + if (baseUnit.GetNodeAt (location) is AttributedNode) { + baseUnit = ParseStub ("a()};"); + } + + var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin; + var mref = baseUnit.GetNodeAt<MemberReferenceExpression> (location); + + if (mref == null){ + var invoke = baseUnit.GetNodeAt<InvocationExpression> (location); + if (invoke != null) + mref = invoke.Target as MemberReferenceExpression; + } + Expression expr = null; + if (mref != null) { + expr = mref.Target.Clone (); + mref.Parent.ReplaceWith (expr); + } else { + Expression tref = baseUnit.GetNodeAt<TypeReferenceExpression> (location); + var memberType = tref != null ? ((TypeReferenceExpression)tref).Type as MemberType : null; + if (memberType == null) { + memberType = baseUnit.GetNodeAt<MemberType> (location); + if (memberType != null) { + tref = baseUnit.GetNodeAt<Expression> (location); + if (tref == null) + return null; + } + if (tref is ObjectCreateExpression) { + expr = new TypeReferenceExpression (memberType.Target.Clone ()); + expr.AddAnnotation (new ObjectCreateExpression ()); + } + } + + if (memberType == null) + return null; + if (expr == null) + expr = new TypeReferenceExpression (memberType.Target.Clone ()); + tref.ReplaceWith (expr); + } + + var member = Unit.GetNodeAt<AttributedNode> (memberLocation); + var member2 = baseUnit.GetNodeAt<AttributedNode> (memberLocation); + member2.Remove (); + member.ReplaceWith (member2); + var tsvisitor = new TypeSystemConvertVisitor (ProjectContent, this.CSharpParsedFile.FileName); + Unit.AcceptVisitor (tsvisitor, null); + return Tuple.Create (tsvisitor.ParsedFile, (AstNode)expr, Unit); + } + + Tuple<CSharpParsedFile, AstNode, CompilationUnit> GetExpressionAtCursor () + { +// if (currentMember == null && currentType == null) +// return null; + + TextLocation memberLocation; + if (currentMember != null) { + memberLocation = currentMember.Region.Begin; + } else if (currentType != null) { + memberLocation = currentType.Region.Begin; + } else { + memberLocation = location; + } + + var baseUnit = ParseStub (""); + var tmpUnit = baseUnit; + AstNode expr = baseUnit.GetNodeAt<IdentifierExpression> (location.Line, location.Column - 1); + if (expr == null) + expr = baseUnit.GetNodeAt<Attribute> (location.Line, location.Column - 1); + + if (expr == null) { + baseUnit = ParseStub ("()"); + expr = baseUnit.GetNodeAt<IdentifierExpression> (location.Line, location.Column - 1); + } + + // try initializer expression + if (expr == null) { + baseUnit = ParseStub ("a = b};", false); + expr = baseUnit.GetNodeAt<ArrayInitializerExpression> (location.Line, location.Column - 1); + } + + // try statement + if (expr == null) { + expr = tmpUnit.GetNodeAt<SwitchStatement> (location.Line, location.Column - 1); + baseUnit = tmpUnit; + } + + if (expr == null) { + var forStmt = tmpUnit.GetNodeAt<ForStatement> (location.Line, location.Column - 3); + expr = forStmt; + if (forStmt != null && forStmt.EmbeddedStatement.IsNull) { + var id = new IdentifierExpression ("stub"); + forStmt.EmbeddedStatement = new BlockStatement () { Statements = { new ExpressionStatement (id) }}; + expr = id; + } + baseUnit = tmpUnit; + } + + if (expr == null) + return null; + var member = Unit.GetNodeAt<AttributedNode> (memberLocation); + var member2 = baseUnit.GetNodeAt<AttributedNode> (memberLocation); + if (member != null && member2 != null) { + member2.Remove (); + + if (member is TypeDeclaration) { + member.AddChild (member2, TypeDeclaration.MemberRole); + } else { + member.ReplaceWith (member2); + } + } else { + var tsvisitor2 = new TypeSystemConvertVisitor (ProjectContent, CSharpParsedFile.FileName); + Unit.AcceptVisitor (tsvisitor2, null); + return Tuple.Create (tsvisitor2.ParsedFile, expr, baseUnit); + } + var tsvisitor = new TypeSystemConvertVisitor (ProjectContent, CSharpParsedFile.FileName); + Unit.AcceptVisitor (tsvisitor, null); + return Tuple.Create (tsvisitor.ParsedFile, expr, Unit); + } + + Tuple<CSharpParsedFile, AstNode, CompilationUnit> GetExpressionAt (int offset) + { + var parser = new CSharpParser (); + string text = this.document.GetText (0, this.offset); + var sb = new StringBuilder (text); + sb.Append ("a;"); + AppendMissingClosingBrackets (sb, text, false); + var stream = new System.IO.StringReader (sb.ToString ()); + var completionUnit = parser.Parse (stream, 0); + stream.Close (); + var loc = document.GetLocation (offset); + + var expr = completionUnit.GetNodeAt (loc, n => n is Expression || n is VariableDeclarationStatement); + if (expr == null) + return null; + var tsvisitor = new TypeSystemConvertVisitor (ProjectContent, CSharpParsedFile.FileName); + completionUnit.AcceptVisitor (tsvisitor, null); + + return Tuple.Create (tsvisitor.ParsedFile, expr, completionUnit); + } + + + Tuple<CSharpParsedFile, AstNode, CompilationUnit> GetNewExpressionAt (int offset) + { + var parser = new CSharpParser (); + string text = this.document.GetText (0, this.offset); + var sb = new StringBuilder (text); + sb.Append ("a ();"); + AppendMissingClosingBrackets (sb, text, false); + var stream = new System.IO.StringReader (sb.ToString ()); + var completionUnit = parser.Parse (stream, 0); + stream.Close (); + var loc = document.GetLocation (offset); + + var expr = completionUnit.GetNodeAt (loc, n => n is Expression); + if (expr == null) + return null; + var tsvisitor = new TypeSystemConvertVisitor (ProjectContent, CSharpParsedFile.FileName); + completionUnit.AcceptVisitor (tsvisitor, null); + + return Tuple.Create (tsvisitor.ParsedFile, expr, completionUnit); + } + + + #endregion + + #region Helper methods + string GetPreviousToken (ref int i, bool allowLineChange) + { + char c; + if (i <= 0) + return null; + + do { + c = document.GetCharAt (--i); + } while (i > 0 && char.IsWhiteSpace (c) && (allowLineChange ? true : c != '\n')); + + if (i == 0) + return null; + + if (!char.IsLetterOrDigit (c)) + return new string (c, 1); + + int endOffset = i + 1; + + do { + c = document.GetCharAt (i - 1); + if (!(char.IsLetterOrDigit (c) || c == '_')) + break; + + i--; + } while (i > 0); + + return document.GetText (i, endOffset - i); + } + + bool GetParameterCompletionCommandOffset (out int cpos) + { + // Start calculating the parameter offset from the beginning of the + // current member, instead of the beginning of the file. + cpos = offset - 1; + IMember mem = currentMember; + if (mem == null || (mem is IType)) + return false; + int startPos = document.GetOffset (mem.Region.BeginLine, mem.Region.BeginColumn); + int parenDepth = 0; + int chevronDepth = 0; + while (cpos > startPos) { + char c = document.GetCharAt (cpos); + if (c == ')') + parenDepth++; + if (c == '>') + chevronDepth++; + if (parenDepth == 0 && c == '(' || chevronDepth == 0 && c == '<') { + int p = GetCurrentParameterIndex (cpos + 1, startPos); + if (p != -1) { + cpos++; + return true; + } else { + return false; + } + } + if (c == '(') + parenDepth--; + if (c == '<') + chevronDepth--; + cpos--; + } + return false; + } + + int GetCurrentParameterIndex (int offset, int memberStart) + { + int cursor = this.offset; + int i = offset; + + if (i > cursor) + return -1; + if (i == cursor) + return 1; // parameters are 1 based + int index = memberStart + 1; + int parentheses = 0; + int bracket = 0; + bool insideQuote = false, insideString = false, insideSingleLineComment = false, insideMultiLineComment = false; + do { + char c = document.GetCharAt (i - 1); + switch (c) { + case '\\': + if (insideString || insideQuote) + i++; + break; + case '\'': + if (!insideString && !insideSingleLineComment && !insideMultiLineComment) + insideQuote = !insideQuote; + break; + case '"': + if (!insideQuote && !insideSingleLineComment && !insideMultiLineComment) + insideString = !insideString; + break; + case '/': + if (!insideQuote && !insideString && !insideMultiLineComment) { + if (document.GetCharAt (i) == '/') + insideSingleLineComment = true; + if (document.GetCharAt (i) == '*') + insideMultiLineComment = true; + } + break; + case '*': + if (insideMultiLineComment && document.GetCharAt (i) == '/') + insideMultiLineComment = false; + break; + case '\n': + case '\r': + insideSingleLineComment = false; + break; + case '{': + if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment) + bracket++; + break; + case '}': + if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment) + bracket--; + break; + case '(': + if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment) + parentheses++; + break; + case ')': + if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment) + parentheses--; + break; + case ',': + if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment && parentheses == 1 && bracket == 0) + index++; + break; + } + i++; + } while (i <= cursor && parentheses >= 0); + + return parentheses != 1 || bracket > 0 ? -1 : index; + } + + CSharpResolver GetState () + { + var state = new CSharpResolver (ctx, System.Threading.CancellationToken.None); + + state.CurrentMember = CSharpParsedFile.GetMember (location); + state.CurrentTypeDefinition = CSharpParsedFile.GetInnermostTypeDefinition (location); + state.CurrentUsingScope = CSharpParsedFile.GetUsingScope (location); + if (state.CurrentMember != null) { + var node = Unit.GetNodeAt (location); + if (node == null) + return state; + var navigator = new NodeListResolveVisitorNavigator (new[] { node }); + var visitor = new ResolveVisitor (state, CSharpParsedFile, navigator); + Unit.AcceptVisitor (visitor, null); + try { + var newState = visitor.GetResolverStateBefore (node); + if (newState != null) + state = newState; + } catch (Exception) { + } + } + + return state; + } + #endregion + + #region Preprocessor + + IEnumerable<ICompletionData> GetDirectiveCompletionData () + { + yield return factory.CreateLiteralCompletionData ("if"); + yield return factory.CreateLiteralCompletionData ("else"); + yield return factory.CreateLiteralCompletionData ("elif"); + yield return factory.CreateLiteralCompletionData ("endif"); + yield return factory.CreateLiteralCompletionData ("define"); + yield return factory.CreateLiteralCompletionData ("undef"); + yield return factory.CreateLiteralCompletionData ("warning"); + yield return factory.CreateLiteralCompletionData ("error"); + yield return factory.CreateLiteralCompletionData ("pragma"); + yield return factory.CreateLiteralCompletionData ("line"); + yield return factory.CreateLiteralCompletionData ("line hidden"); + yield return factory.CreateLiteralCompletionData ("line default"); + yield return factory.CreateLiteralCompletionData ("region"); + yield return factory.CreateLiteralCompletionData ("endregion"); + } + #endregion + + #region Xml Comments + static readonly List<string> commentTags = new List<string> (new string[] { "c", "code", "example", "exception", "include", "list", "listheader", "item", "term", "description", "para", "param", "paramref", "permission", "remarks", "returns", "see", "seealso", "summary", "value" }); + + IEnumerable<ICompletionData> GetXmlDocumentationCompletionData () + { + yield return factory.CreateLiteralCompletionData ("c", "Set text in a code-like font"); + yield return factory.CreateLiteralCompletionData ("code", "Set one or more lines of source code or program output"); + yield return factory.CreateLiteralCompletionData ("example", "Indicate an example"); + yield return factory.CreateLiteralCompletionData ("exception", "Identifies the exceptions a method can throw", "exception cref=\"|\"></exception>"); + yield return factory.CreateLiteralCompletionData ("include", "Includes comments from a external file", "include file=\"|\" path=\"\">"); + yield return factory.CreateLiteralCompletionData ("list", "Create a list or table", "list type=\"|\">"); + yield return factory.CreateLiteralCompletionData ("listheader", "Define the heading row"); + yield return factory.CreateLiteralCompletionData ("item", "Defines list or table item"); + + yield return factory.CreateLiteralCompletionData ("term", "A term to define"); + yield return factory.CreateLiteralCompletionData ("description", "Describes a list item"); + yield return factory.CreateLiteralCompletionData ("para", "Permit structure to be added to text"); + + yield return factory.CreateLiteralCompletionData ("param", "Describe a parameter for a method or constructor", "param name=\"|\">"); + yield return factory.CreateLiteralCompletionData ("paramref", "Identify that a word is a parameter name", "paramref name=\"|\"/>"); + + yield return factory.CreateLiteralCompletionData ("permission", "Document the security accessibility of a member", "permission cref=\"|\""); + yield return factory.CreateLiteralCompletionData ("remarks", "Describe a type"); + yield return factory.CreateLiteralCompletionData ("returns", "Describe the return value of a method"); + yield return factory.CreateLiteralCompletionData ("see", "Specify a link", "see cref=\"|\"/>"); + yield return factory.CreateLiteralCompletionData ("seealso", "Generate a See Also entry", "seealso cref=\"|\"/>"); + yield return factory.CreateLiteralCompletionData ("summary", "Describe a member of a type"); + yield return factory.CreateLiteralCompletionData ("typeparam", "Describe a type parameter for a generic type or method"); + yield return factory.CreateLiteralCompletionData ("typeparamref", "Identify that a word is a type parameter name"); + yield return factory.CreateLiteralCompletionData ("value", "Describe a property"); + } + #endregion + + #region Keywords + static string[] expressionLevelKeywords = new string [] { "as", "is", "else", "out", "ref", "null", "delegate", "default"}; + + static string[] primitiveTypesKeywords = new string [] { "void", "object", "bool", "byte", "sbyte", "char", "short", "int", "long", "ushort", "uint", "ulong", "float", "double", "decimal", "string"}; + + static string[] statementStartKeywords = new string [] { "base", "new", "sizeof", "this", + "true", "false", "typeof", "checked", "unchecked", "from", "break", "checked", + "unchecked", "const", "continue", "do", "finally", "fixed", "for", "foreach", + "goto", "if", "lock", "return", "stackalloc", "switch", "throw", "try", "unsafe", + "using", "while", "yield", "dynamic", "var" }; + + static string[] globalLevelKeywords = new string [] { + "namespace", "using", "extern", "public", "internal", + "class", "interface", "struct", "enum", "delegate", + "abstract", "sealed", "static", "unsafe", "partial" + }; + + static string[] accessorModifierKeywords = new string [] { + "public", "internal", "protected", "private" + }; + + static string[] typeLevelKeywords = new string [] { + "public", "internal", "protected", "private", + "class", "interface", "struct", "enum", "delegate", + "abstract", "sealed", "static", "unsafe", "partial", + "const", "event", "extern", "fixed","new", + "operator", "explicit", "implicit", + "override", "readonly", "virtual", "volatile" + }; + static string[] linqKeywords = new string[] { "from", "where", "select", "group", "into", "orderby", "join", "let", "in", "on", "equals", "by", "ascending", "descending" }; + #endregion + } +} + diff --git a/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs b/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs index 2cb81e30bb..767826ba8a 100644 --- a/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs +++ b/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs @@ -1,445 +1,446 @@ -//
-// CSharpCompletionEngineBase.cs
-//
-// Author:
-// Mike Krüger <mkrueger@xamarin.com>
-//
-// Copyright (c) 2011 Xamarin Inc. (http://xamarin.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-using ICSharpCode.NRefactory.CSharp.Resolver;
-using ICSharpCode.NRefactory.Editor;
-using ICSharpCode.NRefactory.TypeSystem;
-using ICSharpCode.NRefactory.Semantics;
-
-namespace ICSharpCode.NRefactory.CSharp.Completion
-{
- /// <summary>
- /// Acts as a common base between code completion and parameter completion.
- /// </summary>
- public class CSharpCompletionEngineBase
- {
- protected IDocument document;
- protected int offset;
- protected TextLocation location;
-
- protected ITypeDefinition currentType;
- protected IMember currentMember;
-
- #region Input properties
- public ITypeResolveContext ctx { get; set; }
- public CompilationUnit Unit { get; set; }
- public CSharpParsedFile CSharpParsedFile { get; set; }
- public IProjectContent ProjectContent { get; set; }
- #endregion
-
- protected void SetOffset (int offset)
- {
- Reset ();
-
- this.offset = offset;
- this.location = document.GetLocation (offset);
-
- this.currentType = CSharpParsedFile.GetInnermostTypeDefinition (location);
- this.currentMember = CSharpParsedFile.GetMember (location);
- }
-
- #region Context helper methods
- protected bool IsInsideCommentOrString ()
- {
- var text = GetMemberTextToCaret ();
- bool inSingleComment = false, inString = false, inVerbatimString = false, inChar = false, inMultiLineComment = false;
-
- for (int i = 0; i < text.Item1.Length - 1; i++) {
- char ch = text.Item1[i];
- char nextCh = text.Item1[i + 1];
-
- switch (ch) {
- case '/':
- if (inString || inChar || inVerbatimString)
- break;
- if (nextCh == '/') {
- i++;
- inSingleComment = true;
- }
- if (nextCh == '*')
- inMultiLineComment = true;
- break;
- case '*':
- if (inString || inChar || inVerbatimString || inSingleComment)
- break;
- if (nextCh == '/') {
- i++;
- inMultiLineComment = false;
- }
- break;
- case '@':
- if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
- break;
- if (nextCh == '"') {
- i++;
- inVerbatimString = true;
- }
- break;
- case '\n':
- case '\r':
- inSingleComment = false;
- inString = false;
- inChar = false;
- break;
- case '\\':
- if (inString || inChar)
- i++;
- break;
- case '"':
- if (inSingleComment || inMultiLineComment || inChar)
- break;
- if (inVerbatimString) {
- if (nextCh == '"') {
- i++;
- break;
- }
- inVerbatimString = false;
- break;
- }
- inString = !inString;
- break;
- case '\'':
- if (inSingleComment || inMultiLineComment || inString || inVerbatimString)
- break;
- inChar = !inChar;
- break;
- }
- }
-
- return inSingleComment || inString || inVerbatimString || inChar || inMultiLineComment;
- }
-
- protected bool IsInsideComment (int offset)
- {
- var loc = document.GetLocation (offset);
- return Unit.GetNodeAt<ICSharpCode.NRefactory.CSharp.Comment> (loc.Line, loc.Column) != null;
- }
-
- protected bool IsInsideDocComment ()
- {
- var loc = document.GetLocation (offset);
- var cmt = Unit.GetNodeAt<ICSharpCode.NRefactory.CSharp.Comment> (loc.Line, loc.Column - 1);
- return cmt != null && cmt.CommentType == CommentType.Documentation;
- }
-
- protected bool IsInsideString (int offset)
- {
-
- var loc = document.GetLocation (offset);
- var expr = Unit.GetNodeAt<PrimitiveExpression> (loc.Line, loc.Column);
- return expr != null && expr.Value is string;
- }
- #endregion
-
- #region Basic parsing/resolving functions
- protected void AppendMissingClosingBrackets (StringBuilder wrapper, string memberText, bool appendSemicolon)
- {
- var bracketStack = new Stack<Tuple<char, int>> ();
-
- bool isInString = false, isInChar = false;
- bool isInLineComment = false, isInBlockComment = false;
-
- for (int pos = 0; pos < memberText.Length; pos++) {
- char ch = memberText [pos];
- switch (ch) {
- case '(':
- case '[':
- case '{':
- if (!isInString && !isInChar && !isInLineComment && !isInBlockComment)
- bracketStack.Push (Tuple.Create (ch, pos));
- break;
- case ')':
- case ']':
- case '}':
- if (!isInString && !isInChar && !isInLineComment && !isInBlockComment)
- if (bracketStack.Count > 0)
- bracketStack.Pop ();
- break;
- case '\r':
- case '\n':
- isInLineComment = false;
- break;
- case '/':
- if (isInBlockComment) {
- if (pos > 0 && memberText [pos - 1] == '*')
- isInBlockComment = false;
- } else if (!isInString && !isInChar && pos + 1 < memberText.Length) {
- char nextChar = memberText [pos + 1];
- if (nextChar == '/')
- isInLineComment = true;
- if (!isInLineComment && nextChar == '*')
- isInBlockComment = true;
- }
- break;
- case '"':
- if (!(isInChar || isInLineComment || isInBlockComment))
- isInString = !isInString;
- break;
- case '\'':
- if (!(isInString || isInLineComment || isInBlockComment))
- isInChar = !isInChar;
- break;
- default :
- break;
- }
- }
- bool didAppendSemicolon = !appendSemicolon;
-
- char lastBracket = '\0';
- while (bracketStack.Count > 0) {
- var t = bracketStack.Pop ();
- switch (t.Item1) {
- case '(':
- wrapper.Append (')');
- didAppendSemicolon = false;
- lastBracket = ')';
- break;
- case '[':
- wrapper.Append (']');
- didAppendSemicolon = false;
- lastBracket = ']';
- break;
- case '<':
- wrapper.Append ('>');
- didAppendSemicolon = false;
- lastBracket = '>';
- break;
- case '{':
- int o = t.Item2 - 1;
- if (!didAppendSemicolon) {
- didAppendSemicolon = true;
- wrapper.Append (';');
- }
-
- bool didAppendCatch = false;
- while (o >= "try".Length) {
- char ch = memberText[o];
- if (!char.IsWhiteSpace (ch)) {
- if (ch == 'y' && memberText[o - 1] == 'r' && memberText[o - 2] == 't') {
- wrapper.Append ("} catch {}");
- didAppendCatch = true;
- }
- break;
- }
- o--;
- }
- if (!didAppendCatch)
- wrapper.Append ('}');
- break;
- }
- }
- if (currentMember == null && lastBracket == ']') {
- // attribute context
- wrapper.Append ("class GenAttr {}");
- } else {
- if (!didAppendSemicolon)
- wrapper.Append (';');
- }
- }
-
- protected CompilationUnit ParseStub (string continuation, bool appendSemicolon = true)
- {
- var mt = GetMemberTextToCaret ();
- if (mt == null)
- return null;
-
- string memberText = mt.Item1;
- bool wrapInClass = mt.Item2;
-
- var wrapper = new StringBuilder ();
- if (wrapInClass) {
- wrapper.Append ("class Stub {");
- wrapper.AppendLine ();
- }
-
- wrapper.Append (memberText);
- wrapper.Append (continuation);
- AppendMissingClosingBrackets (wrapper, memberText, appendSemicolon);
-
- if (wrapInClass)
- wrapper.Append ('}');
-
- TextLocation memberLocation;
- if (currentMember != null) {
- memberLocation = currentMember.Region.Begin;
- } else if (currentType != null) {
- memberLocation = currentType.Region.Begin;
- } else {
- memberLocation = new TextLocation (1, 1);
- }
- using (var stream = new System.IO.StringReader (wrapper.ToString ())) {
- var parser = new CSharpParser ();
- return parser.Parse (stream, wrapInClass ? memberLocation.Line - 2 : 0);
- }
- }
-
- string cachedText = null;
-
- protected virtual void Reset ()
- {
- cachedText = null;
- }
-
- protected Tuple<string, bool> GetMemberTextToCaret ()
- {
- int startOffset;
- if (currentMember != null) {
- startOffset = document.GetOffset (currentMember.Region.BeginLine, currentMember.Region.BeginColumn);
- } else if (currentType != null) {
- startOffset = document.GetOffset (currentType.Region.BeginLine, currentType.Region.BeginColumn);
- } else {
- startOffset = 0;
- }
- if (cachedText == null)
- cachedText = document.GetText (startOffset, offset - startOffset);
-
- return Tuple.Create (cachedText, startOffset != 0);
- }
-
- protected Tuple<CSharpParsedFile, AstNode, CompilationUnit> GetInvocationBeforeCursor (bool afterBracket)
- {
- CompilationUnit baseUnit;
- if (currentMember == null) {
- baseUnit = ParseStub ("", false);
- var section = baseUnit.GetNodeAt<AttributeSection> (location.Line, location.Column - 2);
- var attr = section != null ? section.Attributes.LastOrDefault () : null;
- if (attr != null) {
- // insert target type into compilation unit, to respect the
- attr.Remove ();
- var node = Unit.GetNodeAt (location) ?? Unit;
- node.AddChild (attr, AttributeSection.AttributeRole);
- return Tuple.Create (CSharpParsedFile, (AstNode)attr, Unit);
- }
- }
-
- if (currentMember == null && currentType == null) {
- return null;
- }
- baseUnit = ParseStub (afterBracket ? "" : "x");
-
- var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
- var mref = baseUnit.GetNodeAt (location.Line, location.Column - 1, n => n is InvocationExpression || n is ObjectCreateExpression);
- AstNode expr;
- if (mref is InvocationExpression) {
- expr = ((InvocationExpression)mref).Target;
- } else if (mref is ObjectCreateExpression) {
- expr = mref;
- } else {
- return null;
- }
-
- /* var member = Unit.GetNodeAt<AttributedNode> (memberLocation);
- var member2 = baseUnit.GetNodeAt<AttributedNode> (memberLocation);
- member2.Remove ();
- member.ReplaceWith (member2);
- var tsvisitor = new TypeSystemConvertVisitor (ProjectContent, CSharpParsedFile.FileName);
- baseUnit.AcceptVisitor (tsvisitor, null);*/
- return Tuple.Create (CSharpParsedFile, (AstNode)expr, baseUnit);
-
- /*
-
- ///////
- if (currentMember == null && currentType == null)
- return null;
-
- CSharpParser parser = new CSharpParser ();
- int startOffset;
- if (currentMember != null) {
- startOffset = document.Editor.LocationToOffset (currentMember.Region.BeginLine, currentMember.Region.BeginColumn);
- } else {
- startOffset = document.Editor.LocationToOffset (currentType.Region.BeginLine, currentType.Region.BeginColumn);
- }
- string memberText = Document.Editor.GetTextBetween (startOffset, Document.Editor.Caret.Offset - 1);
-
- var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
- StringBuilder wrapper = new StringBuilder ();
- wrapper.Append ("class Stub {");
- wrapper.AppendLine ();
- wrapper.Append (memberText);
-
- if (afterBracket) {
- wrapper.Append ("();");
- } else {
- wrapper.Append ("x);");
- }
-
- wrapper.Append (" SomeCall (); } } }");
- var stream = new System.IO.StringReader (wrapper.ToString ());
- var baseUnit = parser.Parse (stream, memberLocation.Line - 2);
- stream.Close ();
- var expr = baseUnit.GetNodeAt<Expression> (document.Editor.Caret.Line, document.Editor.Caret.Column);
- if (expr is InvocationExpression) {
- expr = ((InvocationExpression)expr).Target;
- }
- if (expr == null)
- return null;
- var member = Unit.GetNodeAt<AttributedNode> (memberLocation);
- var member2 = baseUnit.GetNodeAt<AttributedNode> (memberLocation);
- member2.Remove ();
- member.ReplaceWith (member2);
-
- var tsvisitor = new TypeSystemConvertVisitor (ProjectContext, Document.FileName);
- Unit.AcceptVisitor (tsvisitor, null);
- return Tuple.Create (tsvisitor.ParsedFile, expr, Unit);*/
- }
-
- protected Tuple<ResolveResult, CSharpResolver> ResolveExpression (CSharpParsedFile file, AstNode expr, CompilationUnit unit)
- {
- if (expr == null)
- return null;
- AstNode resolveNode;
- if (expr is Expression || expr is AstType) {
- resolveNode = expr;
- } else if (expr is VariableDeclarationStatement) {
- resolveNode = ((VariableDeclarationStatement)expr).Type;
- } else {
- resolveNode = expr;
- }
-
- var csResolver = new CSharpResolver (ctx, System.Threading.CancellationToken.None);
- var navigator = new NodeListResolveVisitorNavigator (new[] { resolveNode });
- var visitor = new ResolveVisitor (csResolver, file, navigator);
- visitor.Scan (unit);
-// Print (unit);
- var state = visitor.GetResolverStateBefore (resolveNode);
- var result = visitor.GetResolveResult (resolveNode);
- return Tuple.Create (result, state);
- }
-
- protected static void Print (AstNode node)
- {
- var v = new CSharpOutputVisitor (Console.Out, new CSharpFormattingOptions ());
- node.AcceptVisitor (v, null);
- }
-
- #endregion
- }
+// +// CSharpCompletionEngineBase.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// Copyright (c) 2011 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using ICSharpCode.NRefactory.CSharp.Resolver; +using ICSharpCode.NRefactory.Editor; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.Semantics; + +namespace ICSharpCode.NRefactory.CSharp.Completion +{ + /// <summary> + /// Acts as a common base between code completion and parameter completion. + /// </summary> + public class CSharpCompletionEngineBase + { + protected IDocument document; + protected int offset; + protected TextLocation location; + + protected ITypeDefinition currentType; + protected IMember currentMember; + + #region Input properties + public ITypeResolveContext ctx { get; set; } + public CompilationUnit Unit { get; set; } + public CSharpParsedFile CSharpParsedFile { get; set; } + public IProjectContent ProjectContent { get; set; } + #endregion + + protected void SetOffset (int offset) + { + Reset (); + + this.offset = offset; + this.location = document.GetLocation (offset); + + this.currentType = CSharpParsedFile.GetInnermostTypeDefinition (location); + this.currentMember = CSharpParsedFile.GetMember (location); + } + + #region Context helper methods + protected bool IsInsideCommentOrString () + { + var text = GetMemberTextToCaret (); + bool inSingleComment = false, inString = false, inVerbatimString = false, inChar = false, inMultiLineComment = false; + + for (int i = 0; i < text.Item1.Length - 1; i++) { + char ch = text.Item1[i]; + char nextCh = text.Item1[i + 1]; + + switch (ch) { + case '/': + if (inString || inChar || inVerbatimString) + break; + if (nextCh == '/') { + i++; + inSingleComment = true; + } + if (nextCh == '*') + inMultiLineComment = true; + break; + case '*': + if (inString || inChar || inVerbatimString || inSingleComment) + break; + if (nextCh == '/') { + i++; + inMultiLineComment = false; + } + break; + case '@': + if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) + break; + if (nextCh == '"') { + i++; + inVerbatimString = true; + } + break; + case '\n': + case '\r': + inSingleComment = false; + inString = false; + inChar = false; + break; + case '\\': + if (inString || inChar) + i++; + break; + case '"': + if (inSingleComment || inMultiLineComment || inChar) + break; + if (inVerbatimString) { + if (nextCh == '"') { + i++; + break; + } + inVerbatimString = false; + break; + } + inString = !inString; + break; + case '\'': + if (inSingleComment || inMultiLineComment || inString || inVerbatimString) + break; + inChar = !inChar; + break; + } + } + + return inSingleComment || inString || inVerbatimString || inChar || inMultiLineComment; + } + + protected bool IsInsideComment (int offset) + { + var loc = document.GetLocation (offset); + return Unit.GetNodeAt<ICSharpCode.NRefactory.CSharp.Comment> (loc.Line, loc.Column) != null; + } + + protected bool IsInsideDocComment () + { + var loc = document.GetLocation (offset); + var cmt = Unit.GetNodeAt<ICSharpCode.NRefactory.CSharp.Comment> (loc.Line, loc.Column - 1); + return cmt != null && cmt.CommentType == CommentType.Documentation; + } + + protected bool IsInsideString (int offset) + { + + var loc = document.GetLocation (offset); + var expr = Unit.GetNodeAt<PrimitiveExpression> (loc.Line, loc.Column); + return expr != null && expr.Value is string; + } + #endregion + + #region Basic parsing/resolving functions + protected void AppendMissingClosingBrackets (StringBuilder wrapper, string memberText, bool appendSemicolon) + { + var bracketStack = new Stack<Tuple<char, int>> (); + + bool isInString = false, isInChar = false; + bool isInLineComment = false, isInBlockComment = false; + + for (int pos = 0; pos < memberText.Length; pos++) { + char ch = memberText [pos]; + switch (ch) { + case '(': + case '[': + case '{': + if (!isInString && !isInChar && !isInLineComment && !isInBlockComment) + bracketStack.Push (Tuple.Create (ch, pos)); + break; + case ')': + case ']': + case '}': + if (!isInString && !isInChar && !isInLineComment && !isInBlockComment) + if (bracketStack.Count > 0) + bracketStack.Pop (); + break; + case '\r': + case '\n': + isInLineComment = false; + break; + case '/': + if (isInBlockComment) { + if (pos > 0 && memberText [pos - 1] == '*') + isInBlockComment = false; + } else if (!isInString && !isInChar && pos + 1 < memberText.Length) { + char nextChar = memberText [pos + 1]; + if (nextChar == '/') + isInLineComment = true; + if (!isInLineComment && nextChar == '*') + isInBlockComment = true; + } + break; + case '"': + if (!(isInChar || isInLineComment || isInBlockComment)) + isInString = !isInString; + break; + case '\'': + if (!(isInString || isInLineComment || isInBlockComment)) + isInChar = !isInChar; + break; + default : + break; + } + } + bool didAppendSemicolon = !appendSemicolon; + + char lastBracket = '\0'; + while (bracketStack.Count > 0) { + var t = bracketStack.Pop (); + switch (t.Item1) { + case '(': + wrapper.Append (')'); + didAppendSemicolon = false; + lastBracket = ')'; + break; + case '[': + wrapper.Append (']'); + didAppendSemicolon = false; + lastBracket = ']'; + break; + case '<': + wrapper.Append ('>'); + didAppendSemicolon = false; + lastBracket = '>'; + break; + case '{': + int o = t.Item2 - 1; + if (!didAppendSemicolon) { + didAppendSemicolon = true; + wrapper.Append (';'); + } + + bool didAppendCatch = false; + while (o >= "try".Length) { + char ch = memberText[o]; + if (!char.IsWhiteSpace (ch)) { + if (ch == 'y' && memberText[o - 1] == 'r' && memberText[o - 2] == 't') { + wrapper.Append ("} catch {}"); + didAppendCatch = true; + } + break; + } + o--; + } + if (!didAppendCatch) + wrapper.Append ('}'); + break; + } + } + if (currentMember == null && lastBracket == ']') { + // attribute context + wrapper.Append ("class GenAttr {}"); + } else { + if (!didAppendSemicolon) + wrapper.Append (';'); + } + } + + protected CompilationUnit ParseStub (string continuation, bool appendSemicolon = true) + { + var mt = GetMemberTextToCaret (); + if (mt == null) + return null; + + string memberText = mt.Item1; + bool wrapInClass = mt.Item2; + + var wrapper = new StringBuilder (); + if (wrapInClass) { + wrapper.Append ("class Stub {"); + wrapper.AppendLine (); + } + + wrapper.Append (memberText); + wrapper.Append (continuation); + AppendMissingClosingBrackets (wrapper, memberText, appendSemicolon); + + if (wrapInClass) + wrapper.Append ('}'); + + TextLocation memberLocation; + if (currentMember != null) { + memberLocation = currentMember.Region.Begin; + } else if (currentType != null) { + memberLocation = currentType.Region.Begin; + } else { + memberLocation = new TextLocation (1, 1); + } + + using (var stream = new System.IO.StringReader (wrapper.ToString ())) { + var parser = new CSharpParser (); + return parser.Parse (stream, wrapInClass ? memberLocation.Line - 2 : 0); + } + } + + string cachedText = null; + + protected virtual void Reset () + { + cachedText = null; + } + + protected Tuple<string, bool> GetMemberTextToCaret () + { + int startOffset; + if (currentMember != null) { + startOffset = document.GetOffset (currentMember.Region.BeginLine, currentMember.Region.BeginColumn); + } else if (currentType != null) { + startOffset = document.GetOffset (currentType.Region.BeginLine, currentType.Region.BeginColumn); + } else { + startOffset = 0; + } + if (cachedText == null) + cachedText = document.GetText (startOffset, offset - startOffset); + + return Tuple.Create (cachedText, startOffset != 0); + } + + protected Tuple<CSharpParsedFile, AstNode, CompilationUnit> GetInvocationBeforeCursor (bool afterBracket) + { + CompilationUnit baseUnit; + if (currentMember == null) { + baseUnit = ParseStub ("", false); + var section = baseUnit.GetNodeAt<AttributeSection> (location.Line, location.Column - 2); + var attr = section != null ? section.Attributes.LastOrDefault () : null; + if (attr != null) { + // insert target type into compilation unit, to respect the + attr.Remove (); + var node = Unit.GetNodeAt (location) ?? Unit; + node.AddChild (attr, AttributeSection.AttributeRole); + return Tuple.Create (CSharpParsedFile, (AstNode)attr, Unit); + } + } + + if (currentMember == null && currentType == null) { + return null; + } + baseUnit = ParseStub (afterBracket ? "" : "x"); + + var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin; + var mref = baseUnit.GetNodeAt (location.Line, location.Column - 1, n => n is InvocationExpression || n is ObjectCreateExpression); + AstNode expr; + if (mref is InvocationExpression) { + expr = ((InvocationExpression)mref).Target; + } else if (mref is ObjectCreateExpression) { + expr = mref; + } else { + return null; + } + + /* var member = Unit.GetNodeAt<AttributedNode> (memberLocation); + var member2 = baseUnit.GetNodeAt<AttributedNode> (memberLocation); + member2.Remove (); + member.ReplaceWith (member2); + var tsvisitor = new TypeSystemConvertVisitor (ProjectContent, CSharpParsedFile.FileName); + baseUnit.AcceptVisitor (tsvisitor, null);*/ + return Tuple.Create (CSharpParsedFile, (AstNode)expr, baseUnit); + + /* + + /////// + if (currentMember == null && currentType == null) + return null; + + CSharpParser parser = new CSharpParser (); + int startOffset; + if (currentMember != null) { + startOffset = document.Editor.LocationToOffset (currentMember.Region.BeginLine, currentMember.Region.BeginColumn); + } else { + startOffset = document.Editor.LocationToOffset (currentType.Region.BeginLine, currentType.Region.BeginColumn); + } + string memberText = Document.Editor.GetTextBetween (startOffset, Document.Editor.Caret.Offset - 1); + + var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin; + StringBuilder wrapper = new StringBuilder (); + wrapper.Append ("class Stub {"); + wrapper.AppendLine (); + wrapper.Append (memberText); + + if (afterBracket) { + wrapper.Append ("();"); + } else { + wrapper.Append ("x);"); + } + + wrapper.Append (" SomeCall (); } } }"); + var stream = new System.IO.StringReader (wrapper.ToString ()); + var baseUnit = parser.Parse (stream, memberLocation.Line - 2); + stream.Close (); + var expr = baseUnit.GetNodeAt<Expression> (document.Editor.Caret.Line, document.Editor.Caret.Column); + if (expr is InvocationExpression) { + expr = ((InvocationExpression)expr).Target; + } + if (expr == null) + return null; + var member = Unit.GetNodeAt<AttributedNode> (memberLocation); + var member2 = baseUnit.GetNodeAt<AttributedNode> (memberLocation); + member2.Remove (); + member.ReplaceWith (member2); + + var tsvisitor = new TypeSystemConvertVisitor (ProjectContext, Document.FileName); + Unit.AcceptVisitor (tsvisitor, null); + return Tuple.Create (tsvisitor.ParsedFile, expr, Unit);*/ + } + + protected Tuple<ResolveResult, CSharpResolver> ResolveExpression (CSharpParsedFile file, AstNode expr, CompilationUnit unit) + { + if (expr == null) + return null; + AstNode resolveNode; + if (expr is Expression || expr is AstType) { + resolveNode = expr; + } else if (expr is VariableDeclarationStatement) { + resolveNode = ((VariableDeclarationStatement)expr).Type; + } else { + resolveNode = expr; + } + + var csResolver = new CSharpResolver (ctx, System.Threading.CancellationToken.None); + var navigator = new NodeListResolveVisitorNavigator (new[] { resolveNode }); + var visitor = new ResolveVisitor (csResolver, file, navigator); + visitor.Scan (unit); +// Print (unit); + var state = visitor.GetResolverStateBefore (resolveNode); + var result = visitor.GetResolveResult (resolveNode); + return Tuple.Create (result, state); + } + + protected static void Print (AstNode node) + { + var v = new CSharpOutputVisitor (Console.Out, new CSharpFormattingOptions ()); + node.AcceptVisitor (v, null); + } + + #endregion + } }
\ No newline at end of file diff --git a/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs b/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs index c946dba60b..6aaa6716ea 100644 --- a/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs +++ b/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs @@ -1,201 +1,201 @@ -//
-// CSharpParameterCompletionEngine.cs
-//
-// Author:
-// Mike Krüger <mkrueger@xamarin.com>
-//
-// Copyright (c) 2011 Xamarin Inc. (http://xamarin.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-using System;
-using ICSharpCode.NRefactory.Editor;
-using ICSharpCode.NRefactory.Completion;
-using System.Collections.Generic;
-using ICSharpCode.NRefactory.Semantics;
-using ICSharpCode.NRefactory.TypeSystem;
-using ICSharpCode.NRefactory.CSharp.Resolver;
-
-namespace ICSharpCode.NRefactory.CSharp.Completion
-{
- public class CSharpParameterCompletionEngine : CSharpCompletionEngineBase
- {
- internal IParameterCompletionDataFactory factory;
-
- public CSharpParameterCompletionEngine (IDocument document, IParameterCompletionDataFactory factory)
- {
- this.document = document;
- this.factory = factory;
- }
-
- public Tuple<CSharpParsedFile, AstNode, CompilationUnit> GetIndexerBeforeCursor ()
- {
- CompilationUnit baseUnit;
- if (currentMember == null && currentType == null)
- return null;
- baseUnit = ParseStub ("x] = a[1");
-
- var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
- var mref = baseUnit.GetNodeAt (location, n => n is IndexerExpression);
- Print (baseUnit);
- AstNode expr;
- if (mref is IndexerExpression) {
- expr = ((IndexerExpression)mref).Target;
- } else {
- return null;
- }
-
- var member = Unit.GetNodeAt<AttributedNode> (memberLocation);
- var member2 = baseUnit.GetNodeAt<AttributedNode> (memberLocation);
- member2.Remove ();
- member.ReplaceWith (member2);
- var tsvisitor = new TypeSystemConvertVisitor (ProjectContent, CSharpParsedFile.FileName);
- Unit.AcceptVisitor (tsvisitor, null);
- return Tuple.Create (tsvisitor.ParsedFile, (AstNode)expr, Unit);
- }
-
- public IParameterDataProvider GetParameterDataProvider (int offset)
- {
- if (offset <= 0)
- return null;
- SetOffset (offset);
- char completionChar = document.GetCharAt (offset - 1);
- if (completionChar != '(' && completionChar != '<' && completionChar != '[')
- return null;
- if (IsInsideCommentOrString ())
- return null;
-
- var invoke = GetInvocationBeforeCursor (true) ?? GetIndexerBeforeCursor ();
- if (invoke == null)
- return null;
-
- ResolveResult resolveResult;
- switch (completionChar) {
- case '(':
- if (invoke.Item2 is ObjectCreateExpression) {
- var createType = ResolveExpression (invoke.Item1, ((ObjectCreateExpression)invoke.Item2).Type, invoke.Item3);
- return factory.CreateConstructorProvider (createType.Item1.Type);
- }
-
- if (invoke.Item2 is ICSharpCode.NRefactory.CSharp.Attribute) {
- var attribute = ResolveExpression (invoke.Item1, invoke.Item2, invoke.Item3);
- if (attribute == null || attribute.Item1 == null)
- return null;
- return factory.CreateConstructorProvider (attribute.Item1.Type);
- }
-
- var invocationExpression = ResolveExpression (invoke.Item1, invoke.Item2, invoke.Item3);
-
- if (invocationExpression == null || invocationExpression.Item1 == null || invocationExpression.Item1.IsError)
- return null;
- resolveResult = invocationExpression.Item1;
- if (resolveResult is MethodGroupResolveResult)
- return factory.CreateMethodDataProvider (resolveResult as MethodGroupResolveResult);
- if (resolveResult is MemberResolveResult) {
- if (resolveResult.Type.Kind == TypeKind.Delegate)
- return factory.CreateDelegateDataProvider (resolveResult.Type);
- var mr = resolveResult as MemberResolveResult;
- if (mr.Member is IMethod)
- return factory.CreateMethodDataProvider ((IMethod)mr.Member);
- }
-
-//
-// if (result.ExpressionContext == ExpressionContext.BaseConstructorCall) {
-// if (resolveResult is ThisResolveResult)
-// return new NRefactoryParameterDataProvider (textEditorData, resolver, resolveResult as ThisResolveResult);
-// if (resolveResult is BaseResolveResult)
-// return new NRefactoryParameterDataProvider (textEditorData, resolver, resolveResult as BaseResolveResult);
-// }
-// IType resolvedType = resolver.SearchType (resolveResult.ResolvedType);
-// if (resolvedType != null && resolvedType.ClassType == ClassType.Delegate) {
-// return new NRefactoryParameterDataProvider (textEditorData, result.Expression, resolvedType);
-// }
- break;
-
-// case '<':
-// if (string.IsNullOrEmpty (result.Expression))
-// return null;
-// return new NRefactoryTemplateParameterDataProvider (textEditorData, resolver, GetUsedNamespaces (), result, new TextLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
-
- case '[':
- var indexerExpression = ResolveExpression (invoke.Item1, invoke.Item2, invoke.Item3);
- if (indexerExpression == null || indexerExpression.Item1 == null || indexerExpression.Item1.IsError)
- return null;
-
- return factory.CreateIndexerParameterDataProvider (indexerExpression.Item1.Type, invoke.Item2);
- }
- return null;
- }
-
- List<string> GetUsedNamespaces ()
- {
- var scope = CSharpParsedFile.GetUsingScope (location);
- var result = new List<string> ();
- while (scope != null) {
- result.Add (scope.NamespaceName);
- foreach (var u in scope.Usings) {
- var ns = u.ResolveNamespace (ctx);
- if (ns == null)
- continue;
- result.Add (ns.NamespaceName);
- }
- scope = scope.Parent;
- }
- return result;
- }
- /*
- public override bool GetParameterCompletionCommandOffset (out int cpos)
- {
- // Start calculating the parameter offset from the beginning of the
- // current member, instead of the beginning of the file.
- cpos = textEditorData.Caret.Offset - 1;
- var parsedDocument = Document.ParsedDocument;
- if (parsedDocument == null)
- return false;
- IMember mem = currentMember;
- if (mem == null || (mem is IType))
- return false;
- int startPos = textEditorData.LocationToOffset (mem.Region.BeginLine, mem.Region.BeginColumn);
- int parenDepth = 0;
- int chevronDepth = 0;
- while (cpos > startPos) {
- char c = textEditorData.GetCharAt (cpos);
- if (c == ')')
- parenDepth++;
- if (c == '>')
- chevronDepth++;
- if (parenDepth == 0 && c == '(' || chevronDepth == 0 && c == '<') {
- int p = MethodParameterDataProvider.GetCurrentParameterIndex (CompletionWidget, cpos + 1, startPos);
- if (p != -1) {
- cpos++;
- return true;
- } else {
- return false;
- }
- }
- if (c == '(')
- parenDepth--;
- if (c == '<')
- chevronDepth--;
- cpos--;
- }
- return false;
- }*/
- }
-}
-
+// +// CSharpParameterCompletionEngine.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// Copyright (c) 2011 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using ICSharpCode.NRefactory.Editor; +using ICSharpCode.NRefactory.Completion; +using System.Collections.Generic; +using ICSharpCode.NRefactory.Semantics; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.CSharp.Resolver; + +namespace ICSharpCode.NRefactory.CSharp.Completion +{ + public class CSharpParameterCompletionEngine : CSharpCompletionEngineBase + { + internal IParameterCompletionDataFactory factory; + + public CSharpParameterCompletionEngine (IDocument document, IParameterCompletionDataFactory factory) + { + this.document = document; + this.factory = factory; + } + + public Tuple<CSharpParsedFile, AstNode, CompilationUnit> GetIndexerBeforeCursor () + { + CompilationUnit baseUnit; + if (currentMember == null && currentType == null) + return null; + baseUnit = ParseStub ("x] = a[1"); + + var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin; + var mref = baseUnit.GetNodeAt (location, n => n is IndexerExpression); + Print (baseUnit); + AstNode expr; + if (mref is IndexerExpression) { + expr = ((IndexerExpression)mref).Target; + } else { + return null; + } + + var member = Unit.GetNodeAt<AttributedNode> (memberLocation); + var member2 = baseUnit.GetNodeAt<AttributedNode> (memberLocation); + member2.Remove (); + member.ReplaceWith (member2); + var tsvisitor = new TypeSystemConvertVisitor (ProjectContent, CSharpParsedFile.FileName); + Unit.AcceptVisitor (tsvisitor, null); + return Tuple.Create (tsvisitor.ParsedFile, (AstNode)expr, Unit); + } + + public IParameterDataProvider GetParameterDataProvider (int offset) + { + if (offset <= 0) + return null; + SetOffset (offset); + char completionChar = document.GetCharAt (offset - 1); + if (completionChar != '(' && completionChar != '<' && completionChar != '[') + return null; + if (IsInsideCommentOrString ()) + return null; + + var invoke = GetInvocationBeforeCursor (true) ?? GetIndexerBeforeCursor (); + if (invoke == null) + return null; + + ResolveResult resolveResult; + switch (completionChar) { + case '(': + if (invoke.Item2 is ObjectCreateExpression) { + var createType = ResolveExpression (invoke.Item1, ((ObjectCreateExpression)invoke.Item2).Type, invoke.Item3); + return factory.CreateConstructorProvider (createType.Item1.Type); + } + + if (invoke.Item2 is ICSharpCode.NRefactory.CSharp.Attribute) { + var attribute = ResolveExpression (invoke.Item1, invoke.Item2, invoke.Item3); + if (attribute == null || attribute.Item1 == null) + return null; + return factory.CreateConstructorProvider (attribute.Item1.Type); + } + + var invocationExpression = ResolveExpression (invoke.Item1, invoke.Item2, invoke.Item3); + + if (invocationExpression == null || invocationExpression.Item1 == null || invocationExpression.Item1.IsError) + return null; + resolveResult = invocationExpression.Item1; + if (resolveResult is MethodGroupResolveResult) + return factory.CreateMethodDataProvider (resolveResult as MethodGroupResolveResult); + if (resolveResult is MemberResolveResult) { + if (resolveResult.Type.Kind == TypeKind.Delegate) + return factory.CreateDelegateDataProvider (resolveResult.Type); + var mr = resolveResult as MemberResolveResult; + if (mr.Member is IMethod) + return factory.CreateMethodDataProvider ((IMethod)mr.Member); + } + +// +// if (result.ExpressionContext == ExpressionContext.BaseConstructorCall) { +// if (resolveResult is ThisResolveResult) +// return new NRefactoryParameterDataProvider (textEditorData, resolver, resolveResult as ThisResolveResult); +// if (resolveResult is BaseResolveResult) +// return new NRefactoryParameterDataProvider (textEditorData, resolver, resolveResult as BaseResolveResult); +// } +// IType resolvedType = resolver.SearchType (resolveResult.ResolvedType); +// if (resolvedType != null && resolvedType.ClassType == ClassType.Delegate) { +// return new NRefactoryParameterDataProvider (textEditorData, result.Expression, resolvedType); +// } + break; + +// case '<': +// if (string.IsNullOrEmpty (result.Expression)) +// return null; +// return new NRefactoryTemplateParameterDataProvider (textEditorData, resolver, GetUsedNamespaces (), result, new TextLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset)); + + case '[': + var indexerExpression = ResolveExpression (invoke.Item1, invoke.Item2, invoke.Item3); + if (indexerExpression == null || indexerExpression.Item1 == null || indexerExpression.Item1.IsError) + return null; + + return factory.CreateIndexerParameterDataProvider (indexerExpression.Item1.Type, invoke.Item2); + } + return null; + } + + List<string> GetUsedNamespaces () + { + var scope = CSharpParsedFile.GetUsingScope (location); + var result = new List<string> (); + while (scope != null) { + result.Add (scope.NamespaceName); + foreach (var u in scope.Usings) { + var ns = u.ResolveNamespace (ctx); + if (ns == null) + continue; + result.Add (ns.NamespaceName); + } + scope = scope.Parent; + } + return result; + } + /* + public override bool GetParameterCompletionCommandOffset (out int cpos) + { + // Start calculating the parameter offset from the beginning of the + // current member, instead of the beginning of the file. + cpos = textEditorData.Caret.Offset - 1; + var parsedDocument = Document.ParsedDocument; + if (parsedDocument == null) + return false; + IMember mem = currentMember; + if (mem == null || (mem is IType)) + return false; + int startPos = textEditorData.LocationToOffset (mem.Region.BeginLine, mem.Region.BeginColumn); + int parenDepth = 0; + int chevronDepth = 0; + while (cpos > startPos) { + char c = textEditorData.GetCharAt (cpos); + if (c == ')') + parenDepth++; + if (c == '>') + chevronDepth++; + if (parenDepth == 0 && c == '(' || chevronDepth == 0 && c == '<') { + int p = MethodParameterDataProvider.GetCurrentParameterIndex (CompletionWidget, cpos + 1, startPos); + if (p != -1) { + cpos++; + return true; + } else { + return false; + } + } + if (c == '(') + parenDepth--; + if (c == '<') + chevronDepth--; + cpos--; + } + return false; + }*/ + } +} + diff --git a/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/IParameterCompletionDataFactory.cs b/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/IParameterCompletionDataFactory.cs index 48d8c5a308..56321bdb18 100644 --- a/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/IParameterCompletionDataFactory.cs +++ b/main/contrib/ICSharpCode.NRefactory.CSharp/Completion/IParameterCompletionDataFactory.cs @@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion IParameterDataProvider CreateMethodDataProvider (IMethod method); IParameterDataProvider CreateDelegateDataProvider (IType type); - + IParameterDataProvider CreateIndexerParameterDataProvider (IType type, AstNode resolvedNode); } diff --git a/main/contrib/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs b/main/contrib/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs index 8e5cd77ffd..0e562e3e7b 100644 --- a/main/contrib/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs +++ b/main/contrib/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs @@ -1462,10 +1462,9 @@ namespace ICSharpCode.NRefactory.CSharp var result = new ExpressionStatement (); if (statementExpression.Expression == null) return result; - object expr = statementExpression.Expression.Accept (this); - if (expr != null) { - result.AddChild ((Expression)expr, ExpressionStatement.Roles.Expression); - } + var expr = statementExpression.Expression.Accept (this) as Expression; + if (expr != null) + result.AddChild (expr, ExpressionStatement.Roles.Expression); var location = LocationsBag.GetLocations (statementExpression); if (location != null) result.AddChild (new CSharpTokenNode (Convert (location[0]), 1), ExpressionStatement.Roles.Semicolon); diff --git a/main/contrib/ICSharpCode.NRefactory.CSharp/Parser/TypeSystemConvertVisitor.cs b/main/contrib/ICSharpCode.NRefactory.CSharp/Parser/TypeSystemConvertVisitor.cs index 1eac3f9091..8e03c367d2 100644 --- a/main/contrib/ICSharpCode.NRefactory.CSharp/Parser/TypeSystemConvertVisitor.cs +++ b/main/contrib/ICSharpCode.NRefactory.CSharp/Parser/TypeSystemConvertVisitor.cs @@ -710,6 +710,9 @@ namespace ICSharpCode.NRefactory.CSharp m.IsShadowing = (modifiers & Modifiers.New) != 0; m.IsStatic = (modifiers & Modifiers.Static) != 0; m.IsVirtual = (modifiers & Modifiers.Virtual) != 0; + m.IsPartial = (modifiers & Modifiers.Partial) != 0; + + } static Accessibility? GetAccessibility(Modifiers modifiers) diff --git a/main/contrib/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-tokenizer.cs b/main/contrib/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-tokenizer.cs index f22e56b43b..8bd8303982 100644 --- a/main/contrib/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-tokenizer.cs +++ b/main/contrib/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-tokenizer.cs @@ -3239,16 +3239,16 @@ namespace Mono.CSharp bool docAppend = false; if (doc_processing && peek_char () == '*') { int ch = get_char (); - if (position_stack.Count == 0) - sbag.PushCommentChar (ch); // But when it is /**/, just do nothing. if (peek_char () == '/') { ch = get_char (); if (position_stack.Count == 0) { - sbag.PushCommentChar (ch); sbag.EndComment (line, col + 1); } continue; + } else { + if (position_stack.Count == 0) + sbag.PushCommentChar (ch); } if (doc_state == XmlCommentState.Allowed) docAppend = true; @@ -3264,16 +3264,15 @@ namespace Mono.CSharp } while ((d = get_char ()) != -1){ - if (position_stack.Count == 0) - sbag.PushCommentChar (d); if (d == '*' && peek_char () == '/'){ - if (position_stack.Count == 0) - sbag.PushCommentChar ('/'); get_char (); if (position_stack.Count == 0) sbag.EndComment (line, col + 1); comments_seen = true; break; + } else { + if (position_stack.Count == 0) + sbag.PushCommentChar (d); } if (docAppend) xml_comment_buffer.Append ((char) d); diff --git a/main/contrib/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs b/main/contrib/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs index 4b8b067770..8b68564132 100644 --- a/main/contrib/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs +++ b/main/contrib/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs @@ -483,6 +483,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver get { return false; } } + bool IMember.IsPartial { + get { return false; } + } + EntityType IEntity.EntityType { get { return EntityType.Operator; } } diff --git a/main/contrib/ICSharpCode.NRefactory/TypeSystem/IMember.cs b/main/contrib/ICSharpCode.NRefactory/TypeSystem/IMember.cs index 6674e02d23..99ad30e552 100644 --- a/main/contrib/ICSharpCode.NRefactory/TypeSystem/IMember.cs +++ b/main/contrib/ICSharpCode.NRefactory/TypeSystem/IMember.cs @@ -73,6 +73,13 @@ namespace ICSharpCode.NRefactory.TypeSystem bool IsOverridable { get; } + + /// <summary> + /// Gets if the member is partial. Returns true when the member is "partial". + /// </summary> + bool IsPartial { + get; + } } #if WITH_CONTRACTS diff --git a/main/contrib/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs b/main/contrib/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs index 0c4c69f7a1..a3fb7316c9 100644 --- a/main/contrib/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs +++ b/main/contrib/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs @@ -53,6 +53,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation const ushort FlagVirtual = 0x0010; const ushort FlagOverride = 0x0020; const ushort FlagStatic = 0x0040; + const ushort FlagPartial = 0x0080; + // Flags of form 0xY000 are reserved for use in derived classes (DefaultMethod etc.) protected override void FreezeInternal() @@ -144,6 +146,15 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } } + public bool IsPartial { + get { return flags[FlagPartial]; } + set { + CheckBeforeMutation(); + flags[FlagPartial] = value; + } + } + + public bool IsOverridable { get { return (IsAbstract || IsVirtual || IsOverride) && !IsSealed; diff --git a/main/contrib/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs b/main/contrib/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs index cc9c88c0f4..2a9616ab40 100644 --- a/main/contrib/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs +++ b/main/contrib/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs @@ -166,6 +166,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation get { return memberDefinition.IsProtectedAndInternal; } } + public bool IsPartial { + get { return memberDefinition.IsPartial; } + } + public IProjectContent ProjectContent { get { return memberDefinition.ProjectContent; } } |