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