236 lines
6.3 KiB
C#
236 lines
6.3 KiB
C#
//
|
|
// 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<string> results, string prefix, IEnumerable<string> 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<string> ();
|
|
|
|
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<string> ();
|
|
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<string> ();
|
|
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]);
|
|
}
|
|
}
|
|
|
|
}
|