2010-01-20 Zoltan Varga <vargaz@gmail.com>
[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 //
11 // Completion* classes derive from ExpressionStatement as this allows
12 // them to pass through the parser in many conditions that require
13 // statements even when the expression is incomplete (for example
14 // completing inside a lambda
15 //
16 namespace Mono.CSharp {
17         using System;
18         using System.Collections.Generic;
19         using System.Reflection;
20         using System.Reflection.Emit;
21         using System.Text;
22
23         //
24         // A common base class for Completing expressions, it
25         // is just a very simple ExpressionStatement
26         //
27         public abstract class CompletingExpression : ExpressionStatement {
28                 public override void EmitStatement (EmitContext ec)
29                 {
30                         // Do nothing
31                 }
32
33                 public override void Emit (EmitContext ec)
34                 {
35                         // Do nothing
36                 }
37
38                 public override Expression CreateExpressionTree (ResolveContext ec)
39                 {
40                         return null;
41                 }
42         }
43         
44         public class CompletionSimpleName : CompletingExpression {
45                 public string Prefix;
46                 
47                 public CompletionSimpleName (string prefix, Location l)
48                 {
49                         this.loc = l;
50                         this.Prefix = prefix;
51                 }
52
53                 public static void AppendResults (List<string> results, string prefix, IEnumerable<string> names)
54                 {
55                         foreach (string name in names){
56                                 if (name == null || prefix == null)
57                                         continue;
58
59                                 if (!name.StartsWith (prefix))
60                                         continue;
61
62                                 if (results.Contains (name))
63                                         continue;
64
65                                 if (prefix != null)
66                                         results.Add (name.Substring (prefix.Length));
67                                 else
68                                         results.Add (name);
69                         }
70
71                 }
72                 
73                 protected override Expression DoResolve (ResolveContext ec)
74                 {
75                         var results = new List<string> ();
76
77                         AppendResults (results, Prefix, Evaluator.GetVarNames ());
78                         AppendResults (results, Prefix, ec.CurrentTypeDefinition.NamespaceEntry.CompletionGetTypesStartingWith (Prefix));
79                         AppendResults (results, Prefix, Evaluator.GetUsingList ());
80                         
81                         throw new CompletionResult (Prefix, results.ToArray ());
82                 }
83
84                 protected override void CloneTo (CloneContext clonectx, Expression t)
85                 {
86                         // Nothing
87                 }
88         }
89         
90         public class CompletionMemberAccess : CompletingExpression {
91                 Expression expr;
92                 string partial_name;
93                 TypeArguments targs;
94
95                 internal static MemberFilter CollectingFilter = new MemberFilter (Match);
96
97                 static bool Match (MemberInfo m, object filter_criteria)
98                 {
99                         if (m is FieldInfo){
100                                 if (((FieldInfo) m).IsSpecialName)
101                                         return false;
102                                 
103                         }
104                         if (m is MethodInfo){
105                                 if (((MethodInfo) m).IsSpecialName)
106                                         return false;
107                         }
108
109                         if (filter_criteria == null)
110                                 return true;
111                         
112                         string n = (string) filter_criteria;
113                         if (m.Name.StartsWith (n))
114                                 return true;
115                         
116                         return false;
117                 }
118                 
119                 public CompletionMemberAccess (Expression e, string partial_name, Location l)
120                 {
121                         this.expr = e;
122                         this.loc = l;
123                         this.partial_name = partial_name;
124                 }
125
126                 public CompletionMemberAccess (Expression e, string partial_name, TypeArguments targs, Location l)
127                 {
128                         this.expr = e;
129                         this.loc = l;
130                         this.partial_name = partial_name;
131                         this.targs = targs;
132                 }
133                 
134                 protected override Expression DoResolve (ResolveContext ec)
135                 {
136                         Expression expr_resolved = expr.Resolve (ec,
137                                 ResolveFlags.VariableOrValue | ResolveFlags.Type |
138                                 ResolveFlags.Intermediate);
139
140                         if (expr_resolved == null)
141                                 return null;
142
143                         Type expr_type = expr_resolved.Type;
144                         if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_type == TypeManager.null_type || expr_type == InternalType.AnonymousMethod) {
145                                 Unary.Error_OperatorCannotBeApplied (ec, loc, ".", expr_type);
146                                 return null;
147                         }
148
149                         if (targs != null) {
150                                 if (!targs.Resolve (ec))
151                                         return null;
152                         }
153
154                         var results = new List<string> ();
155                         if (expr_resolved is Namespace){
156                                 Namespace nexpr = expr_resolved as Namespace;
157                                 string namespaced_partial;
158
159                                 if (partial_name == null)
160                                         namespaced_partial = nexpr.Name;
161                                 else
162                                         namespaced_partial = nexpr.Name + "." + partial_name;
163
164 #if false
165                                 Console.WriteLine ("Workign with: namespaced partial {0}", namespaced_partial);
166                                 foreach (var x in ec.TypeContainer.NamespaceEntry.CompletionGetTypesStartingWith (ec.TypeContainer, namespaced_partial)){
167                                         Console.WriteLine ("    {0}", x);
168                                 }
169 #endif
170
171                                 CompletionSimpleName.AppendResults (
172                                         results,
173                                         partial_name, 
174                                         ec.CurrentTypeDefinition.NamespaceEntry.CompletionGetTypesStartingWith (namespaced_partial));
175                         } else {
176                                 MemberInfo [] result = expr_type.FindMembers (
177                                         MemberTypes.All, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public,
178                                         CollectingFilter, partial_name);
179
180                                 foreach (MemberInfo r in result){
181                                         string name;
182                                         
183                                         MethodBase rasb = r as MethodBase;
184                                         if (rasb != null && rasb.IsSpecialName)
185                                                 continue;
186                                         
187                                         if (partial_name == null)
188                                                 name = r.Name;
189                                         else 
190                                                 name = r.Name.Substring (partial_name.Length);
191                                         
192                                         if (results.Contains (name))
193                                                 continue;
194                                         results.Add (name);
195                                 }
196                         }
197
198                         throw new CompletionResult (partial_name == null ? "" : partial_name, results.ToArray ());
199                 }
200
201                 protected override void CloneTo (CloneContext clonectx, Expression t)
202                 {
203                         CompletionMemberAccess target = (CompletionMemberAccess) t;
204
205                         if (targs != null)
206                                 target.targs = targs.Clone ();
207
208                         target.expr = expr.Clone (clonectx);
209                 }
210         }
211
212         public class CompletionElementInitializer : CompletingExpression {
213                 string partial_name;
214                 
215                 public CompletionElementInitializer (string partial_name, Location l)
216                 {
217                         this.partial_name = partial_name;
218                         this.loc = l;
219                 }
220                 
221                 protected override Expression DoResolve (ResolveContext ec)
222                 {
223                         MemberList members = TypeManager.FindMembers (
224                                 ec.CurrentInitializerVariable.Type,
225                                 MemberTypes.Field | MemberTypes.Property,
226                                 BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public,
227                                 CompletionMemberAccess.CollectingFilter, partial_name);
228
229                         string [] result = new string [members.Count];
230                         int i = 0;
231                         foreach (MemberInfo mi in members){
232                                 string name;
233                                 
234                                 if (partial_name == null)
235                                         name = mi.Name;
236                                 else
237                                         name = mi.Name.Substring (partial_name.Length);
238                                 
239                                 result [i++] = name;
240                         }
241
242                         if (partial_name != null && i > 0 && result [0] == "")
243                                 throw new CompletionResult ("", new string [] { "=" });
244                         
245                         throw new CompletionResult (partial_name == null ? "" : partial_name, result);
246                 }
247
248                 protected override void CloneTo (CloneContext clonectx, Expression t)
249                 {
250                         // Nothing
251                 }
252         }
253 }