2009-08-21 Marek Safar <marek.safar@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;
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 (ArrayList results, string prefix, IEnumerable names)
54                 {
55                         foreach (string name in names){
56                                 if (name == 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                 public override Expression DoResolve (ResolveContext ec)
74                 {
75                         ArrayList results = new ArrayList ();
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, (string []) results.ToArray (typeof (string)));
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                 public override Expression DoResolve (ResolveContext ec)
135                 {
136                         SimpleName original = expr as SimpleName;
137                         Expression expr_resolved = expr.Resolve (ec,
138                                 ResolveFlags.VariableOrValue | ResolveFlags.Type |
139                                 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
140
141                         if (expr_resolved == null)
142                                 return null;
143
144                         Type expr_type = expr_resolved.Type;
145                         if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_type == TypeManager.null_type || expr_type == InternalType.AnonymousMethod) {
146                                 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
147                                 return null;
148                         }
149
150                         if (targs != null) {
151                                 if (!targs.Resolve (ec))
152                                         return null;
153                         }
154
155                         ArrayList results = new ArrayList ();
156                         if (expr_resolved is Namespace){
157                                 Namespace nexpr = expr_resolved as Namespace;
158                                 string namespaced_partial;
159
160                                 if (partial_name == null)
161                                         namespaced_partial = nexpr.Name;
162                                 else
163                                         namespaced_partial = nexpr.Name + "." + partial_name;
164
165 #if false
166                                 Console.WriteLine ("Workign with: namespaced partial {0}", namespaced_partial);
167                                 foreach (var x in ec.TypeContainer.NamespaceEntry.CompletionGetTypesStartingWith (ec.TypeContainer, namespaced_partial)){
168                                         Console.WriteLine ("    {0}", x);
169                                 }
170 #endif
171
172                                 CompletionSimpleName.AppendResults (
173                                         results,
174                                         partial_name, 
175                                         ec.CurrentTypeDefinition.NamespaceEntry.CompletionGetTypesStartingWith (namespaced_partial));
176                         } else {
177                                 MemberInfo [] result = expr_type.FindMembers (
178                                         MemberTypes.All, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public,
179                                         CollectingFilter, partial_name);
180
181                                 foreach (MemberInfo r in result){
182                                         string name;
183                                         
184                                         MethodBase rasb = r as MethodBase;
185                                         if (rasb != null && rasb.IsSpecialName)
186                                                 continue;
187                                         
188                                         if (partial_name == null)
189                                                 name = r.Name;
190                                         else 
191                                                 name = r.Name.Substring (partial_name.Length);
192                                         
193                                         if (results.Contains (name))
194                                                 continue;
195                                         results.Add (name);
196                                 }
197                         }
198
199                         throw new CompletionResult (partial_name == null ? "" : partial_name, (string []) results.ToArray (typeof (string)));
200                 }
201
202                 protected override void CloneTo (CloneContext clonectx, Expression t)
203                 {
204                         CompletionMemberAccess target = (CompletionMemberAccess) t;
205
206                         if (targs != null)
207                                 target.targs = targs.Clone ();
208
209                         target.expr = expr.Clone (clonectx);
210                 }
211         }
212
213         public class CompletionElementInitializer : CompletingExpression {
214                 string partial_name;
215                 
216                 public CompletionElementInitializer (string partial_name, Location l)
217                 {
218                         this.partial_name = partial_name;
219                         this.loc = l;
220                 }
221                 
222                 public override Expression DoResolve (ResolveContext ec)
223                 {
224                         MemberList members = TypeManager.FindMembers (
225                                 ec.CurrentInitializerVariable.Type,
226                                 MemberTypes.Field | MemberTypes.Property,
227                                 BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public,
228                                 CompletionMemberAccess.CollectingFilter, partial_name);
229
230                         string [] result = new string [members.Count];
231                         int i = 0;
232                         foreach (MemberInfo mi in members){
233                                 string name;
234                                 
235                                 if (partial_name == null)
236                                         name = mi.Name;
237                                 else
238                                         name = mi.Name.Substring (partial_name.Length);
239                                 
240                                 result [i++] = name;
241                         }
242
243                         if (partial_name != null && i > 0 && result [0] == "")
244                                 throw new CompletionResult ("", new string [] { "=" });
245                         
246                         throw new CompletionResult (partial_name == null ? "" : partial_name, result);
247                 }
248
249                 protected override void CloneTo (CloneContext clonectx, Expression t)
250                 {
251                         // Nothing
252                 }
253         }
254 }