Merge pull request #194 from QuickJack/master
[mono.git] / mcs / mcs / complete.cs
1 //
2 // complete.cs: Expression that are used for completion suggestions.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Marek Safar (marek.safar@gmail.com)
7 //
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2009 Novell, Inc.
10 // Copyright 2011 Xamarin Inc
11 //
12 // Completion* classes derive from ExpressionStatement as this allows
13 // them to pass through the parser in many conditions that require
14 // statements even when the expression is incomplete (for example
15 // completing inside a lambda
16 //
17 using System.Collections.Generic;
18 using System.Linq;
19
20 namespace Mono.CSharp {
21
22         //
23         // A common base class for Completing expressions, it
24         // is just a very simple ExpressionStatement
25         //
26         public abstract class CompletingExpression : ExpressionStatement
27         {
28                 public static void AppendResults (List<string> results, string prefix, IEnumerable<string> names)
29                 {
30                         foreach (string name in names) {
31                                 if (name == null)
32                                         continue;
33
34                                 if (prefix != null && !name.StartsWith (prefix))
35                                         continue;
36
37                                 if (results.Contains (name))
38                                         continue;
39
40                                 if (prefix != null)
41                                         results.Add (name.Substring (prefix.Length));
42                                 else
43                                         results.Add (name);
44                         }
45                 }
46
47                 public override bool ContainsEmitWithAwait ()
48                 {
49                         return false;
50                 }
51
52                 public override Expression CreateExpressionTree (ResolveContext ec)
53                 {
54                         return null;
55                 }
56
57                 public override void EmitStatement (EmitContext ec)
58                 {
59                         // Do nothing
60                 }
61
62                 public override void Emit (EmitContext ec)
63                 {
64                         // Do nothing
65                 }
66         }
67         
68         public class CompletionSimpleName : CompletingExpression {
69                 public string Prefix;
70                 
71                 public CompletionSimpleName (string prefix, Location l)
72                 {
73                         this.loc = l;
74                         this.Prefix = prefix;
75                 }
76                 
77                 protected override Expression DoResolve (ResolveContext ec)
78                 {
79                         var results = new List<string> ();
80
81                         AppendResults (results, Prefix, ec.Module.Evaluator.GetVarNames ());
82                         AppendResults (results, Prefix, ec.CurrentMemberDefinition.Parent.NamespaceEntry.CompletionGetTypesStartingWith (Prefix));
83                         AppendResults (results, Prefix, ec.Module.Evaluator.GetUsingList ());
84                         
85                         throw new CompletionResult (Prefix, results.ToArray ());
86                 }
87
88                 protected override void CloneTo (CloneContext clonectx, Expression t)
89                 {
90                         // Nothing
91                 }
92         }
93         
94         public class CompletionMemberAccess : CompletingExpression {
95                 Expression expr;
96                 string partial_name;
97                 TypeArguments targs;
98                 
99                 public CompletionMemberAccess (Expression e, string partial_name, Location l)
100                 {
101                         this.expr = e;
102                         this.loc = l;
103                         this.partial_name = partial_name;
104                 }
105
106                 public CompletionMemberAccess (Expression e, string partial_name, TypeArguments targs, Location l)
107                 {
108                         this.expr = e;
109                         this.loc = l;
110                         this.partial_name = partial_name;
111                         this.targs = targs;
112                 }
113                 
114                 protected override Expression DoResolve (ResolveContext ec)
115                 {
116                         Expression expr_resolved = expr.Resolve (ec,
117                                 ResolveFlags.VariableOrValue | ResolveFlags.Type);
118
119                         if (expr_resolved == null)
120                                 return null;
121
122                         TypeSpec expr_type = expr_resolved.Type;
123                         if (expr_type.IsPointer || expr_type.Kind == MemberKind.Void || expr_type == InternalType.NullLiteral || expr_type == InternalType.AnonymousMethod) {
124                                 expr_resolved.Error_OperatorCannotBeApplied (ec, loc, ".", expr_type);
125                                 return null;
126                         }
127
128                         if (targs != null) {
129                                 if (!targs.Resolve (ec))
130                                         return null;
131                         }
132
133                         var results = new List<string> ();
134                         if (expr_resolved is Namespace){
135                                 Namespace nexpr = expr_resolved as Namespace;
136                                 string namespaced_partial;
137
138                                 if (partial_name == null)
139                                         namespaced_partial = nexpr.Name;
140                                 else
141                                         namespaced_partial = nexpr.Name + "." + partial_name;
142
143 #if false
144                                 Console.WriteLine ("Workign with: namespaced partial {0}", namespaced_partial);
145                                 foreach (var x in ec.TypeContainer.NamespaceEntry.CompletionGetTypesStartingWith (ec.TypeContainer, namespaced_partial)){
146                                         Console.WriteLine ("    {0}", x);
147                                 }
148 #endif
149
150                                 CompletionSimpleName.AppendResults (
151                                         results,
152                                         partial_name, 
153                                         ec.CurrentMemberDefinition.Parent.NamespaceEntry.CompletionGetTypesStartingWith (namespaced_partial));
154                         } else {
155                                 var r = MemberCache.GetCompletitionMembers (ec, expr_type, partial_name).Select (l => l.Name);
156                                 AppendResults (results, partial_name, r);
157                         }
158
159                         throw new CompletionResult (partial_name == null ? "" : partial_name, results.Distinct ().ToArray ());
160                 }
161
162                 protected override void CloneTo (CloneContext clonectx, Expression t)
163                 {
164                         CompletionMemberAccess target = (CompletionMemberAccess) t;
165
166                         if (targs != null)
167                                 target.targs = targs.Clone ();
168
169                         target.expr = expr.Clone (clonectx);
170                 }
171         }
172
173         public class CompletionElementInitializer : CompletingExpression {
174                 string partial_name;
175                 
176                 public CompletionElementInitializer (string partial_name, Location l)
177                 {
178                         this.partial_name = partial_name;
179                         this.loc = l;
180                 }
181                 
182                 protected override Expression DoResolve (ResolveContext ec)
183                 {
184                         var members = MemberCache.GetCompletitionMembers (ec, ec.CurrentInitializerVariable.Type, partial_name);
185
186 // TODO: Does this mean exact match only ?
187 //                      if (partial_name != null && results.Count > 0 && result [0] == "")
188 //                              throw new CompletionResult ("", new string [] { "=" });
189
190                         var results = members.Where (l => (l.Kind & (MemberKind.Field | MemberKind.Property)) != 0).Select (l => l.Name).ToList ();
191                         if (partial_name != null) {
192                                 var temp = new List<string> ();
193                                 AppendResults (temp, partial_name, results);
194                                 results = temp;
195                         }
196
197                         throw new CompletionResult (partial_name == null ? "" : partial_name, results.Distinct ().ToArray ());
198                 }
199
200                 protected override void CloneTo (CloneContext clonectx, Expression t)
201                 {
202                         // Nothing
203                 }
204         }
205         
206 }