1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
|
//
// 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;
//
// Resolve the expression with flow analysis turned off, we'll do the definite
// assignment checks later. This is because we don't know yet what the expression
// will resolve to - it may resolve to a FieldExpr and in this case we must do the
// definite assignment check on the actual field and not on the whole struct.
//
using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
if (sn != null) {
expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
//
// 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) {
using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
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))
return null;
}
var results = new List<string> ();
if (expr is Namespace) {
Namespace nexpr = expr as Namespace;
string namespaced_partial;
if (partial_name == null)
namespaced_partial = nexpr.Name;
else
namespaced_partial = nexpr.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
}
}
}
|