// // complete.cs: Expression that are used for completion suggestions. // // Author: // Miguel de Icaza (miguel@ximian.com) // Marek Safar (marek.safar@gmail.com) // // Copyright 2001, 2002, 2003 Ximian, Inc. // Copyright 2003-2009 Novell, Inc. // Copyright 2011 Xamarin Inc // // Completion* classes derive from ExpressionStatement as this allows // them to pass through the parser in many conditions that require // statements even when the expression is incomplete (for example // completing inside a lambda // using System.Collections.Generic; using System.Linq; namespace Mono.CSharp { // // A common base class for Completing expressions, it // is just a very simple ExpressionStatement // public abstract class CompletingExpression : ExpressionStatement { public static void AppendResults (List results, string prefix, IEnumerable names) { foreach (string name in names) { if (name == null) continue; if (prefix != null && !name.StartsWith (prefix)) continue; if (results.Contains (name)) continue; if (prefix != null) results.Add (name.Substring (prefix.Length)); else results.Add (name); } } public override bool ContainsEmitWithAwait () { return false; } public override Expression CreateExpressionTree (ResolveContext ec) { return null; } public override void EmitStatement (EmitContext ec) { // Do nothing } public override void Emit (EmitContext ec) { // Do nothing } } public class CompletionSimpleName : CompletingExpression { public string Prefix; public CompletionSimpleName (string prefix, Location l) { this.loc = l; this.Prefix = prefix; } protected override Expression DoResolve (ResolveContext ec) { var results = new List (); ec.CurrentMemberDefinition.GetCompletionStartingWith (Prefix, results); throw new CompletionResult (Prefix, results.Distinct ().Select (l => l.Substring (Prefix.Length)).ToArray ()); } protected override void CloneTo (CloneContext clonectx, Expression t) { // Nothing } } public class CompletionMemberAccess : CompletingExpression { Expression expr; string partial_name; TypeArguments targs; public CompletionMemberAccess (Expression e, string partial_name, Location l) { this.expr = e; this.loc = l; this.partial_name = partial_name; } public CompletionMemberAccess (Expression e, string partial_name, TypeArguments targs, Location l) { this.expr = e; this.loc = l; this.partial_name = partial_name; this.targs = targs; } protected override Expression DoResolve (ResolveContext rc) { var sn = expr as SimpleName; const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type; if (sn != null) { var errors_printer = new SessionReportPrinter (); var old = rc.Report.SetPrinter (errors_printer); try { expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity); } finally { rc.Report.SetPrinter (old); } if (errors_printer.ErrorsCount != 0) return null; // // Resolve expression which does have type set as we need expression type // with disable flow analysis as we don't know whether left side expression // is used as variable or type // if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) { expr = expr.Resolve (rc); } else if (expr is TypeParameterExpr) { expr.Error_UnexpectedKind (rc, flags, sn.Location); expr = null; } } else { expr = expr.Resolve (rc, flags); } if (expr == null) return null; TypeSpec expr_type = expr.Type; if (expr_type.IsPointer || expr_type.Kind == MemberKind.Void || expr_type == InternalType.NullLiteral || expr_type == InternalType.AnonymousMethod) { expr.Error_OperatorCannotBeApplied (rc, loc, ".", expr_type); return null; } if (targs != null) { if (!targs.Resolve (rc, true)) return null; } var results = new List (); var nexpr = expr as NamespaceExpression; if (nexpr != null) { string namespaced_partial; if (partial_name == null) namespaced_partial = nexpr.Namespace.Name; else namespaced_partial = nexpr.Namespace.Name + "." + partial_name; rc.CurrentMemberDefinition.GetCompletionStartingWith (namespaced_partial, results); if (partial_name != null) results = results.Select (l => l.Substring (partial_name.Length)).ToList (); } else { var r = MemberCache.GetCompletitionMembers (rc, expr_type, partial_name).Select (l => l.Name); AppendResults (results, partial_name, r); } throw new CompletionResult (partial_name == null ? "" : partial_name, results.Distinct ().ToArray ()); } protected override void CloneTo (CloneContext clonectx, Expression t) { CompletionMemberAccess target = (CompletionMemberAccess) t; if (targs != null) target.targs = targs.Clone (); target.expr = expr.Clone (clonectx); } } public class CompletionElementInitializer : CompletingExpression { string partial_name; public CompletionElementInitializer (string partial_name, Location l) { this.partial_name = partial_name; this.loc = l; } protected override Expression DoResolve (ResolveContext ec) { var members = MemberCache.GetCompletitionMembers (ec, ec.CurrentInitializerVariable.Type, partial_name); // TODO: Does this mean exact match only ? // if (partial_name != null && results.Count > 0 && result [0] == "") // throw new CompletionResult ("", new string [] { "=" }); var results = members.Where (l => (l.Kind & (MemberKind.Field | MemberKind.Property)) != 0).Select (l => l.Name).ToList (); if (partial_name != null) { var temp = new List (); AppendResults (temp, partial_name, results); results = temp; } throw new CompletionResult (partial_name == null ? "" : partial_name, results.Distinct ().ToArray ()); } protected override void CloneTo (CloneContext clonectx, Expression t) { // Nothing } } public class EmptyCompletion : CompletingExpression { protected override void CloneTo (CloneContext clonectx, Expression target) { } protected override Expression DoResolve (ResolveContext rc) { throw new CompletionResult ("", new string [0]); } } }