1 | // Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team |
---|
2 | // |
---|
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this |
---|
4 | // software and associated documentation files (the "Software"), to deal in the Software |
---|
5 | // without restriction, including without limitation the rights to use, copy, modify, merge, |
---|
6 | // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons |
---|
7 | // to whom the Software is furnished to do so, subject to the following conditions: |
---|
8 | // |
---|
9 | // The above copyright notice and this permission notice shall be included in all copies or |
---|
10 | // substantial portions of the Software. |
---|
11 | // |
---|
12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
---|
13 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
---|
14 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE |
---|
15 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
---|
16 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
---|
17 | // DEALINGS IN THE SOFTWARE. |
---|
18 | |
---|
19 | using System; |
---|
20 | using System.Collections.Generic; |
---|
21 | using System.Diagnostics; |
---|
22 | using System.Linq; |
---|
23 | using System.Text; |
---|
24 | using System.Threading; |
---|
25 | using ICSharpCode.NRefactory.CSharp.Analysis; |
---|
26 | using ICSharpCode.NRefactory.CSharp.TypeSystem; |
---|
27 | using ICSharpCode.NRefactory.Semantics; |
---|
28 | using ICSharpCode.NRefactory.TypeSystem; |
---|
29 | using ICSharpCode.NRefactory.TypeSystem.Implementation; |
---|
30 | |
---|
31 | namespace ICSharpCode.NRefactory.CSharp.Resolver |
---|
32 | { |
---|
33 | /// <summary> |
---|
34 | /// Traverses the DOM and resolves expressions. |
---|
35 | /// </summary> |
---|
36 | /// <remarks> |
---|
37 | /// The ResolveVisitor does two jobs at the same time: it tracks the resolve context (properties on CSharpResolver) |
---|
38 | /// and it resolves the expressions visited. |
---|
39 | /// To allow using the context tracking without having to resolve every expression in the file (e.g. when you want to resolve |
---|
40 | /// only a single node deep within the DOM), you can use the <see cref="IResolveVisitorNavigator"/> interface. |
---|
41 | /// The navigator allows you to switch the between scanning mode and resolving mode. |
---|
42 | /// In scanning mode, the context is tracked (local variables registered etc.), but nodes are not resolved. |
---|
43 | /// While scanning, the navigator will get asked about every node that the resolve visitor is about to enter. |
---|
44 | /// This allows the navigator whether to keep scanning, whether switch to resolving mode, or whether to completely skip the |
---|
45 | /// subtree rooted at that node. |
---|
46 | /// |
---|
47 | /// In resolving mode, the context is tracked and nodes will be resolved. |
---|
48 | /// The resolve visitor may decide that it needs to resolve other nodes as well in order to resolve the current node. |
---|
49 | /// In this case, those nodes will be resolved automatically, without asking the navigator interface. |
---|
50 | /// For child nodes that are not essential to resolving, the resolve visitor will switch back to scanning mode (and thus will |
---|
51 | /// ask the navigator for further instructions). |
---|
52 | /// |
---|
53 | /// Moreover, there is the <c>ResolveAll</c> mode - it works similar to resolving mode, but will not switch back to scanning mode. |
---|
54 | /// The whole subtree will be resolved without notifying the navigator. |
---|
55 | /// </remarks> |
---|
56 | sealed class ResolveVisitor : IAstVisitor<ResolveResult> |
---|
57 | { |
---|
58 | // The ResolveVisitor is also responsible for handling lambda expressions. |
---|
59 | |
---|
60 | static readonly ResolveResult errorResult = ErrorResolveResult.UnknownError; |
---|
61 | |
---|
62 | CSharpResolver resolver; |
---|
63 | /// <summary>Resolve result of the current LINQ query.</summary> |
---|
64 | /// <remarks>We do not have to put this into the stored state (resolver) because |
---|
65 | /// query expressions are always resolved in a single operation.</remarks> |
---|
66 | ResolveResult currentQueryResult; |
---|
67 | readonly CSharpUnresolvedFile unresolvedFile; |
---|
68 | readonly Dictionary<AstNode, ResolveResult> resolveResultCache = new Dictionary<AstNode, ResolveResult>(); |
---|
69 | readonly Dictionary<AstNode, CSharpResolver> resolverBeforeDict = new Dictionary<AstNode, CSharpResolver>(); |
---|
70 | readonly Dictionary<AstNode, CSharpResolver> resolverAfterDict = new Dictionary<AstNode, CSharpResolver>(); |
---|
71 | readonly Dictionary<Expression, ConversionWithTargetType> conversionDict = new Dictionary<Expression, ConversionWithTargetType>(); |
---|
72 | |
---|
73 | internal struct ConversionWithTargetType |
---|
74 | { |
---|
75 | public readonly Conversion Conversion; |
---|
76 | public readonly IType TargetType; |
---|
77 | |
---|
78 | public ConversionWithTargetType(Conversion conversion, IType targetType) |
---|
79 | { |
---|
80 | this.Conversion = conversion; |
---|
81 | this.TargetType = targetType; |
---|
82 | } |
---|
83 | } |
---|
84 | |
---|
85 | IResolveVisitorNavigator navigator; |
---|
86 | bool resolverEnabled; |
---|
87 | List<LambdaBase> undecidedLambdas; |
---|
88 | internal CancellationToken cancellationToken; |
---|
89 | |
---|
90 | #region Constructor |
---|
91 | static readonly IResolveVisitorNavigator skipAllNavigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Skip, null); |
---|
92 | |
---|
93 | /// <summary> |
---|
94 | /// Creates a new ResolveVisitor instance. |
---|
95 | /// </summary> |
---|
96 | public ResolveVisitor(CSharpResolver resolver, CSharpUnresolvedFile unresolvedFile) |
---|
97 | { |
---|
98 | if (resolver == null) |
---|
99 | throw new ArgumentNullException("resolver"); |
---|
100 | this.resolver = resolver; |
---|
101 | this.unresolvedFile = unresolvedFile; |
---|
102 | this.navigator = skipAllNavigator; |
---|
103 | } |
---|
104 | |
---|
105 | internal void SetNavigator(IResolveVisitorNavigator navigator) |
---|
106 | { |
---|
107 | this.navigator = navigator ?? skipAllNavigator; |
---|
108 | } |
---|
109 | |
---|
110 | ResolveResult voidResult { |
---|
111 | get { |
---|
112 | return new ResolveResult(resolver.Compilation.FindType(KnownTypeCode.Void)); |
---|
113 | } |
---|
114 | } |
---|
115 | #endregion |
---|
116 | |
---|
117 | #region ResetContext |
---|
118 | /// <summary> |
---|
119 | /// Resets the visitor to the stored position, runs the action, and then reverts the visitor to the previous position. |
---|
120 | /// </summary> |
---|
121 | void ResetContext(CSharpResolver storedContext, Action action) |
---|
122 | { |
---|
123 | var oldResolverEnabled = this.resolverEnabled; |
---|
124 | var oldResolver = this.resolver; |
---|
125 | var oldQueryResult = this.currentQueryResult; |
---|
126 | try { |
---|
127 | this.resolverEnabled = false; |
---|
128 | this.resolver = storedContext; |
---|
129 | this.currentQueryResult = null; |
---|
130 | |
---|
131 | action(); |
---|
132 | } finally { |
---|
133 | this.resolverEnabled = oldResolverEnabled; |
---|
134 | this.resolver = oldResolver; |
---|
135 | this.currentQueryResult = oldQueryResult; |
---|
136 | } |
---|
137 | } |
---|
138 | #endregion |
---|
139 | |
---|
140 | #region Scan / Resolve |
---|
141 | /// <summary> |
---|
142 | /// Scans the AST rooted at the given node. |
---|
143 | /// </summary> |
---|
144 | public void Scan(AstNode node) |
---|
145 | { |
---|
146 | if (node == null || node.IsNull) |
---|
147 | return; |
---|
148 | switch (node.NodeType) { |
---|
149 | case NodeType.Token: |
---|
150 | case NodeType.Whitespace: |
---|
151 | return; // skip tokens, identifiers, comments, etc. |
---|
152 | } |
---|
153 | // don't Scan again if the node was already resolved |
---|
154 | if (resolveResultCache.ContainsKey(node)) { |
---|
155 | // Restore state change caused by this node: |
---|
156 | CSharpResolver newResolver; |
---|
157 | if (resolverAfterDict.TryGetValue(node, out newResolver)) |
---|
158 | resolver = newResolver; |
---|
159 | return; |
---|
160 | } |
---|
161 | |
---|
162 | var mode = navigator.Scan(node); |
---|
163 | switch (mode) { |
---|
164 | case ResolveVisitorNavigationMode.Skip: |
---|
165 | if (node is VariableDeclarationStatement || node is SwitchSection) { |
---|
166 | // Enforce scanning of variable declarations. |
---|
167 | goto case ResolveVisitorNavigationMode.Scan; |
---|
168 | } |
---|
169 | StoreCurrentState(node); |
---|
170 | break; |
---|
171 | case ResolveVisitorNavigationMode.Scan: |
---|
172 | bool oldResolverEnabled = resolverEnabled; |
---|
173 | var oldResolver = resolver; |
---|
174 | resolverEnabled = false; |
---|
175 | StoreCurrentState(node); |
---|
176 | ResolveResult result = node.AcceptVisitor(this); |
---|
177 | if (result != null) { |
---|
178 | // If the node was resolved, store the result even though it wasn't requested. |
---|
179 | // This is necessary so that Visit-methods that decide to always resolve are |
---|
180 | // guaranteed to get called only once. |
---|
181 | // This is used for lambda registration. |
---|
182 | StoreResult(node, result); |
---|
183 | if (resolver != oldResolver) { |
---|
184 | // The node changed the resolver state: |
---|
185 | resolverAfterDict.Add(node, resolver); |
---|
186 | } |
---|
187 | cancellationToken.ThrowIfCancellationRequested(); |
---|
188 | } |
---|
189 | resolverEnabled = oldResolverEnabled; |
---|
190 | break; |
---|
191 | case ResolveVisitorNavigationMode.Resolve: |
---|
192 | Resolve(node); |
---|
193 | break; |
---|
194 | default: |
---|
195 | throw new InvalidOperationException("Invalid value for ResolveVisitorNavigationMode"); |
---|
196 | } |
---|
197 | } |
---|
198 | |
---|
199 | /// <summary> |
---|
200 | /// Equivalent to 'Scan', but also resolves the node at the same time. |
---|
201 | /// This method should be only used if the CSharpResolver passed to the ResolveVisitor was manually set |
---|
202 | /// to the correct state. |
---|
203 | /// Otherwise, use <c>resolver.Scan(syntaxTree); var result = resolver.GetResolveResult(node);</c> |
---|
204 | /// instead. |
---|
205 | /// -- |
---|
206 | /// This method now is internal, because it is difficult to use correctly. |
---|
207 | /// Users of the public API should use Scan()+GetResolveResult() instead. |
---|
208 | /// </summary> |
---|
209 | internal ResolveResult Resolve(AstNode node) |
---|
210 | { |
---|
211 | if (node == null || node.IsNull) |
---|
212 | return errorResult; |
---|
213 | bool oldResolverEnabled = resolverEnabled; |
---|
214 | resolverEnabled = true; |
---|
215 | ResolveResult result; |
---|
216 | if (!resolveResultCache.TryGetValue(node, out result)) { |
---|
217 | cancellationToken.ThrowIfCancellationRequested(); |
---|
218 | StoreCurrentState(node); |
---|
219 | var oldResolver = resolver; |
---|
220 | result = node.AcceptVisitor(this) ?? errorResult; |
---|
221 | StoreResult(node, result); |
---|
222 | if (resolver != oldResolver) { |
---|
223 | // The node changed the resolver state: |
---|
224 | resolverAfterDict.Add(node, resolver); |
---|
225 | } |
---|
226 | } |
---|
227 | resolverEnabled = oldResolverEnabled; |
---|
228 | return result; |
---|
229 | } |
---|
230 | |
---|
231 | IType ResolveType(AstType type) |
---|
232 | { |
---|
233 | return Resolve(type).Type; |
---|
234 | } |
---|
235 | |
---|
236 | void StoreCurrentState(AstNode node) |
---|
237 | { |
---|
238 | // It's possible that we re-visit an expression that we scanned over earlier, |
---|
239 | // so we might have to overwrite an existing state. |
---|
240 | |
---|
241 | #if DEBUG |
---|
242 | CSharpResolver oldResolver; |
---|
243 | if (resolverBeforeDict.TryGetValue(node, out oldResolver)) { |
---|
244 | Debug.Assert(oldResolver.LocalVariables.SequenceEqual(resolver.LocalVariables)); |
---|
245 | } |
---|
246 | #endif |
---|
247 | |
---|
248 | resolverBeforeDict[node] = resolver; |
---|
249 | } |
---|
250 | |
---|
251 | void StoreResult(AstNode node, ResolveResult result) |
---|
252 | { |
---|
253 | Debug.Assert(result != null); |
---|
254 | if (node.IsNull) |
---|
255 | return; |
---|
256 | Log.WriteLine("Resolved '{0}' to {1}", node, result); |
---|
257 | Debug.Assert(!CSharpAstResolver.IsUnresolvableNode(node)); |
---|
258 | // The state should be stored before the result is. |
---|
259 | Debug.Assert(resolverBeforeDict.ContainsKey(node)); |
---|
260 | // Don't store results twice. |
---|
261 | Debug.Assert(!resolveResultCache.ContainsKey(node)); |
---|
262 | // Don't use ConversionResolveResult as a result, because it can get |
---|
263 | // confused with an implicit conversion. |
---|
264 | Debug.Assert(!(result is ConversionResolveResult) || result is CastResolveResult); |
---|
265 | resolveResultCache[node] = result; |
---|
266 | if (navigator != null) |
---|
267 | navigator.Resolved(node, result); |
---|
268 | } |
---|
269 | |
---|
270 | void ScanChildren(AstNode node) |
---|
271 | { |
---|
272 | for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { |
---|
273 | Scan(child); |
---|
274 | } |
---|
275 | } |
---|
276 | #endregion |
---|
277 | |
---|
278 | #region Process Conversions |
---|
279 | sealed class AnonymousFunctionConversion : Conversion |
---|
280 | { |
---|
281 | public readonly IType ReturnType; |
---|
282 | public readonly ExplicitlyTypedLambda ExplicitlyTypedLambda; |
---|
283 | public readonly LambdaTypeHypothesis Hypothesis; |
---|
284 | readonly bool isValid; |
---|
285 | |
---|
286 | public AnonymousFunctionConversion(IType returnType, LambdaTypeHypothesis hypothesis, bool isValid) |
---|
287 | { |
---|
288 | if (returnType == null) |
---|
289 | throw new ArgumentNullException("returnType"); |
---|
290 | this.ReturnType = returnType; |
---|
291 | this.Hypothesis = hypothesis; |
---|
292 | this.isValid = isValid; |
---|
293 | } |
---|
294 | |
---|
295 | public AnonymousFunctionConversion(IType returnType, ExplicitlyTypedLambda explicitlyTypedLambda, bool isValid) |
---|
296 | { |
---|
297 | if (returnType == null) |
---|
298 | throw new ArgumentNullException("returnType"); |
---|
299 | this.ReturnType = returnType; |
---|
300 | this.ExplicitlyTypedLambda = explicitlyTypedLambda; |
---|
301 | this.isValid = isValid; |
---|
302 | } |
---|
303 | |
---|
304 | public override bool IsValid { |
---|
305 | get { return isValid; } |
---|
306 | } |
---|
307 | |
---|
308 | public override bool IsImplicit { |
---|
309 | get { return true; } |
---|
310 | } |
---|
311 | |
---|
312 | public override bool IsAnonymousFunctionConversion { |
---|
313 | get { return true; } |
---|
314 | } |
---|
315 | } |
---|
316 | |
---|
317 | /// <summary> |
---|
318 | /// Convert 'rr' to the target type using the specified conversion. |
---|
319 | /// </summary> |
---|
320 | void ProcessConversion(Expression expr, ResolveResult rr, Conversion conversion, IType targetType) |
---|
321 | { |
---|
322 | AnonymousFunctionConversion afc = conversion as AnonymousFunctionConversion; |
---|
323 | if (afc != null) { |
---|
324 | Log.WriteLine("Processing conversion of anonymous function to " + targetType + "..."); |
---|
325 | |
---|
326 | Log.Indent(); |
---|
327 | if (afc.Hypothesis != null) |
---|
328 | afc.Hypothesis.MergeInto(this, afc.ReturnType); |
---|
329 | if (afc.ExplicitlyTypedLambda != null) |
---|
330 | afc.ExplicitlyTypedLambda.ApplyReturnType(this, afc.ReturnType); |
---|
331 | Log.Unindent(); |
---|
332 | } |
---|
333 | if (expr != null && !expr.IsNull && conversion != Conversion.IdentityConversion) { |
---|
334 | navigator.ProcessConversion(expr, rr, conversion, targetType); |
---|
335 | conversionDict[expr] = new ConversionWithTargetType(conversion, targetType); |
---|
336 | } |
---|
337 | } |
---|
338 | |
---|
339 | void ImportConversions(ResolveVisitor childVisitor) |
---|
340 | { |
---|
341 | foreach (var pair in childVisitor.conversionDict) { |
---|
342 | conversionDict.Add(pair.Key, pair.Value); |
---|
343 | navigator.ProcessConversion(pair.Key, resolveResultCache[pair.Key], pair.Value.Conversion, pair.Value.TargetType); |
---|
344 | } |
---|
345 | } |
---|
346 | |
---|
347 | /// <summary> |
---|
348 | /// Convert 'rr' to the target type. |
---|
349 | /// </summary> |
---|
350 | void ProcessConversion(Expression expr, ResolveResult rr, IType targetType) |
---|
351 | { |
---|
352 | if (expr == null || expr.IsNull) |
---|
353 | return; |
---|
354 | ProcessConversion(expr, rr, resolver.conversions.ImplicitConversion(rr, targetType), targetType); |
---|
355 | } |
---|
356 | |
---|
357 | /// <summary> |
---|
358 | /// Resolves the specified expression and processes the conversion to targetType. |
---|
359 | /// </summary> |
---|
360 | void ResolveAndProcessConversion(Expression expr, IType targetType) |
---|
361 | { |
---|
362 | if (targetType.Kind == TypeKind.Unknown) { |
---|
363 | // no need to resolve the expression right now |
---|
364 | Scan(expr); |
---|
365 | } else { |
---|
366 | ProcessConversion(expr, Resolve(expr), targetType); |
---|
367 | } |
---|
368 | } |
---|
369 | |
---|
370 | void ProcessConversionResult(Expression expr, ConversionResolveResult rr) |
---|
371 | { |
---|
372 | if (rr != null && !(rr is CastResolveResult)) |
---|
373 | ProcessConversion(expr, rr.Input, rr.Conversion, rr.Type); |
---|
374 | } |
---|
375 | |
---|
376 | void ProcessConversionResults(IEnumerable<Expression> expr, IEnumerable<ResolveResult> conversionResolveResults) |
---|
377 | { |
---|
378 | Debug.Assert(expr.Count() == conversionResolveResults.Count()); |
---|
379 | using (var e1 = expr.GetEnumerator()) { |
---|
380 | using (var e2 = conversionResolveResults.GetEnumerator()) { |
---|
381 | while (e1.MoveNext() && e2.MoveNext()) { |
---|
382 | ProcessConversionResult(e1.Current, e2.Current as ConversionResolveResult); |
---|
383 | } |
---|
384 | } |
---|
385 | } |
---|
386 | } |
---|
387 | |
---|
388 | void MarkUnknownNamedArguments(IEnumerable<Expression> arguments) |
---|
389 | { |
---|
390 | foreach (var nae in arguments.OfType<NamedArgumentExpression>()) { |
---|
391 | StoreCurrentState(nae); |
---|
392 | StoreResult(nae, new NamedArgumentResolveResult(nae.Name, resolveResultCache[nae.Expression])); |
---|
393 | } |
---|
394 | } |
---|
395 | |
---|
396 | void ProcessInvocationResult(Expression target, IEnumerable<Expression> arguments, ResolveResult invocation) |
---|
397 | { |
---|
398 | if (invocation is CSharpInvocationResolveResult || invocation is DynamicInvocationResolveResult) { |
---|
399 | int i = 0; |
---|
400 | IList<ResolveResult> argumentsRR; |
---|
401 | if (invocation is CSharpInvocationResolveResult) { |
---|
402 | var csi = (CSharpInvocationResolveResult)invocation; |
---|
403 | if (csi.IsExtensionMethodInvocation) { |
---|
404 | Debug.Assert(arguments.Count() + 1 == csi.Arguments.Count); |
---|
405 | ProcessConversionResult(target, csi.Arguments[0] as ConversionResolveResult); |
---|
406 | i = 1; |
---|
407 | } else { |
---|
408 | Debug.Assert(arguments.Count() == csi.Arguments.Count); |
---|
409 | } |
---|
410 | argumentsRR = csi.Arguments; |
---|
411 | } |
---|
412 | else { |
---|
413 | argumentsRR = ((DynamicInvocationResolveResult)invocation).Arguments; |
---|
414 | } |
---|
415 | |
---|
416 | foreach (Expression arg in arguments) { |
---|
417 | ResolveResult argRR = argumentsRR[i++]; |
---|
418 | NamedArgumentExpression nae = arg as NamedArgumentExpression; |
---|
419 | NamedArgumentResolveResult nrr = argRR as NamedArgumentResolveResult; |
---|
420 | Debug.Assert((nae == null) == (nrr == null)); |
---|
421 | if (nae != null && nrr != null) { |
---|
422 | StoreCurrentState(nae); |
---|
423 | StoreResult(nae, nrr); |
---|
424 | ProcessConversionResult(nae.Expression, nrr.Argument as ConversionResolveResult); |
---|
425 | } else { |
---|
426 | ProcessConversionResult(arg, argRR as ConversionResolveResult); |
---|
427 | } |
---|
428 | } |
---|
429 | } |
---|
430 | else { |
---|
431 | MarkUnknownNamedArguments(arguments); |
---|
432 | } |
---|
433 | } |
---|
434 | #endregion |
---|
435 | |
---|
436 | #region GetResolveResult |
---|
437 | /// <summary> |
---|
438 | /// Gets the resolve result for the specified node. |
---|
439 | /// If the node was not resolved by the navigator, this method will resolve it. |
---|
440 | /// </summary> |
---|
441 | public ResolveResult GetResolveResult(AstNode node) |
---|
442 | { |
---|
443 | Debug.Assert(!CSharpAstResolver.IsUnresolvableNode(node)); |
---|
444 | |
---|
445 | MergeUndecidedLambdas(); |
---|
446 | ResolveResult result; |
---|
447 | if (resolveResultCache.TryGetValue(node, out result)) |
---|
448 | return result; |
---|
449 | |
---|
450 | AstNode parent; |
---|
451 | CSharpResolver storedResolver = GetPreviouslyScannedContext(node, out parent); |
---|
452 | ResetContext( |
---|
453 | storedResolver, |
---|
454 | delegate { |
---|
455 | navigator = new NodeListResolveVisitorNavigator(node); |
---|
456 | Debug.Assert(!resolverEnabled); |
---|
457 | Scan(parent); |
---|
458 | navigator = skipAllNavigator; |
---|
459 | }); |
---|
460 | |
---|
461 | MergeUndecidedLambdas(); |
---|
462 | return resolveResultCache[node]; |
---|
463 | } |
---|
464 | |
---|
465 | CSharpResolver GetPreviouslyScannedContext(AstNode node, out AstNode parent) |
---|
466 | { |
---|
467 | parent = node; |
---|
468 | CSharpResolver storedResolver; |
---|
469 | while (!resolverBeforeDict.TryGetValue(parent, out storedResolver)) { |
---|
470 | AstNode tmp = parent.Parent; |
---|
471 | if (tmp == null) |
---|
472 | throw new InvalidOperationException("Could not find a resolver state for any parent of the specified node. Are you trying to resolve a node that is not a descendant of the CSharpAstResolver's root node?"); |
---|
473 | if (tmp.NodeType == NodeType.Whitespace) |
---|
474 | return resolver; // special case: resolve expression within preprocessor directive |
---|
475 | parent = tmp; |
---|
476 | } |
---|
477 | return storedResolver; |
---|
478 | } |
---|
479 | |
---|
480 | /// <summary> |
---|
481 | /// Gets the resolver state in front of the specified node. |
---|
482 | /// If the node was not visited by a previous scanning process, the |
---|
483 | /// AST will be scanned again to determine the state. |
---|
484 | /// </summary> |
---|
485 | public CSharpResolver GetResolverStateBefore(AstNode node) |
---|
486 | { |
---|
487 | MergeUndecidedLambdas(); |
---|
488 | CSharpResolver r; |
---|
489 | if (resolverBeforeDict.TryGetValue(node, out r)) |
---|
490 | return r; |
---|
491 | |
---|
492 | AstNode parent; |
---|
493 | CSharpResolver storedResolver = GetPreviouslyScannedContext(node, out parent); |
---|
494 | ResetContext( |
---|
495 | storedResolver, |
---|
496 | delegate { |
---|
497 | navigator = new NodeListResolveVisitorNavigator(new[] { node }, scanOnly: true); |
---|
498 | Debug.Assert(!resolverEnabled); |
---|
499 | // parent might already be resolved if 'node' is an unresolvable node |
---|
500 | Scan(parent); |
---|
501 | navigator = skipAllNavigator; |
---|
502 | }); |
---|
503 | |
---|
504 | MergeUndecidedLambdas(); |
---|
505 | while (node != null) { |
---|
506 | if (resolverBeforeDict.TryGetValue(node, out r)) |
---|
507 | return r; |
---|
508 | node = node.Parent; |
---|
509 | } |
---|
510 | return null; |
---|
511 | } |
---|
512 | |
---|
513 | public CSharpResolver GetResolverStateAfter(AstNode node) |
---|
514 | { |
---|
515 | // Resolve the node to fill the resolverAfterDict |
---|
516 | GetResolveResult(node); |
---|
517 | CSharpResolver result; |
---|
518 | if (resolverAfterDict.TryGetValue(node, out result)) |
---|
519 | return result; |
---|
520 | else |
---|
521 | return GetResolverStateBefore(node); |
---|
522 | } |
---|
523 | |
---|
524 | public ConversionWithTargetType GetConversionWithTargetType(Expression expr) |
---|
525 | { |
---|
526 | GetResolverStateBefore(expr); |
---|
527 | ResolveParentForConversion(expr); |
---|
528 | ConversionWithTargetType result; |
---|
529 | if (conversionDict.TryGetValue(expr, out result)) { |
---|
530 | return result; |
---|
531 | } else { |
---|
532 | ResolveResult rr = GetResolveResult(expr); |
---|
533 | return new ConversionWithTargetType(Conversion.IdentityConversion, rr.Type); |
---|
534 | } |
---|
535 | } |
---|
536 | #endregion |
---|
537 | |
---|
538 | #region Track UsingScope |
---|
539 | ResolveResult IAstVisitor<ResolveResult>.VisitSyntaxTree(SyntaxTree unit) |
---|
540 | { |
---|
541 | CSharpResolver previousResolver = resolver; |
---|
542 | try { |
---|
543 | if (unresolvedFile != null) { |
---|
544 | resolver = resolver.WithCurrentUsingScope(unresolvedFile.RootUsingScope.Resolve(resolver.Compilation)); |
---|
545 | } else { |
---|
546 | var cv = new TypeSystemConvertVisitor(unit.FileName ?? string.Empty); |
---|
547 | ApplyVisitorToUsings(cv, unit.Children); |
---|
548 | PushUsingScope(cv.UnresolvedFile.RootUsingScope); |
---|
549 | } |
---|
550 | ScanChildren(unit); |
---|
551 | return voidResult; |
---|
552 | } finally { |
---|
553 | resolver = previousResolver; |
---|
554 | } |
---|
555 | } |
---|
556 | |
---|
557 | void ApplyVisitorToUsings(TypeSystemConvertVisitor visitor, IEnumerable<AstNode> children) |
---|
558 | { |
---|
559 | foreach (var child in children) { |
---|
560 | if (child is ExternAliasDeclaration || child is UsingDeclaration || child is UsingAliasDeclaration) { |
---|
561 | child.AcceptVisitor(visitor); |
---|
562 | } |
---|
563 | } |
---|
564 | } |
---|
565 | |
---|
566 | void PushUsingScope(UsingScope usingScope) |
---|
567 | { |
---|
568 | usingScope.Freeze(); |
---|
569 | resolver = resolver.WithCurrentUsingScope(new ResolvedUsingScope(resolver.CurrentTypeResolveContext, usingScope)); |
---|
570 | } |
---|
571 | |
---|
572 | ResolveResult IAstVisitor<ResolveResult>.VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration) |
---|
573 | { |
---|
574 | CSharpResolver previousResolver = resolver; |
---|
575 | try { |
---|
576 | var nsName = namespaceDeclaration.NamespaceName; |
---|
577 | AstNode child = namespaceDeclaration.FirstChild; |
---|
578 | |
---|
579 | for (; child != null && child.Role != Roles.LBrace; child = child.NextSibling) { |
---|
580 | Scan(child); |
---|
581 | } |
---|
582 | |
---|
583 | if (unresolvedFile != null) { |
---|
584 | resolver = resolver.WithCurrentUsingScope(unresolvedFile.GetUsingScope(namespaceDeclaration.StartLocation).Resolve(resolver.Compilation)); |
---|
585 | |
---|
586 | } else { |
---|
587 | // string fileName = namespaceDeclaration.GetRegion().FileName ?? string.Empty; |
---|
588 | // Fetch parent using scope |
---|
589 | // Create root using scope if necessary |
---|
590 | if (resolver.CurrentUsingScope == null) |
---|
591 | PushUsingScope(new UsingScope()); |
---|
592 | |
---|
593 | // Create child using scope |
---|
594 | DomRegion region = namespaceDeclaration.GetRegion(); |
---|
595 | var identifiers = namespaceDeclaration.Identifiers.ToList(); |
---|
596 | // For all but the last identifier: |
---|
597 | UsingScope usingScope; |
---|
598 | for (int i = 0; i < identifiers.Count - 1; i++) { |
---|
599 | usingScope = new UsingScope(resolver.CurrentUsingScope.UnresolvedUsingScope, identifiers[i]); |
---|
600 | usingScope.Region = region; |
---|
601 | PushUsingScope(usingScope); |
---|
602 | } |
---|
603 | // Last using scope: |
---|
604 | usingScope = new UsingScope(resolver.CurrentUsingScope.UnresolvedUsingScope, identifiers.Last()); |
---|
605 | usingScope.Region = region; |
---|
606 | var cv = new TypeSystemConvertVisitor(new CSharpUnresolvedFile(), usingScope); |
---|
607 | ApplyVisitorToUsings(cv, namespaceDeclaration.Children); |
---|
608 | PushUsingScope(usingScope); |
---|
609 | } |
---|
610 | for (; child != null; child = child.NextSibling) { |
---|
611 | Scan(child); |
---|
612 | } |
---|
613 | |
---|
614 | // merge undecided lambdas before leaving the using scope so that |
---|
615 | // the resolver can make better use of its cache |
---|
616 | MergeUndecidedLambdas(); |
---|
617 | if (resolver.CurrentUsingScope != null && resolver.CurrentUsingScope.Namespace != null) |
---|
618 | return new NamespaceResolveResult(resolver.CurrentUsingScope.Namespace); |
---|
619 | else |
---|
620 | return null; |
---|
621 | } finally { |
---|
622 | resolver = previousResolver; |
---|
623 | } |
---|
624 | } |
---|
625 | #endregion |
---|
626 | |
---|
627 | #region Track CurrentTypeDefinition |
---|
628 | ResolveResult VisitTypeOrDelegate(AstNode typeDeclaration, string name, int typeParameterCount) |
---|
629 | { |
---|
630 | CSharpResolver previousResolver = resolver; |
---|
631 | try { |
---|
632 | ITypeDefinition newTypeDefinition = null; |
---|
633 | if (resolver.CurrentTypeDefinition != null) { |
---|
634 | int totalTypeParameterCount = resolver.CurrentTypeDefinition.TypeParameterCount + typeParameterCount; |
---|
635 | foreach (ITypeDefinition nestedType in resolver.CurrentTypeDefinition.NestedTypes) { |
---|
636 | if (nestedType.Name == name && nestedType.TypeParameterCount == totalTypeParameterCount) { |
---|
637 | newTypeDefinition = nestedType; |
---|
638 | break; |
---|
639 | } |
---|
640 | } |
---|
641 | } else if (resolver.CurrentUsingScope != null) { |
---|
642 | newTypeDefinition = resolver.CurrentUsingScope.Namespace.GetTypeDefinition(name, typeParameterCount); |
---|
643 | } |
---|
644 | if (newTypeDefinition != null) |
---|
645 | resolver = resolver.WithCurrentTypeDefinition(newTypeDefinition); |
---|
646 | |
---|
647 | ScanChildren(typeDeclaration); |
---|
648 | |
---|
649 | // merge undecided lambdas before leaving the type definition so that |
---|
650 | // the resolver can make better use of its cache |
---|
651 | MergeUndecidedLambdas(); |
---|
652 | |
---|
653 | return newTypeDefinition != null ? new TypeResolveResult(newTypeDefinition) : errorResult; |
---|
654 | } finally { |
---|
655 | resolver = previousResolver; |
---|
656 | } |
---|
657 | } |
---|
658 | |
---|
659 | ResolveResult IAstVisitor<ResolveResult>.VisitTypeDeclaration(TypeDeclaration typeDeclaration) |
---|
660 | { |
---|
661 | return VisitTypeOrDelegate(typeDeclaration, typeDeclaration.Name, typeDeclaration.TypeParameters.Count); |
---|
662 | } |
---|
663 | |
---|
664 | ResolveResult IAstVisitor<ResolveResult>.VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration) |
---|
665 | { |
---|
666 | return VisitTypeOrDelegate(delegateDeclaration, delegateDeclaration.Name, delegateDeclaration.TypeParameters.Count); |
---|
667 | } |
---|
668 | #endregion |
---|
669 | |
---|
670 | #region Track CurrentMember |
---|
671 | ResolveResult IAstVisitor<ResolveResult>.VisitFieldDeclaration(FieldDeclaration fieldDeclaration) |
---|
672 | { |
---|
673 | return VisitFieldOrEventDeclaration(fieldDeclaration, SymbolKind.Field); |
---|
674 | } |
---|
675 | |
---|
676 | ResolveResult IAstVisitor<ResolveResult>.VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration) |
---|
677 | { |
---|
678 | return VisitFieldOrEventDeclaration(fixedFieldDeclaration, SymbolKind.Field); |
---|
679 | } |
---|
680 | |
---|
681 | ResolveResult IAstVisitor<ResolveResult>.VisitEventDeclaration(EventDeclaration eventDeclaration) |
---|
682 | { |
---|
683 | return VisitFieldOrEventDeclaration(eventDeclaration, SymbolKind.Event); |
---|
684 | } |
---|
685 | |
---|
686 | ResolveResult VisitFieldOrEventDeclaration(EntityDeclaration fieldOrEventDeclaration, SymbolKind symbolKind) |
---|
687 | { |
---|
688 | //int initializerCount = fieldOrEventDeclaration.GetChildrenByRole(Roles.Variable).Count; |
---|
689 | CSharpResolver oldResolver = resolver; |
---|
690 | for (AstNode node = fieldOrEventDeclaration.FirstChild; node != null; node = node.NextSibling) { |
---|
691 | if (node.Role == Roles.Variable || node.Role == FixedFieldDeclaration.VariableRole) { |
---|
692 | IMember member; |
---|
693 | if (unresolvedFile != null) { |
---|
694 | member = GetMemberFromLocation(node); |
---|
695 | } else { |
---|
696 | string name = ((VariableInitializer)node).Name; |
---|
697 | member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, symbolKind, name); |
---|
698 | } |
---|
699 | resolver = resolver.WithCurrentMember(member); |
---|
700 | |
---|
701 | Scan(node); |
---|
702 | |
---|
703 | resolver = oldResolver; |
---|
704 | } else { |
---|
705 | Scan(node); |
---|
706 | } |
---|
707 | } |
---|
708 | return voidResult; |
---|
709 | } |
---|
710 | |
---|
711 | IMember GetMemberFromLocation(AstNode node) |
---|
712 | { |
---|
713 | ITypeDefinition typeDef = resolver.CurrentTypeDefinition; |
---|
714 | if (typeDef == null) |
---|
715 | return null; |
---|
716 | TextLocation location = TypeSystemConvertVisitor.GetStartLocationAfterAttributes(node); |
---|
717 | return typeDef.GetMembers( |
---|
718 | delegate (IUnresolvedMember m) { |
---|
719 | if (m.UnresolvedFile != unresolvedFile) |
---|
720 | return false; |
---|
721 | DomRegion region = m.Region; |
---|
722 | return !region.IsEmpty && region.Begin <= location && region.End > location; |
---|
723 | }, |
---|
724 | GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions |
---|
725 | ).FirstOrDefault(); |
---|
726 | } |
---|
727 | |
---|
728 | ResolveResult IAstVisitor<ResolveResult>.VisitVariableInitializer(VariableInitializer variableInitializer) |
---|
729 | { |
---|
730 | // Within the variable initializer, the newly declared variable is not yet available: |
---|
731 | var resolverWithVariable = resolver; |
---|
732 | if (variableInitializer.Parent is VariableDeclarationStatement) |
---|
733 | resolver = resolver.PopLastVariable(); |
---|
734 | |
---|
735 | ArrayInitializerExpression aie = variableInitializer.Initializer as ArrayInitializerExpression; |
---|
736 | if (resolverEnabled || aie != null) { |
---|
737 | ResolveResult result = errorResult; |
---|
738 | if (variableInitializer.Parent is FieldDeclaration || variableInitializer.Parent is EventDeclaration) { |
---|
739 | if (resolver.CurrentMember != null) { |
---|
740 | result = new MemberResolveResult(null, resolver.CurrentMember, false); |
---|
741 | } |
---|
742 | } else { |
---|
743 | string identifier = variableInitializer.Name; |
---|
744 | foreach (IVariable v in resolverWithVariable.LocalVariables) { |
---|
745 | if (v.Name == identifier) { |
---|
746 | result = new LocalResolveResult(v); |
---|
747 | break; |
---|
748 | } |
---|
749 | } |
---|
750 | } |
---|
751 | ArrayType arrayType = result.Type as ArrayType; |
---|
752 | if (aie != null && arrayType != null) { |
---|
753 | StoreCurrentState(aie); |
---|
754 | List<Expression> initializerElements = new List<Expression>(); |
---|
755 | int[] sizes = new int[arrayType.Dimensions]; |
---|
756 | UnpackArrayInitializer(initializerElements, sizes, aie, 0, true); |
---|
757 | ResolveResult[] initializerElementResults = new ResolveResult[initializerElements.Count]; |
---|
758 | for (int i = 0; i < initializerElementResults.Length; i++) { |
---|
759 | initializerElementResults[i] = Resolve(initializerElements[i]); |
---|
760 | } |
---|
761 | var arrayCreation = resolver.ResolveArrayCreation(arrayType.ElementType, sizes, initializerElementResults); |
---|
762 | StoreResult(aie, arrayCreation); |
---|
763 | ProcessConversionResults(initializerElements, arrayCreation.InitializerElements); |
---|
764 | } else if (variableInitializer.Parent is FixedStatement) { |
---|
765 | var initRR = Resolve(variableInitializer.Initializer); |
---|
766 | PointerType pointerType; |
---|
767 | if (initRR.Type.Kind == TypeKind.Array) { |
---|
768 | pointerType = new PointerType(((ArrayType)initRR.Type).ElementType); |
---|
769 | } else if (ReflectionHelper.GetTypeCode(initRR.Type) == TypeCode.String) { |
---|
770 | pointerType = new PointerType(resolver.Compilation.FindType(KnownTypeCode.Char)); |
---|
771 | } else { |
---|
772 | pointerType = null; |
---|
773 | ProcessConversion(variableInitializer.Initializer, initRR, result.Type); |
---|
774 | } |
---|
775 | if (pointerType != null) { |
---|
776 | var conversion = resolver.conversions.ImplicitConversion(pointerType, result.Type); |
---|
777 | if (conversion.IsIdentityConversion) |
---|
778 | conversion = Conversion.ImplicitPointerConversion; |
---|
779 | ProcessConversion(variableInitializer.Initializer, initRR, conversion, result.Type); |
---|
780 | } |
---|
781 | } else { |
---|
782 | ResolveAndProcessConversion(variableInitializer.Initializer, result.Type); |
---|
783 | } |
---|
784 | resolver = resolverWithVariable; |
---|
785 | return result; |
---|
786 | } else { |
---|
787 | Scan(variableInitializer.Initializer); |
---|
788 | resolver = resolverWithVariable; |
---|
789 | return null; |
---|
790 | } |
---|
791 | } |
---|
792 | |
---|
793 | ResolveResult IAstVisitor<ResolveResult>.VisitFixedVariableInitializer(FixedVariableInitializer fixedVariableInitializer) |
---|
794 | { |
---|
795 | if (resolverEnabled) { |
---|
796 | ResolveResult result = errorResult; |
---|
797 | if (resolver.CurrentMember != null) { |
---|
798 | result = new MemberResolveResult(null, resolver.CurrentMember, false); |
---|
799 | } |
---|
800 | ResolveAndProcessConversion(fixedVariableInitializer.CountExpression, resolver.Compilation.FindType(KnownTypeCode.Int32)); |
---|
801 | return result; |
---|
802 | } else { |
---|
803 | ScanChildren(fixedVariableInitializer); |
---|
804 | return null; |
---|
805 | } |
---|
806 | } |
---|
807 | |
---|
808 | ResolveResult VisitMethodMember(EntityDeclaration memberDeclaration) |
---|
809 | { |
---|
810 | CSharpResolver oldResolver = resolver; |
---|
811 | try { |
---|
812 | IMember member = null; |
---|
813 | if (unresolvedFile != null) { |
---|
814 | member = GetMemberFromLocation(memberDeclaration); |
---|
815 | } |
---|
816 | if (member == null) { |
---|
817 | // Re-discover the method: |
---|
818 | SymbolKind symbolKind = memberDeclaration.SymbolKind; |
---|
819 | var parameterTypes = TypeSystemConvertVisitor.GetParameterTypes(memberDeclaration.GetChildrenByRole(Roles.Parameter), InterningProvider.Dummy); |
---|
820 | if (symbolKind == SymbolKind.Constructor) { |
---|
821 | string name = memberDeclaration.HasModifier(Modifiers.Static) ? ".cctor" : ".ctor"; |
---|
822 | member = AbstractUnresolvedMember.Resolve( |
---|
823 | resolver.CurrentTypeResolveContext, symbolKind, name, |
---|
824 | parameterTypeReferences: parameterTypes); |
---|
825 | } else if (symbolKind == SymbolKind.Destructor) { |
---|
826 | member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, symbolKind, "Finalize"); |
---|
827 | } else { |
---|
828 | string[] typeParameterNames = memberDeclaration.GetChildrenByRole(Roles.TypeParameter).Select(tp => tp.Name).ToArray(); |
---|
829 | AstType explicitInterfaceAstType = memberDeclaration.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole); |
---|
830 | ITypeReference explicitInterfaceType = null; |
---|
831 | if (!explicitInterfaceAstType.IsNull) { |
---|
832 | explicitInterfaceType = explicitInterfaceAstType.ToTypeReference(); |
---|
833 | } |
---|
834 | member = AbstractUnresolvedMember.Resolve( |
---|
835 | resolver.CurrentTypeResolveContext, symbolKind, memberDeclaration.Name, |
---|
836 | explicitInterfaceType, typeParameterNames, parameterTypes); |
---|
837 | } |
---|
838 | } |
---|
839 | resolver = resolver.WithCurrentMember(member); |
---|
840 | ScanChildren(memberDeclaration); |
---|
841 | |
---|
842 | if (member != null) |
---|
843 | return new MemberResolveResult(null, member, false); |
---|
844 | else |
---|
845 | return errorResult; |
---|
846 | } finally { |
---|
847 | resolver = oldResolver; |
---|
848 | } |
---|
849 | } |
---|
850 | |
---|
851 | ResolveResult IAstVisitor<ResolveResult>.VisitMethodDeclaration(MethodDeclaration methodDeclaration) |
---|
852 | { |
---|
853 | return VisitMethodMember(methodDeclaration); |
---|
854 | } |
---|
855 | |
---|
856 | ResolveResult IAstVisitor<ResolveResult>.VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration) |
---|
857 | { |
---|
858 | return VisitMethodMember(operatorDeclaration); |
---|
859 | } |
---|
860 | |
---|
861 | ResolveResult IAstVisitor<ResolveResult>.VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration) |
---|
862 | { |
---|
863 | return VisitMethodMember(constructorDeclaration); |
---|
864 | } |
---|
865 | |
---|
866 | ResolveResult IAstVisitor<ResolveResult>.VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration) |
---|
867 | { |
---|
868 | return VisitMethodMember(destructorDeclaration); |
---|
869 | } |
---|
870 | |
---|
871 | // handle properties/indexers |
---|
872 | ResolveResult VisitPropertyMember(EntityDeclaration propertyOrIndexerDeclaration) |
---|
873 | { |
---|
874 | CSharpResolver oldResolver = resolver; |
---|
875 | try { |
---|
876 | IMember member; |
---|
877 | if (unresolvedFile != null) { |
---|
878 | member = GetMemberFromLocation(propertyOrIndexerDeclaration); |
---|
879 | } else { |
---|
880 | // Re-discover the property: |
---|
881 | string name = propertyOrIndexerDeclaration.Name; |
---|
882 | var parameterTypeReferences = TypeSystemConvertVisitor.GetParameterTypes(propertyOrIndexerDeclaration.GetChildrenByRole(Roles.Parameter), InterningProvider.Dummy); |
---|
883 | AstType explicitInterfaceAstType = propertyOrIndexerDeclaration.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole); |
---|
884 | ITypeReference explicitInterfaceType = null; |
---|
885 | if (!explicitInterfaceAstType.IsNull) { |
---|
886 | explicitInterfaceType = explicitInterfaceAstType.ToTypeReference(); |
---|
887 | } |
---|
888 | member = AbstractUnresolvedMember.Resolve( |
---|
889 | resolver.CurrentTypeResolveContext, propertyOrIndexerDeclaration.SymbolKind, name, |
---|
890 | explicitInterfaceType, parameterTypeReferences: parameterTypeReferences); |
---|
891 | } |
---|
892 | // We need to use the property as current member so that indexer parameters can be resolved correctly. |
---|
893 | resolver = resolver.WithCurrentMember(member); |
---|
894 | var resolverWithPropertyAsMember = resolver; |
---|
895 | |
---|
896 | for (AstNode node = propertyOrIndexerDeclaration.FirstChild; node != null; node = node.NextSibling) { |
---|
897 | if (node.Role == PropertyDeclaration.GetterRole && member is IProperty) { |
---|
898 | resolver = resolver.WithCurrentMember(((IProperty)member).Getter); |
---|
899 | Scan(node); |
---|
900 | resolver = resolverWithPropertyAsMember; |
---|
901 | } else if (node.Role == PropertyDeclaration.SetterRole && member is IProperty) { |
---|
902 | resolver = resolver.WithCurrentMember(((IProperty)member).Setter); |
---|
903 | Scan(node); |
---|
904 | resolver = resolverWithPropertyAsMember; |
---|
905 | } else { |
---|
906 | Scan(node); |
---|
907 | } |
---|
908 | } |
---|
909 | if (member != null) |
---|
910 | return new MemberResolveResult(null, member, false); |
---|
911 | else |
---|
912 | return errorResult; |
---|
913 | } finally { |
---|
914 | resolver = oldResolver; |
---|
915 | } |
---|
916 | } |
---|
917 | |
---|
918 | ResolveResult IAstVisitor<ResolveResult>.VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration) |
---|
919 | { |
---|
920 | return VisitPropertyMember(propertyDeclaration); |
---|
921 | } |
---|
922 | |
---|
923 | ResolveResult IAstVisitor<ResolveResult>.VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration) |
---|
924 | { |
---|
925 | return VisitPropertyMember(indexerDeclaration); |
---|
926 | } |
---|
927 | |
---|
928 | ResolveResult IAstVisitor<ResolveResult>.VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration) |
---|
929 | { |
---|
930 | CSharpResolver oldResolver = resolver; |
---|
931 | try { |
---|
932 | IMember member; |
---|
933 | if (unresolvedFile != null) { |
---|
934 | member = GetMemberFromLocation(eventDeclaration); |
---|
935 | } else { |
---|
936 | string name = eventDeclaration.Name; |
---|
937 | AstType explicitInterfaceAstType = eventDeclaration.PrivateImplementationType; |
---|
938 | if (explicitInterfaceAstType.IsNull) { |
---|
939 | member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, SymbolKind.Event, name); |
---|
940 | } else { |
---|
941 | member = AbstractUnresolvedMember.Resolve(resolver.CurrentTypeResolveContext, SymbolKind.Event, name, |
---|
942 | explicitInterfaceAstType.ToTypeReference()); |
---|
943 | } |
---|
944 | } |
---|
945 | resolver = resolver.WithCurrentMember(member); |
---|
946 | var resolverWithEventAsMember = resolver; |
---|
947 | |
---|
948 | for (AstNode node = eventDeclaration.FirstChild; node != null; node = node.NextSibling) { |
---|
949 | if (node.Role == CustomEventDeclaration.AddAccessorRole && member is IEvent) { |
---|
950 | resolver = resolver.WithCurrentMember(((IEvent)member).AddAccessor); |
---|
951 | Scan(node); |
---|
952 | resolver = resolverWithEventAsMember; |
---|
953 | } else if (node.Role == CustomEventDeclaration.RemoveAccessorRole && member is IEvent) { |
---|
954 | resolver = resolver.WithCurrentMember(((IEvent)member).RemoveAccessor); |
---|
955 | Scan(node); |
---|
956 | resolver = resolverWithEventAsMember; |
---|
957 | } else { |
---|
958 | Scan(node); |
---|
959 | } |
---|
960 | } |
---|
961 | |
---|
962 | if (member != null) |
---|
963 | return new MemberResolveResult(null, member, false); |
---|
964 | else |
---|
965 | return errorResult; |
---|
966 | } finally { |
---|
967 | resolver = oldResolver; |
---|
968 | } |
---|
969 | } |
---|
970 | |
---|
971 | ResolveResult IAstVisitor<ResolveResult>.VisitParameterDeclaration(ParameterDeclaration parameterDeclaration) |
---|
972 | { |
---|
973 | ScanChildren(parameterDeclaration); |
---|
974 | if (resolverEnabled) { |
---|
975 | string name = parameterDeclaration.Name; |
---|
976 | |
---|
977 | if (parameterDeclaration.Parent is DocumentationReference) { |
---|
978 | // create a dummy parameter |
---|
979 | IType type = ResolveType(parameterDeclaration.Type); |
---|
980 | switch (parameterDeclaration.ParameterModifier) { |
---|
981 | case ParameterModifier.Ref: |
---|
982 | case ParameterModifier.Out: |
---|
983 | type = new ByReferenceType(type); |
---|
984 | break; |
---|
985 | } |
---|
986 | return new LocalResolveResult(new DefaultParameter( |
---|
987 | type, name, |
---|
988 | isRef: parameterDeclaration.ParameterModifier == ParameterModifier.Ref, |
---|
989 | isOut: parameterDeclaration.ParameterModifier == ParameterModifier.Out, |
---|
990 | isParams: parameterDeclaration.ParameterModifier == ParameterModifier.Params)); |
---|
991 | } |
---|
992 | |
---|
993 | // Look in lambda parameters: |
---|
994 | foreach (IParameter p in resolver.LocalVariables.OfType<IParameter>()) { |
---|
995 | if (p.Name == name) |
---|
996 | return new LocalResolveResult(p); |
---|
997 | } |
---|
998 | |
---|
999 | IParameterizedMember pm = resolver.CurrentMember as IParameterizedMember; |
---|
1000 | if (pm == null && resolver.CurrentTypeDefinition != null) { |
---|
1001 | // Also consider delegate parameters: |
---|
1002 | pm = resolver.CurrentTypeDefinition.GetDelegateInvokeMethod(); |
---|
1003 | // pm will be null if the current type isn't a delegate |
---|
1004 | } |
---|
1005 | if (pm != null) { |
---|
1006 | foreach (IParameter p in pm.Parameters) { |
---|
1007 | if (p.Name == name) { |
---|
1008 | return new LocalResolveResult(p); |
---|
1009 | } |
---|
1010 | } |
---|
1011 | } |
---|
1012 | |
---|
1013 | return errorResult; |
---|
1014 | } else { |
---|
1015 | return null; |
---|
1016 | } |
---|
1017 | } |
---|
1018 | |
---|
1019 | ResolveResult IAstVisitor<ResolveResult>.VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration) |
---|
1020 | { |
---|
1021 | ScanChildren(typeParameterDeclaration); |
---|
1022 | if (resolverEnabled) { |
---|
1023 | string name = typeParameterDeclaration.Name; |
---|
1024 | IMethod m = resolver.CurrentMember as IMethod; |
---|
1025 | if (m != null) { |
---|
1026 | foreach (var tp in m.TypeParameters) { |
---|
1027 | if (tp.Name == name) |
---|
1028 | return new TypeResolveResult(tp); |
---|
1029 | } |
---|
1030 | } |
---|
1031 | if (resolver.CurrentTypeDefinition != null) { |
---|
1032 | var typeParameters = resolver.CurrentTypeDefinition.TypeParameters; |
---|
1033 | // look backwards so that TPs in the current type take precedence over those copied from outer types |
---|
1034 | for (int i = typeParameters.Count - 1; i >= 0; i--) { |
---|
1035 | if (typeParameters[i].Name == name) |
---|
1036 | return new TypeResolveResult(typeParameters[i]); |
---|
1037 | } |
---|
1038 | } |
---|
1039 | return errorResult; |
---|
1040 | } else { |
---|
1041 | return null; |
---|
1042 | } |
---|
1043 | } |
---|
1044 | |
---|
1045 | ResolveResult IAstVisitor<ResolveResult>.VisitEnumMemberDeclaration(EnumMemberDeclaration enumMemberDeclaration) |
---|
1046 | { |
---|
1047 | CSharpResolver oldResolver = resolver; |
---|
1048 | try { |
---|
1049 | // Scan enum member attributes before setting resolver.CurrentMember, so that |
---|
1050 | // enum values used as attribute arguments have the correct type. |
---|
1051 | // (within an enum member, all other enum members are treated as having their underlying type) |
---|
1052 | foreach (var attributeSection in enumMemberDeclaration.Attributes) |
---|
1053 | Scan(attributeSection); |
---|
1054 | |
---|
1055 | IMember member = null; |
---|
1056 | if (unresolvedFile != null) { |
---|
1057 | member = GetMemberFromLocation(enumMemberDeclaration); |
---|
1058 | } else if (resolver.CurrentTypeDefinition != null) { |
---|
1059 | string name = enumMemberDeclaration.Name; |
---|
1060 | member = resolver.CurrentTypeDefinition.GetFields(f => f.Name == name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); |
---|
1061 | } |
---|
1062 | resolver = resolver.WithCurrentMember(member); |
---|
1063 | |
---|
1064 | if (resolverEnabled && resolver.CurrentTypeDefinition != null) { |
---|
1065 | ResolveAndProcessConversion(enumMemberDeclaration.Initializer, resolver.CurrentTypeDefinition.EnumUnderlyingType); |
---|
1066 | if (resolverEnabled && member != null) |
---|
1067 | return new MemberResolveResult(null, member, false); |
---|
1068 | else |
---|
1069 | return errorResult; |
---|
1070 | } else { |
---|
1071 | Scan(enumMemberDeclaration.Initializer); |
---|
1072 | return null; |
---|
1073 | } |
---|
1074 | } finally { |
---|
1075 | resolver = oldResolver; |
---|
1076 | } |
---|
1077 | } |
---|
1078 | #endregion |
---|
1079 | |
---|
1080 | #region Track CheckForOverflow |
---|
1081 | ResolveResult IAstVisitor<ResolveResult>.VisitCheckedExpression(CheckedExpression checkedExpression) |
---|
1082 | { |
---|
1083 | CSharpResolver oldResolver = resolver; |
---|
1084 | try { |
---|
1085 | resolver = resolver.WithCheckForOverflow(true); |
---|
1086 | if (resolverEnabled) { |
---|
1087 | return Resolve(checkedExpression.Expression); |
---|
1088 | } else { |
---|
1089 | ScanChildren(checkedExpression); |
---|
1090 | return null; |
---|
1091 | } |
---|
1092 | } finally { |
---|
1093 | resolver = oldResolver; |
---|
1094 | } |
---|
1095 | } |
---|
1096 | |
---|
1097 | ResolveResult IAstVisitor<ResolveResult>.VisitUncheckedExpression(UncheckedExpression uncheckedExpression) |
---|
1098 | { |
---|
1099 | CSharpResolver oldResolver = resolver; |
---|
1100 | try { |
---|
1101 | resolver = resolver.WithCheckForOverflow(false); |
---|
1102 | if (resolverEnabled) { |
---|
1103 | return Resolve(uncheckedExpression.Expression); |
---|
1104 | } else { |
---|
1105 | ScanChildren(uncheckedExpression); |
---|
1106 | return null; |
---|
1107 | } |
---|
1108 | } finally { |
---|
1109 | resolver = oldResolver; |
---|
1110 | } |
---|
1111 | } |
---|
1112 | |
---|
1113 | ResolveResult IAstVisitor<ResolveResult>.VisitCheckedStatement(CheckedStatement checkedStatement) |
---|
1114 | { |
---|
1115 | CSharpResolver oldResolver = resolver; |
---|
1116 | try { |
---|
1117 | resolver = resolver.WithCheckForOverflow(true); |
---|
1118 | ScanChildren(checkedStatement); |
---|
1119 | return voidResult; |
---|
1120 | } finally { |
---|
1121 | resolver = oldResolver; |
---|
1122 | } |
---|
1123 | } |
---|
1124 | |
---|
1125 | ResolveResult IAstVisitor<ResolveResult>.VisitUncheckedStatement(UncheckedStatement uncheckedStatement) |
---|
1126 | { |
---|
1127 | CSharpResolver oldResolver = resolver; |
---|
1128 | try { |
---|
1129 | resolver = resolver.WithCheckForOverflow(false); |
---|
1130 | ScanChildren(uncheckedStatement); |
---|
1131 | return voidResult; |
---|
1132 | } finally { |
---|
1133 | resolver = oldResolver; |
---|
1134 | } |
---|
1135 | } |
---|
1136 | #endregion |
---|
1137 | |
---|
1138 | #region Visit AnonymousTypeCreateExpression |
---|
1139 | static string GetAnonymousTypePropertyName(Expression expr, out Expression resolveExpr) |
---|
1140 | { |
---|
1141 | if (expr is NamedExpression) { |
---|
1142 | var namedArgExpr = (NamedExpression)expr; |
---|
1143 | resolveExpr = namedArgExpr.Expression; |
---|
1144 | return namedArgExpr.Name; |
---|
1145 | } |
---|
1146 | // no name given, so it's a projection initializer |
---|
1147 | if (expr is MemberReferenceExpression) { |
---|
1148 | resolveExpr = expr; |
---|
1149 | return ((MemberReferenceExpression)expr).MemberName; |
---|
1150 | } |
---|
1151 | if (expr is IdentifierExpression) { |
---|
1152 | resolveExpr = expr; |
---|
1153 | return ((IdentifierExpression)expr).Identifier; |
---|
1154 | } |
---|
1155 | resolveExpr = null; |
---|
1156 | return null; |
---|
1157 | } |
---|
1158 | |
---|
1159 | class AnonymousTypeMember |
---|
1160 | { |
---|
1161 | public readonly Expression Expression; |
---|
1162 | public readonly ResolveResult Initializer; |
---|
1163 | |
---|
1164 | public AnonymousTypeMember(Expression expression, ResolveResult initializer) |
---|
1165 | { |
---|
1166 | this.Expression = expression; |
---|
1167 | this.Initializer = initializer; |
---|
1168 | } |
---|
1169 | } |
---|
1170 | |
---|
1171 | ResolveResult IAstVisitor<ResolveResult>.VisitAnonymousTypeCreateExpression(AnonymousTypeCreateExpression anonymousTypeCreateExpression) |
---|
1172 | { |
---|
1173 | // 7.6.10.6 Anonymous object creation expressions |
---|
1174 | List<IUnresolvedProperty> unresolvedProperties = new List<IUnresolvedProperty>(); |
---|
1175 | List<AnonymousTypeMember> members = new List<AnonymousTypeMember>(); |
---|
1176 | foreach (var expr in anonymousTypeCreateExpression.Initializers) { |
---|
1177 | Expression resolveExpr; |
---|
1178 | var name = GetAnonymousTypePropertyName(expr, out resolveExpr); |
---|
1179 | if (resolveExpr != null) { |
---|
1180 | var initRR = Resolve(resolveExpr); |
---|
1181 | var returnTypeRef = initRR.Type.ToTypeReference(); |
---|
1182 | var property = new DefaultUnresolvedProperty(); |
---|
1183 | property.Name = name; |
---|
1184 | property.Accessibility = Accessibility.Public; |
---|
1185 | property.ReturnType = returnTypeRef; |
---|
1186 | property.Getter = new DefaultUnresolvedMethod { |
---|
1187 | Name = "get_" + name, |
---|
1188 | Accessibility = Accessibility.Public, |
---|
1189 | ReturnType = returnTypeRef, |
---|
1190 | SymbolKind = SymbolKind.Accessor, |
---|
1191 | AccessorOwner = property |
---|
1192 | }; |
---|
1193 | unresolvedProperties.Add(property); |
---|
1194 | members.Add(new AnonymousTypeMember(expr, initRR)); |
---|
1195 | } else { |
---|
1196 | Scan(expr); |
---|
1197 | } |
---|
1198 | } |
---|
1199 | var anonymousType = new AnonymousType(resolver.Compilation, unresolvedProperties); |
---|
1200 | var properties = anonymousType.GetProperties().ToList(); |
---|
1201 | Debug.Assert(properties.Count == members.Count); |
---|
1202 | List<ResolveResult> assignments = new List<ResolveResult>(); |
---|
1203 | for (int i = 0; i < members.Count; i++) { |
---|
1204 | ResolveResult lhs = new MemberResolveResult(new InitializedObjectResolveResult(anonymousType), properties[i]); |
---|
1205 | ResolveResult rhs = members[i].Initializer; |
---|
1206 | ResolveResult assignment = resolver.ResolveAssignment(AssignmentOperatorType.Assign, lhs, rhs); |
---|
1207 | var ne = members[i].Expression as NamedExpression; |
---|
1208 | if (ne != null) { |
---|
1209 | StoreCurrentState(ne); |
---|
1210 | // ne.Expression was already resolved by the first loop |
---|
1211 | StoreResult(ne, lhs); |
---|
1212 | } |
---|
1213 | assignments.Add(assignment); |
---|
1214 | } |
---|
1215 | var anonymousCtor = DefaultResolvedMethod.GetDummyConstructor(resolver.Compilation, anonymousType); |
---|
1216 | return new InvocationResolveResult(null, anonymousCtor, initializerStatements: assignments); |
---|
1217 | } |
---|
1218 | #endregion |
---|
1219 | |
---|
1220 | #region Visit Expressions |
---|
1221 | ResolveResult IAstVisitor<ResolveResult>.VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression) |
---|
1222 | { |
---|
1223 | int dimensions = arrayCreateExpression.Arguments.Count; |
---|
1224 | IEnumerable<Expression> sizeArgumentExpressions; |
---|
1225 | ResolveResult[] sizeArguments; |
---|
1226 | IEnumerable<ArraySpecifier> additionalArraySpecifiers; |
---|
1227 | if (dimensions == 0) { |
---|
1228 | var firstSpecifier = arrayCreateExpression.AdditionalArraySpecifiers.FirstOrDefault(); |
---|
1229 | if (firstSpecifier != null) { |
---|
1230 | dimensions = firstSpecifier.Dimensions; |
---|
1231 | additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers.Skip(1); |
---|
1232 | } else { |
---|
1233 | // No array specifiers (neither with nor without size) - can happen if there are syntax errors. |
---|
1234 | // Dimensions must be at least one; otherwise 'new ArrayType' will crash. |
---|
1235 | dimensions = 1; |
---|
1236 | additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers; |
---|
1237 | } |
---|
1238 | sizeArguments = null; |
---|
1239 | sizeArgumentExpressions = null; |
---|
1240 | } else { |
---|
1241 | sizeArgumentExpressions = arrayCreateExpression.Arguments; |
---|
1242 | sizeArguments = new ResolveResult[dimensions]; |
---|
1243 | int pos = 0; |
---|
1244 | foreach (var node in sizeArgumentExpressions) |
---|
1245 | sizeArguments[pos++] = Resolve(node); |
---|
1246 | additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers; |
---|
1247 | } |
---|
1248 | |
---|
1249 | int[] sizes; |
---|
1250 | List<Expression> initializerElements; |
---|
1251 | ResolveResult[] initializerElementResults; |
---|
1252 | if (arrayCreateExpression.Initializer.IsNull) { |
---|
1253 | sizes = null; |
---|
1254 | initializerElements = null; |
---|
1255 | initializerElementResults = null; |
---|
1256 | } else { |
---|
1257 | StoreCurrentState(arrayCreateExpression.Initializer); |
---|
1258 | |
---|
1259 | initializerElements = new List<Expression>(); |
---|
1260 | sizes = new int[dimensions]; |
---|
1261 | UnpackArrayInitializer(initializerElements, sizes, arrayCreateExpression.Initializer, 0, true); |
---|
1262 | initializerElementResults = new ResolveResult[initializerElements.Count]; |
---|
1263 | for (int i = 0; i < initializerElementResults.Length; i++) { |
---|
1264 | initializerElementResults[i] = Resolve(initializerElements[i]); |
---|
1265 | } |
---|
1266 | StoreResult(arrayCreateExpression.Initializer, voidResult); |
---|
1267 | } |
---|
1268 | |
---|
1269 | IType elementType; |
---|
1270 | if (arrayCreateExpression.Type.IsNull) { |
---|
1271 | elementType = null; |
---|
1272 | } else { |
---|
1273 | elementType = ResolveType(arrayCreateExpression.Type); |
---|
1274 | foreach (var spec in additionalArraySpecifiers.Reverse()) { |
---|
1275 | elementType = new ArrayType(resolver.Compilation, elementType, spec.Dimensions); |
---|
1276 | } |
---|
1277 | } |
---|
1278 | ArrayCreateResolveResult acrr; |
---|
1279 | if (sizeArguments != null) { |
---|
1280 | acrr = resolver.ResolveArrayCreation(elementType, sizeArguments, initializerElementResults); |
---|
1281 | } else if (sizes != null) { |
---|
1282 | acrr = resolver.ResolveArrayCreation(elementType, sizes, initializerElementResults); |
---|
1283 | } else { |
---|
1284 | // neither size arguments nor an initializer exist -> error |
---|
1285 | return new ErrorResolveResult(new ArrayType(resolver.Compilation, elementType ?? SpecialType.UnknownType, dimensions)); |
---|
1286 | } |
---|
1287 | if (sizeArgumentExpressions != null) |
---|
1288 | ProcessConversionResults(sizeArgumentExpressions, acrr.SizeArguments); |
---|
1289 | if (acrr.InitializerElements != null) |
---|
1290 | ProcessConversionResults(initializerElements, acrr.InitializerElements); |
---|
1291 | return acrr; |
---|
1292 | } |
---|
1293 | |
---|
1294 | void UnpackArrayInitializer(List<Expression> elementList, int[] sizes, ArrayInitializerExpression initializer, int dimension, bool resolveNestedInitializersToVoid) |
---|
1295 | { |
---|
1296 | Debug.Assert(dimension < sizes.Length); |
---|
1297 | int elementCount = 0; |
---|
1298 | if (dimension + 1 < sizes.Length) { |
---|
1299 | foreach (var node in initializer.Elements) { |
---|
1300 | ArrayInitializerExpression aie = node as ArrayInitializerExpression; |
---|
1301 | if (aie != null) { |
---|
1302 | if (resolveNestedInitializersToVoid) { |
---|
1303 | StoreCurrentState(aie); |
---|
1304 | StoreResult(aie, voidResult); |
---|
1305 | } |
---|
1306 | UnpackArrayInitializer(elementList, sizes, aie, dimension + 1, resolveNestedInitializersToVoid); |
---|
1307 | } else { |
---|
1308 | elementList.Add(node); |
---|
1309 | } |
---|
1310 | elementCount++; |
---|
1311 | } |
---|
1312 | } else { |
---|
1313 | foreach (var expr in initializer.Elements) { |
---|
1314 | elementList.Add(expr); |
---|
1315 | elementCount++; |
---|
1316 | } |
---|
1317 | } |
---|
1318 | if (sizes[dimension] == 0) // 0 = uninitialized |
---|
1319 | sizes[dimension] = elementCount; |
---|
1320 | else if (sizes[dimension] != elementCount) |
---|
1321 | sizes[dimension] = -1; // -1 = error |
---|
1322 | } |
---|
1323 | |
---|
1324 | ResolveResult IAstVisitor<ResolveResult>.VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression) |
---|
1325 | { |
---|
1326 | // Array initializers are handled by their parent expression. |
---|
1327 | ScanChildren(arrayInitializerExpression); |
---|
1328 | return errorResult; |
---|
1329 | } |
---|
1330 | |
---|
1331 | ResolveResult IAstVisitor<ResolveResult>.VisitAsExpression(AsExpression asExpression) |
---|
1332 | { |
---|
1333 | if (resolverEnabled) { |
---|
1334 | ResolveResult input = Resolve(asExpression.Expression); |
---|
1335 | var targetType = ResolveType(asExpression.Type); |
---|
1336 | return new CastResolveResult(targetType, input, Conversion.TryCast, resolver.CheckForOverflow); |
---|
1337 | } else { |
---|
1338 | ScanChildren(asExpression); |
---|
1339 | return null; |
---|
1340 | } |
---|
1341 | } |
---|
1342 | |
---|
1343 | ResolveResult IAstVisitor<ResolveResult>.VisitAssignmentExpression(AssignmentExpression assignmentExpression) |
---|
1344 | { |
---|
1345 | if (resolverEnabled) { |
---|
1346 | Expression left = assignmentExpression.Left; |
---|
1347 | Expression right = assignmentExpression.Right; |
---|
1348 | ResolveResult leftResult = Resolve(left); |
---|
1349 | ResolveResult rightResult = Resolve(right); |
---|
1350 | ResolveResult rr = resolver.ResolveAssignment(assignmentExpression.Operator, leftResult, rightResult); |
---|
1351 | ProcessConversionsInBinaryOperatorResult(left, right, rr); |
---|
1352 | return rr; |
---|
1353 | } else { |
---|
1354 | ScanChildren(assignmentExpression); |
---|
1355 | return null; |
---|
1356 | } |
---|
1357 | } |
---|
1358 | |
---|
1359 | ResolveResult IAstVisitor<ResolveResult>.VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression) |
---|
1360 | { |
---|
1361 | if (resolverEnabled) { |
---|
1362 | return resolver.ResolveBaseReference(); |
---|
1363 | } else { |
---|
1364 | ScanChildren(baseReferenceExpression); |
---|
1365 | return null; |
---|
1366 | } |
---|
1367 | } |
---|
1368 | |
---|
1369 | ResolveResult IAstVisitor<ResolveResult>.VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression) |
---|
1370 | { |
---|
1371 | if (resolverEnabled) { |
---|
1372 | Expression left = binaryOperatorExpression.Left; |
---|
1373 | Expression right = binaryOperatorExpression.Right; |
---|
1374 | ResolveResult leftResult = Resolve(left); |
---|
1375 | ResolveResult rightResult = Resolve(right); |
---|
1376 | ResolveResult rr = resolver.ResolveBinaryOperator(binaryOperatorExpression.Operator, leftResult, rightResult); |
---|
1377 | ProcessConversionsInBinaryOperatorResult(left, right, rr); |
---|
1378 | return rr; |
---|
1379 | } else { |
---|
1380 | ScanChildren(binaryOperatorExpression); |
---|
1381 | return null; |
---|
1382 | } |
---|
1383 | } |
---|
1384 | |
---|
1385 | ResolveResult ProcessConversionsInBinaryOperatorResult(Expression left, Expression right, ResolveResult rr) |
---|
1386 | { |
---|
1387 | OperatorResolveResult orr = rr as OperatorResolveResult; |
---|
1388 | if (orr != null && orr.Operands.Count == 2) { |
---|
1389 | ProcessConversionResult(left, orr.Operands[0] as ConversionResolveResult); |
---|
1390 | ProcessConversionResult(right, orr.Operands[1] as ConversionResolveResult); |
---|
1391 | } else { |
---|
1392 | InvocationResolveResult irr = rr as InvocationResolveResult; |
---|
1393 | if (irr != null && irr.Arguments.Count == 2) { |
---|
1394 | ProcessConversionResult(left, irr.Arguments[0] as ConversionResolveResult); |
---|
1395 | ProcessConversionResult(right, irr.Arguments[1] as ConversionResolveResult); |
---|
1396 | } |
---|
1397 | } |
---|
1398 | return rr; |
---|
1399 | } |
---|
1400 | |
---|
1401 | ResolveResult IAstVisitor<ResolveResult>.VisitCastExpression(CastExpression castExpression) |
---|
1402 | { |
---|
1403 | if (resolverEnabled) { |
---|
1404 | var targetType = ResolveType(castExpression.Type); |
---|
1405 | var expr = castExpression.Expression; |
---|
1406 | var rr = resolver.ResolveCast(targetType, Resolve(expr)); |
---|
1407 | var crr = rr as ConversionResolveResult; |
---|
1408 | if (crr != null) { |
---|
1409 | Debug.Assert(!(crr is CastResolveResult)); |
---|
1410 | ProcessConversion(expr, crr.Input, crr.Conversion, targetType); |
---|
1411 | rr = new CastResolveResult(crr); |
---|
1412 | } |
---|
1413 | return rr; |
---|
1414 | } else { |
---|
1415 | ScanChildren(castExpression); |
---|
1416 | return null; |
---|
1417 | } |
---|
1418 | } |
---|
1419 | |
---|
1420 | ResolveResult IAstVisitor<ResolveResult>.VisitConditionalExpression(ConditionalExpression conditionalExpression) |
---|
1421 | { |
---|
1422 | if (resolverEnabled) { |
---|
1423 | Expression condition = conditionalExpression.Condition; |
---|
1424 | Expression trueExpr = conditionalExpression.TrueExpression; |
---|
1425 | Expression falseExpr = conditionalExpression.FalseExpression; |
---|
1426 | |
---|
1427 | ResolveResult rr = resolver.ResolveConditional(Resolve(condition), Resolve(trueExpr), Resolve(falseExpr)); |
---|
1428 | OperatorResolveResult corr = rr as OperatorResolveResult; |
---|
1429 | if (corr != null && corr.Operands.Count == 3) { |
---|
1430 | ProcessConversionResult(condition, corr.Operands[0] as ConversionResolveResult); |
---|
1431 | ProcessConversionResult(trueExpr, corr.Operands[1] as ConversionResolveResult); |
---|
1432 | ProcessConversionResult(falseExpr, corr.Operands[2] as ConversionResolveResult); |
---|
1433 | } |
---|
1434 | return rr; |
---|
1435 | } else { |
---|
1436 | ScanChildren(conditionalExpression); |
---|
1437 | return null; |
---|
1438 | } |
---|
1439 | } |
---|
1440 | |
---|
1441 | ResolveResult IAstVisitor<ResolveResult>.VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression) |
---|
1442 | { |
---|
1443 | if (resolverEnabled) { |
---|
1444 | return resolver.ResolveDefaultValue(ResolveType(defaultValueExpression.Type)); |
---|
1445 | } else { |
---|
1446 | ScanChildren(defaultValueExpression); |
---|
1447 | return null; |
---|
1448 | } |
---|
1449 | } |
---|
1450 | |
---|
1451 | ResolveResult IAstVisitor<ResolveResult>.VisitDirectionExpression(DirectionExpression directionExpression) |
---|
1452 | { |
---|
1453 | if (resolverEnabled) { |
---|
1454 | ResolveResult rr = Resolve(directionExpression.Expression); |
---|
1455 | return new ByReferenceResolveResult(rr, directionExpression.FieldDirection == FieldDirection.Out); |
---|
1456 | } else { |
---|
1457 | ScanChildren(directionExpression); |
---|
1458 | return null; |
---|
1459 | } |
---|
1460 | } |
---|
1461 | |
---|
1462 | ResolveResult IAstVisitor<ResolveResult>.VisitIndexerExpression(IndexerExpression indexerExpression) |
---|
1463 | { |
---|
1464 | if (resolverEnabled || NeedsResolvingDueToNamedArguments(indexerExpression)) { |
---|
1465 | Expression target = indexerExpression.Target; |
---|
1466 | ResolveResult targetResult = Resolve(target); |
---|
1467 | string[] argumentNames; |
---|
1468 | ResolveResult[] arguments = GetArguments(indexerExpression.Arguments, out argumentNames); |
---|
1469 | ResolveResult rr = resolver.ResolveIndexer(targetResult, arguments, argumentNames); |
---|
1470 | ArrayAccessResolveResult aarr = rr as ArrayAccessResolveResult; |
---|
1471 | if (aarr != null) { |
---|
1472 | MarkUnknownNamedArguments(indexerExpression.Arguments); |
---|
1473 | ProcessConversionResults(indexerExpression.Arguments, aarr.Indexes); |
---|
1474 | } else { |
---|
1475 | ProcessInvocationResult(target, indexerExpression.Arguments, rr); |
---|
1476 | } |
---|
1477 | return rr; |
---|
1478 | } else { |
---|
1479 | ScanChildren(indexerExpression); |
---|
1480 | return null; |
---|
1481 | } |
---|
1482 | } |
---|
1483 | |
---|
1484 | ResolveResult IAstVisitor<ResolveResult>.VisitIsExpression(IsExpression isExpression) |
---|
1485 | { |
---|
1486 | if (resolverEnabled) { |
---|
1487 | ResolveResult input = Resolve(isExpression.Expression); |
---|
1488 | IType targetType = ResolveType(isExpression.Type); |
---|
1489 | IType booleanType = resolver.Compilation.FindType(KnownTypeCode.Boolean); |
---|
1490 | return new TypeIsResolveResult(input, targetType, booleanType); |
---|
1491 | } else { |
---|
1492 | ScanChildren(isExpression); |
---|
1493 | return null; |
---|
1494 | } |
---|
1495 | } |
---|
1496 | |
---|
1497 | // NamedArgumentExpression is "identifier: Expression" |
---|
1498 | ResolveResult IAstVisitor<ResolveResult>.VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression) |
---|
1499 | { |
---|
1500 | // The parent expression takes care of handling NamedArgumentExpressions |
---|
1501 | // by calling GetArguments(). |
---|
1502 | // This method gets called only when scanning, or when the named argument is used |
---|
1503 | // in an invalid context. |
---|
1504 | if (resolverEnabled) { |
---|
1505 | return new NamedArgumentResolveResult(namedArgumentExpression.Name, Resolve(namedArgumentExpression.Expression)); |
---|
1506 | } else { |
---|
1507 | Scan(namedArgumentExpression.Expression); |
---|
1508 | return null; |
---|
1509 | } |
---|
1510 | } |
---|
1511 | |
---|
1512 | // NamedExpression is "identifier = Expression" in object initializers and attributes |
---|
1513 | ResolveResult IAstVisitor<ResolveResult>.VisitNamedExpression(NamedExpression namedExpression) |
---|
1514 | { |
---|
1515 | // The parent expression takes care of handling NamedExpression |
---|
1516 | // by calling HandleObjectInitializer() or HandleNamedExpression(). |
---|
1517 | // This method gets called only when scanning, or when the named expression is used |
---|
1518 | // in an invalid context. |
---|
1519 | ScanChildren(namedExpression); |
---|
1520 | return null; |
---|
1521 | } |
---|
1522 | |
---|
1523 | void HandleNamedExpression(NamedExpression namedExpression, List<ResolveResult> initializerStatements) |
---|
1524 | { |
---|
1525 | StoreCurrentState(namedExpression); |
---|
1526 | Expression rhs = namedExpression.Expression; |
---|
1527 | ResolveResult lhsRR = resolver.ResolveIdentifierInObjectInitializer(namedExpression.Name); |
---|
1528 | if (rhs is ArrayInitializerExpression) { |
---|
1529 | HandleObjectInitializer(lhsRR, (ArrayInitializerExpression)rhs, initializerStatements); |
---|
1530 | } else { |
---|
1531 | var rhsRR = Resolve(rhs); |
---|
1532 | var rr = resolver.ResolveAssignment(AssignmentOperatorType.Assign, lhsRR, rhsRR) as OperatorResolveResult; |
---|
1533 | if (rr != null) { |
---|
1534 | ProcessConversionResult(rhs, rr.Operands[1] as ConversionResolveResult); |
---|
1535 | initializerStatements.Add(rr); |
---|
1536 | } |
---|
1537 | } |
---|
1538 | StoreResult(namedExpression, lhsRR); |
---|
1539 | } |
---|
1540 | |
---|
1541 | ResolveResult IAstVisitor<ResolveResult>.VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression) |
---|
1542 | { |
---|
1543 | return resolver.ResolvePrimitive(null); |
---|
1544 | } |
---|
1545 | |
---|
1546 | ResolveResult IAstVisitor<ResolveResult>.VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression) |
---|
1547 | { |
---|
1548 | var typeResolveResult = Resolve(objectCreateExpression.Type); |
---|
1549 | if (typeResolveResult.IsError) { |
---|
1550 | ScanChildren (objectCreateExpression); |
---|
1551 | return typeResolveResult; |
---|
1552 | } |
---|
1553 | IType type = typeResolveResult.Type; |
---|
1554 | |
---|
1555 | List<ResolveResult> initializerStatements = null; |
---|
1556 | var initializer = objectCreateExpression.Initializer; |
---|
1557 | if (!initializer.IsNull) { |
---|
1558 | initializerStatements = new List<ResolveResult>(); |
---|
1559 | HandleObjectInitializer(new InitializedObjectResolveResult(type), initializer, initializerStatements); |
---|
1560 | } |
---|
1561 | |
---|
1562 | string[] argumentNames; |
---|
1563 | ResolveResult[] arguments = GetArguments(objectCreateExpression.Arguments, out argumentNames); |
---|
1564 | |
---|
1565 | ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames, false, initializerStatements); |
---|
1566 | if (arguments.Length == 1 && rr.Type.Kind == TypeKind.Delegate) { |
---|
1567 | MarkUnknownNamedArguments(objectCreateExpression.Arguments); |
---|
1568 | // Apply conversion to argument if it directly wraps the argument |
---|
1569 | // (but not when creating a delegate from a delegate, as then there would be a MGRR for .Invoke in between) |
---|
1570 | // This is necessary for lambda type inference. |
---|
1571 | var crr = rr as ConversionResolveResult; |
---|
1572 | if (crr != null) { |
---|
1573 | if (objectCreateExpression.Arguments.Count == 1) |
---|
1574 | ProcessConversionResult(objectCreateExpression.Arguments.Single(), crr); |
---|
1575 | |
---|
1576 | // wrap the result so that the delegate creation is not handled as a reference |
---|
1577 | // to the target method - otherwise FindReferencedEntities would produce two results for |
---|
1578 | // the same delegate creation. |
---|
1579 | return new CastResolveResult(crr); |
---|
1580 | } else { |
---|
1581 | return rr; |
---|
1582 | } |
---|
1583 | } else { |
---|
1584 | // process conversions in all other cases |
---|
1585 | ProcessInvocationResult(null, objectCreateExpression.Arguments, rr); |
---|
1586 | return rr; |
---|
1587 | } |
---|
1588 | } |
---|
1589 | |
---|
1590 | void HandleObjectInitializer(ResolveResult initializedObject, ArrayInitializerExpression initializer, List<ResolveResult> initializerStatements) |
---|
1591 | { |
---|
1592 | StoreCurrentState(initializer); |
---|
1593 | resolver = resolver.PushObjectInitializer(initializedObject); |
---|
1594 | foreach (Expression element in initializer.Elements) { |
---|
1595 | ArrayInitializerExpression aie = element as ArrayInitializerExpression; |
---|
1596 | if (aie != null) { |
---|
1597 | StoreCurrentState(aie); |
---|
1598 | // constructor argument list in collection initializer |
---|
1599 | ResolveResult[] addArguments = new ResolveResult[aie.Elements.Count]; |
---|
1600 | int i = 0; |
---|
1601 | foreach (var addArgument in aie.Elements) { |
---|
1602 | addArguments[i++] = Resolve(addArgument); |
---|
1603 | } |
---|
1604 | MemberLookup memberLookup = resolver.CreateMemberLookup(); |
---|
1605 | var addRR = memberLookup.Lookup(initializedObject, "Add", EmptyList<IType>.Instance, true); |
---|
1606 | var mgrr = addRR as MethodGroupResolveResult; |
---|
1607 | if (mgrr != null) { |
---|
1608 | OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Compilation, addArguments, null, false, false, false, resolver.CheckForOverflow, resolver.conversions); |
---|
1609 | var invocationRR = or.CreateResolveResult(initializedObject); |
---|
1610 | StoreResult(aie, invocationRR); |
---|
1611 | ProcessInvocationResult(null, aie.Elements, invocationRR); |
---|
1612 | initializerStatements.Add(invocationRR); |
---|
1613 | } else { |
---|
1614 | StoreResult(aie, addRR); |
---|
1615 | } |
---|
1616 | } else if (element is NamedExpression) { |
---|
1617 | HandleNamedExpression((NamedExpression)element, initializerStatements); |
---|
1618 | } else { |
---|
1619 | // unknown kind of expression |
---|
1620 | Scan(element); |
---|
1621 | } |
---|
1622 | } |
---|
1623 | resolver = resolver.PopObjectInitializer(); |
---|
1624 | StoreResult(initializer, voidResult); |
---|
1625 | } |
---|
1626 | |
---|
1627 | ResolveResult IAstVisitor<ResolveResult>.VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression) |
---|
1628 | { |
---|
1629 | if (resolverEnabled) { |
---|
1630 | return Resolve(parenthesizedExpression.Expression); |
---|
1631 | } else { |
---|
1632 | Scan(parenthesizedExpression.Expression); |
---|
1633 | return null; |
---|
1634 | } |
---|
1635 | } |
---|
1636 | |
---|
1637 | ResolveResult IAstVisitor<ResolveResult>.VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression) |
---|
1638 | { |
---|
1639 | if (resolverEnabled) { |
---|
1640 | ResolveResult target = Resolve(pointerReferenceExpression.Target); |
---|
1641 | ResolveResult deferencedTarget = resolver.ResolveUnaryOperator(UnaryOperatorType.Dereference, target); |
---|
1642 | List<IType> typeArguments = new List<IType>(); |
---|
1643 | foreach (AstType typeArgument in pointerReferenceExpression.TypeArguments) { |
---|
1644 | typeArguments.Add(ResolveType(typeArgument)); |
---|
1645 | } |
---|
1646 | return resolver.ResolveMemberAccess(deferencedTarget, pointerReferenceExpression.MemberName, |
---|
1647 | typeArguments, |
---|
1648 | GetNameLookupMode(pointerReferenceExpression)); |
---|
1649 | } else { |
---|
1650 | ScanChildren(pointerReferenceExpression); |
---|
1651 | return null; |
---|
1652 | } |
---|
1653 | } |
---|
1654 | |
---|
1655 | ResolveResult IAstVisitor<ResolveResult>.VisitPrimitiveExpression(PrimitiveExpression primitiveExpression) |
---|
1656 | { |
---|
1657 | return resolver.ResolvePrimitive(primitiveExpression.Value); |
---|
1658 | } |
---|
1659 | |
---|
1660 | ResolveResult IAstVisitor<ResolveResult>.VisitSizeOfExpression(SizeOfExpression sizeOfExpression) |
---|
1661 | { |
---|
1662 | return resolver.ResolveSizeOf(ResolveType(sizeOfExpression.Type)); |
---|
1663 | } |
---|
1664 | |
---|
1665 | ResolveResult IAstVisitor<ResolveResult>.VisitStackAllocExpression(StackAllocExpression stackAllocExpression) |
---|
1666 | { |
---|
1667 | ResolveAndProcessConversion(stackAllocExpression.CountExpression, resolver.Compilation.FindType(KnownTypeCode.Int32)); |
---|
1668 | return new ResolveResult(new PointerType(ResolveType(stackAllocExpression.Type))); |
---|
1669 | } |
---|
1670 | |
---|
1671 | ResolveResult IAstVisitor<ResolveResult>.VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression) |
---|
1672 | { |
---|
1673 | return resolver.ResolveThisReference(); |
---|
1674 | } |
---|
1675 | |
---|
1676 | ResolveResult IAstVisitor<ResolveResult>.VisitTypeOfExpression(TypeOfExpression typeOfExpression) |
---|
1677 | { |
---|
1678 | if (resolverEnabled) { |
---|
1679 | return resolver.ResolveTypeOf(ResolveType(typeOfExpression.Type)); |
---|
1680 | } else { |
---|
1681 | Scan(typeOfExpression.Type); |
---|
1682 | return null; |
---|
1683 | } |
---|
1684 | } |
---|
1685 | |
---|
1686 | ResolveResult IAstVisitor<ResolveResult>.VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression) |
---|
1687 | { |
---|
1688 | if (resolverEnabled) { |
---|
1689 | return Resolve(typeReferenceExpression.Type).ShallowClone(); |
---|
1690 | } else { |
---|
1691 | Scan(typeReferenceExpression.Type); |
---|
1692 | return null; |
---|
1693 | } |
---|
1694 | } |
---|
1695 | |
---|
1696 | ResolveResult IAstVisitor<ResolveResult>.VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression) |
---|
1697 | { |
---|
1698 | if (resolverEnabled) { |
---|
1699 | Expression expr = unaryOperatorExpression.Expression; |
---|
1700 | ResolveResult input = Resolve(expr); |
---|
1701 | ITypeDefinition inputTypeDef = input.Type.GetDefinition(); |
---|
1702 | if (input.IsCompileTimeConstant && expr is PrimitiveExpression && inputTypeDef != null) { |
---|
1703 | // Special cases for int.MinValue and long.MinValue |
---|
1704 | if (inputTypeDef.KnownTypeCode == KnownTypeCode.UInt32 && 2147483648.Equals(input.ConstantValue)) { |
---|
1705 | return new ConstantResolveResult(resolver.Compilation.FindType(KnownTypeCode.Int32), -2147483648); |
---|
1706 | } else if (inputTypeDef.KnownTypeCode == KnownTypeCode.UInt64 && 9223372036854775808.Equals(input.ConstantValue)) { |
---|
1707 | return new ConstantResolveResult(resolver.Compilation.FindType(KnownTypeCode.Int64), -9223372036854775808); |
---|
1708 | } |
---|
1709 | } |
---|
1710 | ResolveResult rr = resolver.ResolveUnaryOperator(unaryOperatorExpression.Operator, input); |
---|
1711 | OperatorResolveResult uorr = rr as OperatorResolveResult; |
---|
1712 | if (uorr != null && uorr.Operands.Count == 1) { |
---|
1713 | ProcessConversionResult(expr, uorr.Operands[0] as ConversionResolveResult); |
---|
1714 | } else { |
---|
1715 | InvocationResolveResult irr = rr as InvocationResolveResult; |
---|
1716 | if (irr != null && irr.Arguments.Count == 1) { |
---|
1717 | ProcessConversionResult(expr, irr.Arguments[0] as ConversionResolveResult); |
---|
1718 | } |
---|
1719 | } |
---|
1720 | return rr; |
---|
1721 | } else { |
---|
1722 | ScanChildren(unaryOperatorExpression); |
---|
1723 | return null; |
---|
1724 | } |
---|
1725 | } |
---|
1726 | |
---|
1727 | ResolveResult IAstVisitor<ResolveResult>.VisitUndocumentedExpression(UndocumentedExpression undocumentedExpression) |
---|
1728 | { |
---|
1729 | ScanChildren(undocumentedExpression); |
---|
1730 | IType resultType; |
---|
1731 | switch (undocumentedExpression.UndocumentedExpressionType) { |
---|
1732 | case UndocumentedExpressionType.ArgListAccess: |
---|
1733 | case UndocumentedExpressionType.ArgList: |
---|
1734 | resultType = resolver.Compilation.FindType(typeof(RuntimeArgumentHandle)); |
---|
1735 | break; |
---|
1736 | case UndocumentedExpressionType.RefValue: |
---|
1737 | var tre = undocumentedExpression.Arguments.ElementAtOrDefault(1) as TypeReferenceExpression; |
---|
1738 | if (tre != null) |
---|
1739 | resultType = ResolveType(tre.Type); |
---|
1740 | else |
---|
1741 | resultType = SpecialType.UnknownType; |
---|
1742 | break; |
---|
1743 | case UndocumentedExpressionType.RefType: |
---|
1744 | resultType = resolver.Compilation.FindType(KnownTypeCode.Type); |
---|
1745 | break; |
---|
1746 | case UndocumentedExpressionType.MakeRef: |
---|
1747 | resultType = resolver.Compilation.FindType(typeof(TypedReference)); |
---|
1748 | break; |
---|
1749 | default: |
---|
1750 | throw new InvalidOperationException("Invalid value for UndocumentedExpressionType"); |
---|
1751 | } |
---|
1752 | return new ResolveResult(resultType); |
---|
1753 | } |
---|
1754 | #endregion |
---|
1755 | |
---|
1756 | #region Visit Identifier/MemberReference/Invocation-Expression |
---|
1757 | // IdentifierExpression, MemberReferenceExpression and InvocationExpression |
---|
1758 | // are grouped together because they have to work together for |
---|
1759 | // "7.6.4.1 Identical simple names and type names" support |
---|
1760 | List<IType> ResolveTypeArguments(IEnumerable<AstType> typeArguments) |
---|
1761 | { |
---|
1762 | List<IType> result = new List<IType>(); |
---|
1763 | foreach (AstType typeArgument in typeArguments) { |
---|
1764 | result.Add(ResolveType(typeArgument)); |
---|
1765 | } |
---|
1766 | return result; |
---|
1767 | } |
---|
1768 | |
---|
1769 | /// <summary> |
---|
1770 | /// Gets and resolves the arguments; unpacking any NamedArgumentExpressions. |
---|
1771 | /// </summary> |
---|
1772 | /// <remarks> |
---|
1773 | /// Callers of GetArguments must also call either ProcessConversionsInInvocation or MarkUnknownNamedArguments |
---|
1774 | /// to ensure the named arguments get resolved. |
---|
1775 | /// Also, as named arguments get resolved by the parent node, the parent node must not scan |
---|
1776 | /// into the argument list without being resolved - see NeedsResolvingDueToNamedArguments(). |
---|
1777 | /// </remarks> |
---|
1778 | ResolveResult[] GetArguments(IEnumerable<Expression> argumentExpressions, out string[] argumentNames) |
---|
1779 | { |
---|
1780 | argumentNames = null; |
---|
1781 | ResolveResult[] arguments = new ResolveResult[argumentExpressions.Count()]; |
---|
1782 | int i = 0; |
---|
1783 | foreach (AstNode argument in argumentExpressions) { |
---|
1784 | NamedArgumentExpression nae = argument as NamedArgumentExpression; |
---|
1785 | AstNode argumentValue; |
---|
1786 | if (nae != null) { |
---|
1787 | if (argumentNames == null) |
---|
1788 | argumentNames = new string[arguments.Length]; |
---|
1789 | argumentNames[i] = nae.Name; |
---|
1790 | argumentValue = nae.Expression; |
---|
1791 | } else { |
---|
1792 | argumentValue = argument; |
---|
1793 | } |
---|
1794 | arguments[i++] = Resolve(argumentValue); |
---|
1795 | } |
---|
1796 | return arguments; |
---|
1797 | } |
---|
1798 | |
---|
1799 | bool NeedsResolvingDueToNamedArguments(Expression nodeWithArguments) |
---|
1800 | { |
---|
1801 | for (AstNode child = nodeWithArguments.FirstChild; child != null; child = child.NextSibling) { |
---|
1802 | if (child is NamedArgumentExpression) |
---|
1803 | return true; |
---|
1804 | } |
---|
1805 | return false; |
---|
1806 | } |
---|
1807 | |
---|
1808 | static NameLookupMode GetNameLookupMode(Expression expr) |
---|
1809 | { |
---|
1810 | InvocationExpression ie = expr.Parent as InvocationExpression; |
---|
1811 | if (ie != null && ie.Target == expr) |
---|
1812 | return NameLookupMode.InvocationTarget; |
---|
1813 | else |
---|
1814 | return NameLookupMode.Expression; |
---|
1815 | } |
---|
1816 | |
---|
1817 | /// <summary> |
---|
1818 | /// Gets whether 'rr' is considered a static access on the target identifier. |
---|
1819 | /// </summary> |
---|
1820 | /// <param name="rr">Resolve Result of the MemberReferenceExpression</param> |
---|
1821 | /// <param name="invocationRR">Resolve Result of the InvocationExpression</param> |
---|
1822 | bool IsStaticResult(ResolveResult rr, ResolveResult invocationRR) |
---|
1823 | { |
---|
1824 | if (rr is TypeResolveResult) |
---|
1825 | return true; |
---|
1826 | MemberResolveResult mrr = (rr is MethodGroupResolveResult ? invocationRR : rr) as MemberResolveResult; |
---|
1827 | return mrr != null && mrr.Member.IsStatic; |
---|
1828 | } |
---|
1829 | |
---|
1830 | ResolveResult IAstVisitor<ResolveResult>.VisitIdentifierExpression(IdentifierExpression identifierExpression) |
---|
1831 | { |
---|
1832 | // Note: this method is not called when it occurs in a situation where an ambiguity between |
---|
1833 | // simple names and type names might occur. |
---|
1834 | if (resolverEnabled) { |
---|
1835 | var typeArguments = ResolveTypeArguments(identifierExpression.TypeArguments); |
---|
1836 | var lookupMode = GetNameLookupMode(identifierExpression); |
---|
1837 | return resolver.LookupSimpleNameOrTypeName( |
---|
1838 | identifierExpression.Identifier, typeArguments, lookupMode); |
---|
1839 | } else { |
---|
1840 | ScanChildren(identifierExpression); |
---|
1841 | return null; |
---|
1842 | } |
---|
1843 | } |
---|
1844 | |
---|
1845 | ResolveResult IAstVisitor<ResolveResult>.VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression) |
---|
1846 | { |
---|
1847 | // target = Resolve(identifierExpression = memberReferenceExpression.Target) |
---|
1848 | // trr = ResolveType(identifierExpression) |
---|
1849 | // rr = Resolve(memberReferenceExpression) |
---|
1850 | |
---|
1851 | IdentifierExpression identifierExpression = memberReferenceExpression.Target as IdentifierExpression; |
---|
1852 | if (identifierExpression != null && identifierExpression.TypeArguments.Count == 0) { |
---|
1853 | // Special handling for §7.6.4.1 Identicial simple names and type names |
---|
1854 | StoreCurrentState(identifierExpression); |
---|
1855 | ResolveResult target = resolver.ResolveSimpleName(identifierExpression.Identifier, EmptyList<IType>.Instance); |
---|
1856 | TypeResolveResult trr; |
---|
1857 | if (resolver.IsVariableReferenceWithSameType(target, identifierExpression.Identifier, out trr)) { |
---|
1858 | // It's ambiguous |
---|
1859 | ResolveResult rr = ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression); |
---|
1860 | ResolveResult simpleNameRR = IsStaticResult(rr, null) ? trr : target; |
---|
1861 | Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}", identifierExpression, simpleNameRR); |
---|
1862 | StoreResult(identifierExpression, simpleNameRR); |
---|
1863 | return rr; |
---|
1864 | } else { |
---|
1865 | // It's not ambiguous |
---|
1866 | Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, target); |
---|
1867 | StoreResult(identifierExpression, target); |
---|
1868 | return ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression); |
---|
1869 | } |
---|
1870 | } else { |
---|
1871 | // Regular code path |
---|
1872 | if (resolverEnabled) { |
---|
1873 | ResolveResult target = Resolve(memberReferenceExpression.Target); |
---|
1874 | return ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression); |
---|
1875 | } else { |
---|
1876 | ScanChildren(memberReferenceExpression); |
---|
1877 | return null; |
---|
1878 | } |
---|
1879 | } |
---|
1880 | } |
---|
1881 | |
---|
1882 | ResolveResult ResolveMemberReferenceOnGivenTarget(ResolveResult target, MemberReferenceExpression memberReferenceExpression) |
---|
1883 | { |
---|
1884 | var typeArguments = ResolveTypeArguments(memberReferenceExpression.TypeArguments); |
---|
1885 | return resolver.ResolveMemberAccess( |
---|
1886 | target, memberReferenceExpression.MemberName, typeArguments, |
---|
1887 | GetNameLookupMode(memberReferenceExpression)); |
---|
1888 | } |
---|
1889 | |
---|
1890 | ResolveResult IAstVisitor<ResolveResult>.VisitInvocationExpression(InvocationExpression invocationExpression) |
---|
1891 | { |
---|
1892 | // rr = Resolve(invocationExpression) |
---|
1893 | // target = Resolve(memberReferenceExpression = invocationExpression.Target) |
---|
1894 | // idRR = Resolve(identifierExpression = memberReferenceExpression.Target) |
---|
1895 | // trr = ResolveType(identifierExpression) |
---|
1896 | |
---|
1897 | MemberReferenceExpression mre = invocationExpression.Target as MemberReferenceExpression; |
---|
1898 | IdentifierExpression identifierExpression = mre != null ? mre.Target as IdentifierExpression : null; |
---|
1899 | if (identifierExpression != null && identifierExpression.TypeArguments.Count == 0) { |
---|
1900 | // Special handling for §7.6.4.1 Identicial simple names and type names |
---|
1901 | |
---|
1902 | StoreCurrentState(identifierExpression); |
---|
1903 | StoreCurrentState(mre); |
---|
1904 | |
---|
1905 | ResolveResult idRR = resolver.ResolveSimpleName(identifierExpression.Identifier, EmptyList<IType>.Instance); |
---|
1906 | ResolveResult target = ResolveMemberReferenceOnGivenTarget(idRR, mre); |
---|
1907 | Log.WriteLine("Member reference '{0}' on potentially-ambiguous simple-name was resolved to {1}", mre, target); |
---|
1908 | StoreResult(mre, target); |
---|
1909 | TypeResolveResult trr; |
---|
1910 | if (resolver.IsVariableReferenceWithSameType(idRR, identifierExpression.Identifier, out trr)) { |
---|
1911 | // It's ambiguous |
---|
1912 | ResolveResult rr = ResolveInvocationOnGivenTarget(target, invocationExpression); |
---|
1913 | ResolveResult simpleNameRR = IsStaticResult(target, rr) ? trr : idRR; |
---|
1914 | Log.WriteLine("Ambiguous simple name '{0}' was resolved to {1}", |
---|
1915 | identifierExpression, simpleNameRR); |
---|
1916 | StoreResult(identifierExpression, simpleNameRR); |
---|
1917 | return rr; |
---|
1918 | } else { |
---|
1919 | // It's not ambiguous |
---|
1920 | Log.WriteLine("Simple name '{0}' was resolved to {1}", identifierExpression, idRR); |
---|
1921 | StoreResult(identifierExpression, idRR); |
---|
1922 | return ResolveInvocationOnGivenTarget(target, invocationExpression); |
---|
1923 | } |
---|
1924 | } else { |
---|
1925 | // Regular code path |
---|
1926 | if (resolverEnabled || NeedsResolvingDueToNamedArguments(invocationExpression)) { |
---|
1927 | ResolveResult target = Resolve(invocationExpression.Target); |
---|
1928 | return ResolveInvocationOnGivenTarget(target, invocationExpression); |
---|
1929 | } else { |
---|
1930 | ScanChildren(invocationExpression); |
---|
1931 | return null; |
---|
1932 | } |
---|
1933 | } |
---|
1934 | } |
---|
1935 | |
---|
1936 | ResolveResult ResolveInvocationOnGivenTarget(ResolveResult target, InvocationExpression invocationExpression) |
---|
1937 | { |
---|
1938 | string[] argumentNames; |
---|
1939 | ResolveResult[] arguments = GetArguments(invocationExpression.Arguments, out argumentNames); |
---|
1940 | ResolveResult rr = resolver.ResolveInvocation(target, arguments, argumentNames); |
---|
1941 | ProcessInvocationResult(invocationExpression.Target, invocationExpression.Arguments, rr); |
---|
1942 | return rr; |
---|
1943 | } |
---|
1944 | #endregion |
---|
1945 | |
---|
1946 | #region Lamdbas / Anonymous Functions |
---|
1947 | ResolveResult IAstVisitor<ResolveResult>.VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression) |
---|
1948 | { |
---|
1949 | return HandleExplicitlyTypedLambda( |
---|
1950 | anonymousMethodExpression.Parameters, anonymousMethodExpression.Body, |
---|
1951 | isAnonymousMethod: true, |
---|
1952 | hasParameterList: anonymousMethodExpression.HasParameterList, |
---|
1953 | isAsync: anonymousMethodExpression.IsAsync); |
---|
1954 | } |
---|
1955 | |
---|
1956 | ResolveResult IAstVisitor<ResolveResult>.VisitLambdaExpression(LambdaExpression lambdaExpression) |
---|
1957 | { |
---|
1958 | bool isExplicitlyTyped = false; |
---|
1959 | bool isImplicitlyTyped = false; |
---|
1960 | foreach (var p in lambdaExpression.Parameters) { |
---|
1961 | isImplicitlyTyped |= p.Type.IsNull; |
---|
1962 | isExplicitlyTyped |= !p.Type.IsNull; |
---|
1963 | } |
---|
1964 | if (isExplicitlyTyped || !isImplicitlyTyped) { |
---|
1965 | return HandleExplicitlyTypedLambda( |
---|
1966 | lambdaExpression.Parameters, lambdaExpression.Body, |
---|
1967 | isAnonymousMethod: false, hasParameterList: true, isAsync: lambdaExpression.IsAsync); |
---|
1968 | } else { |
---|
1969 | return new ImplicitlyTypedLambda(lambdaExpression, this); |
---|
1970 | } |
---|
1971 | } |
---|
1972 | |
---|
1973 | #region Explicitly typed |
---|
1974 | ExplicitlyTypedLambda HandleExplicitlyTypedLambda( |
---|
1975 | AstNodeCollection<ParameterDeclaration> parameterDeclarations, |
---|
1976 | AstNode body, bool isAnonymousMethod, bool hasParameterList, bool isAsync) |
---|
1977 | { |
---|
1978 | CSharpResolver oldResolver = resolver; |
---|
1979 | List<IParameter> parameters = (hasParameterList || parameterDeclarations.Any()) ? new List<IParameter>() : null; |
---|
1980 | //bool oldIsWithinLambdaExpression = resolver.IsWithinLambdaExpression; |
---|
1981 | resolver = resolver.WithIsWithinLambdaExpression(true); |
---|
1982 | foreach (var pd in parameterDeclarations) { |
---|
1983 | IType type = ResolveType(pd.Type); |
---|
1984 | if (pd.ParameterModifier == ParameterModifier.Ref || pd.ParameterModifier == ParameterModifier.Out) |
---|
1985 | type = new ByReferenceType(type); |
---|
1986 | |
---|
1987 | IParameter p = new DefaultParameter(type, pd.Name, |
---|
1988 | region: MakeRegion(pd), |
---|
1989 | isRef: pd.ParameterModifier == ParameterModifier.Ref, |
---|
1990 | isOut: pd.ParameterModifier == ParameterModifier.Out); |
---|
1991 | // The parameter declaration must be scanned in the current context (without the new parameter) |
---|
1992 | // in order to be consistent with the context in which we resolved pd.Type. |
---|
1993 | StoreCurrentState(pd); |
---|
1994 | StoreResult(pd, new LocalResolveResult(p)); |
---|
1995 | ScanChildren(pd); |
---|
1996 | |
---|
1997 | resolver = resolver.AddVariable(p); |
---|
1998 | parameters.Add(p); |
---|
1999 | } |
---|
2000 | |
---|
2001 | var lambda = new ExplicitlyTypedLambda(parameters, isAnonymousMethod, isAsync, resolver, this, body); |
---|
2002 | |
---|
2003 | // Don't scan the lambda body here - we'll do that later when analyzing the ExplicitlyTypedLambda. |
---|
2004 | |
---|
2005 | resolver = oldResolver; |
---|
2006 | return lambda; |
---|
2007 | } |
---|
2008 | |
---|
2009 | DomRegion MakeRegion(AstNode node) |
---|
2010 | { |
---|
2011 | if (unresolvedFile != null) |
---|
2012 | return new DomRegion(unresolvedFile.FileName, node.StartLocation, node.EndLocation); |
---|
2013 | else |
---|
2014 | return node.GetRegion(); |
---|
2015 | } |
---|
2016 | |
---|
2017 | sealed class ExplicitlyTypedLambda : LambdaBase |
---|
2018 | { |
---|
2019 | readonly IList<IParameter> parameters; |
---|
2020 | readonly bool isAnonymousMethod; |
---|
2021 | readonly bool isAsync; |
---|
2022 | |
---|
2023 | CSharpResolver storedContext; |
---|
2024 | ResolveVisitor visitor; |
---|
2025 | AstNode body; |
---|
2026 | ResolveResult bodyRR; |
---|
2027 | |
---|
2028 | IType inferredReturnType; |
---|
2029 | IList<Expression> returnExpressions; |
---|
2030 | IList<ResolveResult> returnValues; |
---|
2031 | bool isValidAsVoidMethod; |
---|
2032 | bool isEndpointUnreachable; |
---|
2033 | |
---|
2034 | // The actual return type is set when the lambda is applied by the conversion. |
---|
2035 | // For async lambdas, this includes the task type |
---|
2036 | IType actualReturnType; |
---|
2037 | |
---|
2038 | internal override bool IsUndecided { |
---|
2039 | get { return actualReturnType == null; } |
---|
2040 | } |
---|
2041 | |
---|
2042 | internal override AstNode LambdaExpression { |
---|
2043 | get { return body.Parent; } |
---|
2044 | } |
---|
2045 | |
---|
2046 | internal override AstNode BodyExpression { |
---|
2047 | get { return body; } |
---|
2048 | } |
---|
2049 | |
---|
2050 | public override ResolveResult Body { |
---|
2051 | get { |
---|
2052 | if (bodyRR != null) |
---|
2053 | return bodyRR; |
---|
2054 | |
---|
2055 | if (body is Expression) { |
---|
2056 | Analyze(); |
---|
2057 | if (returnValues.Count == 1) { |
---|
2058 | bodyRR = returnValues[0]; |
---|
2059 | if (actualReturnType != null) { |
---|
2060 | IType unpackedActualReturnType = isAsync ? visitor.UnpackTask(actualReturnType) : actualReturnType; |
---|
2061 | if (unpackedActualReturnType.Kind != TypeKind.Void) { |
---|
2062 | var conv = storedContext.conversions.ImplicitConversion(bodyRR, unpackedActualReturnType); |
---|
2063 | if (!conv.IsIdentityConversion) |
---|
2064 | bodyRR = new ConversionResolveResult(unpackedActualReturnType, bodyRR, conv, storedContext.CheckForOverflow); |
---|
2065 | } |
---|
2066 | } |
---|
2067 | return bodyRR; |
---|
2068 | } |
---|
2069 | } |
---|
2070 | return bodyRR = visitor.voidResult; |
---|
2071 | } |
---|
2072 | } |
---|
2073 | |
---|
2074 | public ExplicitlyTypedLambda(IList<IParameter> parameters, bool isAnonymousMethod, bool isAsync, CSharpResolver storedContext, ResolveVisitor visitor, AstNode body) |
---|
2075 | { |
---|
2076 | this.parameters = parameters; |
---|
2077 | this.isAnonymousMethod = isAnonymousMethod; |
---|
2078 | this.isAsync = isAsync; |
---|
2079 | this.storedContext = storedContext; |
---|
2080 | this.visitor = visitor; |
---|
2081 | this.body = body; |
---|
2082 | |
---|
2083 | if (visitor.undecidedLambdas == null) |
---|
2084 | visitor.undecidedLambdas = new List<LambdaBase>(); |
---|
2085 | visitor.undecidedLambdas.Add(this); |
---|
2086 | Log.WriteLine("Added undecided explicitly-typed lambda: " + this.LambdaExpression); |
---|
2087 | } |
---|
2088 | |
---|
2089 | public override IList<IParameter> Parameters { |
---|
2090 | get { |
---|
2091 | return parameters ?? EmptyList<IParameter>.Instance; |
---|
2092 | } |
---|
2093 | } |
---|
2094 | |
---|
2095 | bool Analyze() |
---|
2096 | { |
---|
2097 | // If it's not already analyzed |
---|
2098 | if (inferredReturnType == null) { |
---|
2099 | Log.WriteLine("Analyzing " + this.LambdaExpression + "..."); |
---|
2100 | Log.Indent(); |
---|
2101 | |
---|
2102 | visitor.ResetContext( |
---|
2103 | storedContext, |
---|
2104 | delegate { |
---|
2105 | var oldNavigator = visitor.navigator; |
---|
2106 | visitor.navigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Resolve, oldNavigator); |
---|
2107 | visitor.AnalyzeLambda(body, isAsync, out isValidAsVoidMethod, out isEndpointUnreachable, out inferredReturnType, out returnExpressions, out returnValues); |
---|
2108 | visitor.navigator = oldNavigator; |
---|
2109 | }); |
---|
2110 | Log.Unindent(); |
---|
2111 | Log.WriteLine("Finished analyzing " + this.LambdaExpression); |
---|
2112 | |
---|
2113 | if (inferredReturnType == null) |
---|
2114 | throw new InvalidOperationException("AnalyzeLambda() didn't set inferredReturnType"); |
---|
2115 | } |
---|
2116 | return true; |
---|
2117 | } |
---|
2118 | |
---|
2119 | public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions) |
---|
2120 | { |
---|
2121 | Log.WriteLine("Testing validity of {0} for return-type {1}...", this, returnType); |
---|
2122 | Log.Indent(); |
---|
2123 | bool valid = Analyze() && IsValidLambda(isValidAsVoidMethod, isEndpointUnreachable, isAsync, returnValues, returnType, conversions); |
---|
2124 | Log.Unindent(); |
---|
2125 | Log.WriteLine("{0} is {1} for return-type {2}", this, valid ? "valid" : "invalid", returnType); |
---|
2126 | return new AnonymousFunctionConversion(returnType, this, valid); |
---|
2127 | } |
---|
2128 | |
---|
2129 | public override IType GetInferredReturnType(IType[] parameterTypes) |
---|
2130 | { |
---|
2131 | Analyze(); |
---|
2132 | return inferredReturnType; |
---|
2133 | } |
---|
2134 | |
---|
2135 | public override IType ReturnType { |
---|
2136 | get { |
---|
2137 | return actualReturnType ?? SpecialType.UnknownType; |
---|
2138 | } |
---|
2139 | } |
---|
2140 | |
---|
2141 | public override bool IsImplicitlyTyped { |
---|
2142 | get { return false; } |
---|
2143 | } |
---|
2144 | |
---|
2145 | public override bool IsAsync { |
---|
2146 | get { return isAsync; } |
---|
2147 | } |
---|
2148 | |
---|
2149 | public override bool IsAnonymousMethod { |
---|
2150 | get { return isAnonymousMethod; } |
---|
2151 | } |
---|
2152 | |
---|
2153 | public override bool HasParameterList { |
---|
2154 | get { return parameters != null; } |
---|
2155 | } |
---|
2156 | |
---|
2157 | public override string ToString() |
---|
2158 | { |
---|
2159 | return "[ExplicitlyTypedLambda " + this.LambdaExpression + "]"; |
---|
2160 | } |
---|
2161 | |
---|
2162 | public void ApplyReturnType(ResolveVisitor parentVisitor, IType returnType) |
---|
2163 | { |
---|
2164 | if (returnType == null) |
---|
2165 | throw new ArgumentNullException("returnType"); |
---|
2166 | if (parentVisitor != visitor) { |
---|
2167 | // Explicitly typed lambdas do not use a nested visitor |
---|
2168 | throw new InvalidOperationException(); |
---|
2169 | } |
---|
2170 | if (actualReturnType != null) { |
---|
2171 | if (actualReturnType.Equals(returnType)) |
---|
2172 | return; // return type already set |
---|
2173 | throw new InvalidOperationException("inconsistent return types for explicitly-typed lambda"); |
---|
2174 | } |
---|
2175 | actualReturnType = returnType; |
---|
2176 | visitor.undecidedLambdas.Remove(this); |
---|
2177 | Analyze(); |
---|
2178 | IType unpackedReturnType = isAsync ? visitor.UnpackTask(returnType) : returnType; |
---|
2179 | Log.WriteLine("Applying return type {0} to explicitly-typed lambda {1}", unpackedReturnType, this.LambdaExpression); |
---|
2180 | if (unpackedReturnType.Kind != TypeKind.Void || body is BlockStatement) { |
---|
2181 | for (int i = 0; i < returnExpressions.Count; i++) { |
---|
2182 | visitor.ProcessConversion(returnExpressions[i], returnValues[i], unpackedReturnType); |
---|
2183 | } |
---|
2184 | } |
---|
2185 | } |
---|
2186 | |
---|
2187 | internal override void EnforceMerge(ResolveVisitor parentVisitor) |
---|
2188 | { |
---|
2189 | ApplyReturnType(parentVisitor, SpecialType.UnknownType); |
---|
2190 | } |
---|
2191 | } |
---|
2192 | #endregion |
---|
2193 | |
---|
2194 | #region Implicitly typed |
---|
2195 | // Implicitly-typed lambdas are really complex, as the lambda depends on the target type (the delegate to which |
---|
2196 | // the lambda is converted), but figuring out the target type might involve overload resolution (for method |
---|
2197 | // calls in which the lambda is used as argument), which requires knowledge about the lamdba. |
---|
2198 | // |
---|
2199 | // The implementation in NRefactory works like this: |
---|
2200 | // 1. The lambda resolves to a ImplicitlyTypedLambda (derived from LambdaResolveResult). |
---|
2201 | // The lambda body is not resolved yet (one of the few places where ResolveVisitor |
---|
2202 | // deviates from the usual depth-first AST traversal). |
---|
2203 | // 2. The parent statement is resolved as usual. This might require analyzing the lambda in detail (for example |
---|
2204 | // as part of overload resolution). Such analysis happens using LambdaResolveResult.IsValid, where the caller |
---|
2205 | // (i.e. the overload resolution algorithm) supplies the parameter types to the lambda body. For every IsValid() |
---|
2206 | // call, a nested LambdaTypeHypothesis is constructed for analyzing the lambda using the supplied type assignment. |
---|
2207 | // Multiple IsValid() calls may use several LambdaTypeHypothesis instances, one for each set of parameter types. |
---|
2208 | // 3. When the resolver reports the conversions that occurred as part of the parent statement (as with any |
---|
2209 | // conversions), the results from the LambdaTypeHypothesis corresponding to the actually chosen |
---|
2210 | // conversion are merged into the main resolver. |
---|
2211 | // 4. LambdaResolveResult.Body is set to the main resolve result from the chosen nested resolver. I think this |
---|
2212 | // is the only place where NRefactory is mutating a ResolveResult (normally all resolve results are immutable). |
---|
2213 | // As this step is guaranteed to occur before the resolver returns the LamdbaResolveResult to user code, the |
---|
2214 | // mutation shouldn't cause any problems. |
---|
2215 | sealed class ImplicitlyTypedLambda : LambdaBase |
---|
2216 | { |
---|
2217 | readonly LambdaExpression lambda; |
---|
2218 | readonly QuerySelectClause selectClause; |
---|
2219 | |
---|
2220 | readonly CSharpResolver storedContext; |
---|
2221 | readonly CSharpUnresolvedFile unresolvedFile; |
---|
2222 | readonly List<LambdaTypeHypothesis> hypotheses = new List<LambdaTypeHypothesis>(); |
---|
2223 | internal IList<IParameter> parameters = new List<IParameter>(); |
---|
2224 | |
---|
2225 | internal IType actualReturnType; |
---|
2226 | internal LambdaTypeHypothesis winningHypothesis; |
---|
2227 | internal ResolveResult bodyResult; |
---|
2228 | internal readonly ResolveVisitor parentVisitor; |
---|
2229 | |
---|
2230 | internal override bool IsUndecided { |
---|
2231 | get { return winningHypothesis == null; } |
---|
2232 | } |
---|
2233 | |
---|
2234 | internal override AstNode LambdaExpression { |
---|
2235 | get { |
---|
2236 | if (selectClause != null) |
---|
2237 | return selectClause.Expression; |
---|
2238 | else |
---|
2239 | return lambda; |
---|
2240 | } |
---|
2241 | } |
---|
2242 | |
---|
2243 | internal override AstNode BodyExpression { |
---|
2244 | get { |
---|
2245 | if (selectClause != null) |
---|
2246 | return selectClause.Expression; |
---|
2247 | else |
---|
2248 | return lambda.Body; |
---|
2249 | } |
---|
2250 | } |
---|
2251 | |
---|
2252 | public override ResolveResult Body { |
---|
2253 | get { return bodyResult; } |
---|
2254 | } |
---|
2255 | |
---|
2256 | private ImplicitlyTypedLambda(ResolveVisitor parentVisitor) |
---|
2257 | { |
---|
2258 | this.parentVisitor = parentVisitor; |
---|
2259 | this.storedContext = parentVisitor.resolver; |
---|
2260 | this.unresolvedFile = parentVisitor.unresolvedFile; |
---|
2261 | this.bodyResult = parentVisitor.voidResult; |
---|
2262 | } |
---|
2263 | |
---|
2264 | public ImplicitlyTypedLambda(LambdaExpression lambda, ResolveVisitor parentVisitor) |
---|
2265 | : this(parentVisitor) |
---|
2266 | { |
---|
2267 | this.lambda = lambda; |
---|
2268 | foreach (var pd in lambda.Parameters) { |
---|
2269 | parameters.Add(new DefaultParameter(SpecialType.UnknownType, pd.Name, region: parentVisitor.MakeRegion(pd))); |
---|
2270 | } |
---|
2271 | RegisterUndecidedLambda(); |
---|
2272 | } |
---|
2273 | |
---|
2274 | public ImplicitlyTypedLambda(QuerySelectClause selectClause, IEnumerable<IParameter> parameters, ResolveVisitor parentVisitor) |
---|
2275 | : this(parentVisitor) |
---|
2276 | { |
---|
2277 | this.selectClause = selectClause; |
---|
2278 | foreach (IParameter p in parameters) |
---|
2279 | this.parameters.Add(p); |
---|
2280 | |
---|
2281 | RegisterUndecidedLambda(); |
---|
2282 | } |
---|
2283 | |
---|
2284 | void RegisterUndecidedLambda() |
---|
2285 | { |
---|
2286 | if (parentVisitor.undecidedLambdas == null) |
---|
2287 | parentVisitor.undecidedLambdas = new List<LambdaBase>(); |
---|
2288 | parentVisitor.undecidedLambdas.Add(this); |
---|
2289 | Log.WriteLine("Added undecided implicitly-typed lambda: " + this.LambdaExpression); |
---|
2290 | } |
---|
2291 | |
---|
2292 | public override IList<IParameter> Parameters { |
---|
2293 | get { return parameters; } |
---|
2294 | } |
---|
2295 | |
---|
2296 | public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions) |
---|
2297 | { |
---|
2298 | Log.WriteLine("Testing validity of {0} for parameters ({1}) and return-type {2}...", |
---|
2299 | this, string.Join<IType>(", ", parameterTypes), returnType); |
---|
2300 | Log.Indent(); |
---|
2301 | var hypothesis = GetHypothesis(parameterTypes); |
---|
2302 | Conversion c = hypothesis.IsValid(returnType, conversions); |
---|
2303 | Log.Unindent(); |
---|
2304 | Log.WriteLine("{0} is {1} for return-type {2}", hypothesis, c.IsValid ? "valid" : "invalid", returnType); |
---|
2305 | return c; |
---|
2306 | } |
---|
2307 | |
---|
2308 | public override IType GetInferredReturnType(IType[] parameterTypes) |
---|
2309 | { |
---|
2310 | return GetHypothesis(parameterTypes).inferredReturnType; |
---|
2311 | } |
---|
2312 | |
---|
2313 | LambdaTypeHypothesis GetHypothesis(IType[] parameterTypes) |
---|
2314 | { |
---|
2315 | if (parameterTypes.Length != parameters.Count) |
---|
2316 | throw new ArgumentException("Incorrect parameter type count"); |
---|
2317 | foreach (var h in hypotheses) { |
---|
2318 | bool ok = true; |
---|
2319 | for (int i = 0; i < parameterTypes.Length; i++) { |
---|
2320 | if (!parameterTypes[i].Equals(h.parameterTypes[i])) { |
---|
2321 | ok = false; |
---|
2322 | break; |
---|
2323 | } |
---|
2324 | } |
---|
2325 | if (ok) |
---|
2326 | return h; |
---|
2327 | } |
---|
2328 | ResolveVisitor visitor = new ResolveVisitor(storedContext, unresolvedFile); |
---|
2329 | var newHypothesis = new LambdaTypeHypothesis(this, parameterTypes, visitor, lambda != null ? lambda.Parameters : null, storedContext); |
---|
2330 | hypotheses.Add(newHypothesis); |
---|
2331 | return newHypothesis; |
---|
2332 | } |
---|
2333 | |
---|
2334 | /// <summary> |
---|
2335 | /// Get any hypothesis for this lambda. |
---|
2336 | /// This method is used as fallback if the lambda isn't merged the normal way (AnonymousFunctionConversion) |
---|
2337 | /// </summary> |
---|
2338 | internal LambdaTypeHypothesis GetAnyHypothesis() |
---|
2339 | { |
---|
2340 | if (winningHypothesis != null) |
---|
2341 | return winningHypothesis; |
---|
2342 | if (hypotheses.Count == 0) { |
---|
2343 | // make a new hypothesis with unknown parameter types |
---|
2344 | IType[] parameterTypes = new IType[parameters.Count]; |
---|
2345 | for (int i = 0; i < parameterTypes.Length; i++) { |
---|
2346 | parameterTypes[i] = SpecialType.UnknownType; |
---|
2347 | } |
---|
2348 | return GetHypothesis(parameterTypes); |
---|
2349 | } else { |
---|
2350 | // We have the choice, so pick the hypothesis with the least missing parameter types |
---|
2351 | LambdaTypeHypothesis bestHypothesis = hypotheses[0]; |
---|
2352 | int bestHypothesisUnknownParameters = bestHypothesis.CountUnknownParameters(); |
---|
2353 | for (int i = 1; i < hypotheses.Count; i++) { |
---|
2354 | int c = hypotheses[i].CountUnknownParameters(); |
---|
2355 | if (c < bestHypothesisUnknownParameters || |
---|
2356 | (c == bestHypothesisUnknownParameters && hypotheses[i].success && !bestHypothesis.success)) |
---|
2357 | { |
---|
2358 | bestHypothesis = hypotheses[i]; |
---|
2359 | bestHypothesisUnknownParameters = c; |
---|
2360 | } |
---|
2361 | } |
---|
2362 | return bestHypothesis; |
---|
2363 | } |
---|
2364 | } |
---|
2365 | |
---|
2366 | internal override void EnforceMerge(ResolveVisitor parentVisitor) |
---|
2367 | { |
---|
2368 | GetAnyHypothesis().MergeInto(parentVisitor, SpecialType.UnknownType); |
---|
2369 | } |
---|
2370 | |
---|
2371 | public override IType ReturnType { |
---|
2372 | get { return actualReturnType ?? SpecialType.UnknownType; } |
---|
2373 | } |
---|
2374 | |
---|
2375 | public override bool IsImplicitlyTyped { |
---|
2376 | get { return true; } |
---|
2377 | } |
---|
2378 | |
---|
2379 | public override bool IsAnonymousMethod { |
---|
2380 | get { return false; } |
---|
2381 | } |
---|
2382 | |
---|
2383 | public override bool HasParameterList { |
---|
2384 | get { return true; } |
---|
2385 | } |
---|
2386 | |
---|
2387 | public override bool IsAsync { |
---|
2388 | get { return lambda != null && lambda.IsAsync; } |
---|
2389 | } |
---|
2390 | |
---|
2391 | public override string ToString() |
---|
2392 | { |
---|
2393 | return "[ImplicitlyTypedLambda " + this.LambdaExpression + "]"; |
---|
2394 | } |
---|
2395 | } |
---|
2396 | |
---|
2397 | /// <summary> |
---|
2398 | /// Every possible set of parameter types gets its own 'hypothetical world'. |
---|
2399 | /// It uses a nested ResolveVisitor that has its own resolve cache, so that resolve results cannot leave the hypothetical world. |
---|
2400 | /// |
---|
2401 | /// Only after overload resolution is applied and the actual parameter types are known, the winning hypothesis will be merged |
---|
2402 | /// with the parent ResolveVisitor. |
---|
2403 | /// This is done when the AnonymousFunctionConversion is applied on the parent visitor. |
---|
2404 | /// </summary> |
---|
2405 | sealed class LambdaTypeHypothesis : IResolveVisitorNavigator |
---|
2406 | { |
---|
2407 | readonly ImplicitlyTypedLambda lambda; |
---|
2408 | readonly IParameter[] lambdaParameters; |
---|
2409 | internal readonly IType[] parameterTypes; |
---|
2410 | readonly ResolveVisitor visitor; |
---|
2411 | readonly CSharpResolver storedContext; |
---|
2412 | |
---|
2413 | internal readonly IType inferredReturnType; |
---|
2414 | IList<Expression> returnExpressions; |
---|
2415 | IList<ResolveResult> returnValues; |
---|
2416 | bool isValidAsVoidMethod; |
---|
2417 | bool isEndpointUnreachable; |
---|
2418 | internal bool success; |
---|
2419 | |
---|
2420 | public LambdaTypeHypothesis(ImplicitlyTypedLambda lambda, IType[] parameterTypes, ResolveVisitor visitor, |
---|
2421 | ICollection<ParameterDeclaration> parameterDeclarations, CSharpResolver storedContext) |
---|
2422 | { |
---|
2423 | Debug.Assert(parameterTypes.Length == lambda.Parameters.Count); |
---|
2424 | |
---|
2425 | this.lambda = lambda; |
---|
2426 | this.parameterTypes = parameterTypes; |
---|
2427 | this.visitor = visitor; |
---|
2428 | this.storedContext = storedContext; |
---|
2429 | visitor.SetNavigator(this); |
---|
2430 | |
---|
2431 | Log.WriteLine("Analyzing " + ToString() + "..."); |
---|
2432 | Log.Indent(); |
---|
2433 | CSharpResolver oldResolver = visitor.resolver; |
---|
2434 | visitor.resolver = visitor.resolver.WithIsWithinLambdaExpression(true); |
---|
2435 | lambdaParameters = new IParameter[parameterTypes.Length]; |
---|
2436 | if (parameterDeclarations != null) { |
---|
2437 | int i = 0; |
---|
2438 | foreach (var pd in parameterDeclarations) { |
---|
2439 | lambdaParameters[i] = new DefaultParameter(parameterTypes[i], pd.Name, region: visitor.MakeRegion(pd)); |
---|
2440 | visitor.resolver = visitor.resolver.AddVariable(lambdaParameters[i]); |
---|
2441 | i++; |
---|
2442 | visitor.Scan(pd); |
---|
2443 | } |
---|
2444 | } else { |
---|
2445 | for (int i = 0; i < parameterTypes.Length; i++) { |
---|
2446 | var p = lambda.Parameters[i]; |
---|
2447 | lambdaParameters[i] = new DefaultParameter(parameterTypes[i], p.Name, region: p.Region); |
---|
2448 | visitor.resolver = visitor.resolver.AddVariable(lambdaParameters[i]); |
---|
2449 | } |
---|
2450 | } |
---|
2451 | |
---|
2452 | success = true; |
---|
2453 | visitor.AnalyzeLambda(lambda.BodyExpression, lambda.IsAsync, out isValidAsVoidMethod, out isEndpointUnreachable, out inferredReturnType, out returnExpressions, out returnValues); |
---|
2454 | visitor.resolver = oldResolver; |
---|
2455 | Log.Unindent(); |
---|
2456 | Log.WriteLine("Finished analyzing " + ToString()); |
---|
2457 | } |
---|
2458 | |
---|
2459 | ResolveVisitorNavigationMode IResolveVisitorNavigator.Scan(AstNode node) |
---|
2460 | { |
---|
2461 | return ResolveVisitorNavigationMode.Resolve; |
---|
2462 | } |
---|
2463 | |
---|
2464 | void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result) |
---|
2465 | { |
---|
2466 | if (result.IsError) |
---|
2467 | success = false; |
---|
2468 | } |
---|
2469 | |
---|
2470 | void IResolveVisitorNavigator.ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType) |
---|
2471 | { |
---|
2472 | success &= conversion.IsValid; |
---|
2473 | } |
---|
2474 | |
---|
2475 | internal int CountUnknownParameters() |
---|
2476 | { |
---|
2477 | int c = 0; |
---|
2478 | foreach (IType t in parameterTypes) { |
---|
2479 | if (t.Kind == TypeKind.Unknown) |
---|
2480 | c++; |
---|
2481 | } |
---|
2482 | return c; |
---|
2483 | } |
---|
2484 | |
---|
2485 | public Conversion IsValid(IType returnType, CSharpConversions conversions) |
---|
2486 | { |
---|
2487 | bool valid = success && IsValidLambda(isValidAsVoidMethod, isEndpointUnreachable, lambda.IsAsync, returnValues, returnType, conversions); |
---|
2488 | return new AnonymousFunctionConversion(returnType, this, valid); |
---|
2489 | } |
---|
2490 | |
---|
2491 | public void MergeInto(ResolveVisitor parentVisitor, IType returnType) |
---|
2492 | { |
---|
2493 | if (returnType == null) |
---|
2494 | throw new ArgumentNullException("returnType"); |
---|
2495 | if (parentVisitor != lambda.parentVisitor) |
---|
2496 | throw new InvalidOperationException("parent visitor mismatch"); |
---|
2497 | |
---|
2498 | if (lambda.winningHypothesis == this) |
---|
2499 | return; |
---|
2500 | else if (lambda.winningHypothesis != null) |
---|
2501 | throw new InvalidOperationException("Trying to merge conflicting hypotheses"); |
---|
2502 | |
---|
2503 | lambda.actualReturnType = returnType; |
---|
2504 | if (lambda.IsAsync) |
---|
2505 | returnType = parentVisitor.UnpackTask(returnType); |
---|
2506 | |
---|
2507 | lambda.winningHypothesis = this; |
---|
2508 | lambda.parameters = lambdaParameters; // replace untyped parameters with typed parameters |
---|
2509 | if (lambda.BodyExpression is Expression && returnValues.Count == 1) { |
---|
2510 | lambda.bodyResult = returnValues[0]; |
---|
2511 | if (returnType.Kind != TypeKind.Void) { |
---|
2512 | var conv = storedContext.conversions.ImplicitConversion(lambda.bodyResult, returnType); |
---|
2513 | if (!conv.IsIdentityConversion) |
---|
2514 | lambda.bodyResult = new ConversionResolveResult(returnType, lambda.bodyResult, conv, storedContext.CheckForOverflow); |
---|
2515 | } |
---|
2516 | } |
---|
2517 | |
---|
2518 | Log.WriteLine("Applying return type {0} to implicitly-typed lambda {1}", returnType, lambda.LambdaExpression); |
---|
2519 | if (returnType.Kind != TypeKind.Void || lambda.BodyExpression is Statement) { |
---|
2520 | for (int i = 0; i < returnExpressions.Count; i++) { |
---|
2521 | visitor.ProcessConversion(returnExpressions[i], returnValues[i], returnType); |
---|
2522 | } |
---|
2523 | } |
---|
2524 | |
---|
2525 | visitor.MergeUndecidedLambdas(); |
---|
2526 | Log.WriteLine("Merging " + ToString()); |
---|
2527 | foreach (var pair in visitor.resolverBeforeDict) { |
---|
2528 | Debug.Assert(!parentVisitor.resolverBeforeDict.ContainsKey(pair.Key)); |
---|
2529 | parentVisitor.resolverBeforeDict[pair.Key] = pair.Value; |
---|
2530 | } |
---|
2531 | foreach (var pair in visitor.resolverAfterDict) { |
---|
2532 | Debug.Assert(!parentVisitor.resolverAfterDict.ContainsKey(pair.Key)); |
---|
2533 | parentVisitor.resolverAfterDict[pair.Key] = pair.Value; |
---|
2534 | } |
---|
2535 | foreach (var pair in visitor.resolveResultCache) { |
---|
2536 | parentVisitor.StoreResult(pair.Key, pair.Value); |
---|
2537 | } |
---|
2538 | parentVisitor.ImportConversions(visitor); |
---|
2539 | parentVisitor.undecidedLambdas.Remove(lambda); |
---|
2540 | } |
---|
2541 | |
---|
2542 | public override string ToString() |
---|
2543 | { |
---|
2544 | StringBuilder b = new StringBuilder(); |
---|
2545 | b.Append("[LambdaTypeHypothesis ("); |
---|
2546 | for (int i = 0; i < parameterTypes.Length; i++) { |
---|
2547 | if (i > 0) b.Append(", "); |
---|
2548 | b.Append(parameterTypes[i]); |
---|
2549 | b.Append(' '); |
---|
2550 | b.Append(lambda.Parameters[i].Name); |
---|
2551 | } |
---|
2552 | b.Append(") => "); |
---|
2553 | b.Append(lambda.BodyExpression.ToString()); |
---|
2554 | b.Append(']'); |
---|
2555 | return b.ToString(); |
---|
2556 | } |
---|
2557 | } |
---|
2558 | #endregion |
---|
2559 | |
---|
2560 | #region MergeUndecidedLambdas |
---|
2561 | abstract class LambdaBase : LambdaResolveResult |
---|
2562 | { |
---|
2563 | internal abstract bool IsUndecided { get; } |
---|
2564 | internal abstract AstNode LambdaExpression { get; } |
---|
2565 | internal abstract AstNode BodyExpression { get; } |
---|
2566 | |
---|
2567 | internal abstract void EnforceMerge(ResolveVisitor parentVisitor); |
---|
2568 | |
---|
2569 | public override ResolveResult ShallowClone() |
---|
2570 | { |
---|
2571 | if (IsUndecided) |
---|
2572 | throw new NotSupportedException(); |
---|
2573 | return base.ShallowClone(); |
---|
2574 | } |
---|
2575 | } |
---|
2576 | |
---|
2577 | void MergeUndecidedLambdas() |
---|
2578 | { |
---|
2579 | if (undecidedLambdas == null || undecidedLambdas.Count == 0) |
---|
2580 | return; |
---|
2581 | Log.WriteLine("MergeUndecidedLambdas()..."); |
---|
2582 | Log.Indent(); |
---|
2583 | while (undecidedLambdas.Count > 0) { |
---|
2584 | LambdaBase lambda = undecidedLambdas[0]; |
---|
2585 | // may happen caused by parse error l => |
---|
2586 | if (lambda.LambdaExpression == null) { |
---|
2587 | undecidedLambdas.Remove (lambda); |
---|
2588 | continue; |
---|
2589 | } |
---|
2590 | ResolveParentForConversion(lambda.LambdaExpression); |
---|
2591 | if (lambda.IsUndecided) { |
---|
2592 | // Lambda wasn't merged by resolving its parent -> enforce merging |
---|
2593 | Log.WriteLine("Lambda wasn't merged by conversion - enforce merging"); |
---|
2594 | lambda.EnforceMerge(this); |
---|
2595 | } |
---|
2596 | } |
---|
2597 | Log.Unindent(); |
---|
2598 | Log.WriteLine("MergeUndecidedLambdas() finished."); |
---|
2599 | } |
---|
2600 | |
---|
2601 | void ResolveParentForConversion(AstNode expression) |
---|
2602 | { |
---|
2603 | AstNode parent = expression.Parent; |
---|
2604 | // Continue going upwards until we find a node that can be resolved and provides |
---|
2605 | // an expected type. |
---|
2606 | while (ParenthesizedExpression.ActsAsParenthesizedExpression(parent) || CSharpAstResolver.IsUnresolvableNode(parent)) { |
---|
2607 | parent = parent.Parent; |
---|
2608 | } |
---|
2609 | CSharpResolver storedResolver; |
---|
2610 | if (parent != null && resolverBeforeDict.TryGetValue(parent, out storedResolver)) { |
---|
2611 | Log.WriteLine("Trying to resolve '" + parent + "' in order to find the conversion applied to '" + expression + "'..."); |
---|
2612 | Log.Indent(); |
---|
2613 | ResetContext(storedResolver, delegate { Resolve(parent); }); |
---|
2614 | Log.Unindent(); |
---|
2615 | } else { |
---|
2616 | Log.WriteLine("Could not find a suitable parent for '" + expression + "'"); |
---|
2617 | } |
---|
2618 | } |
---|
2619 | #endregion |
---|
2620 | |
---|
2621 | #region AnalyzeLambda |
---|
2622 | IType GetTaskType(IType resultType) |
---|
2623 | { |
---|
2624 | if (resultType.Kind == TypeKind.Unknown) |
---|
2625 | return SpecialType.UnknownType; |
---|
2626 | if (resultType.Kind == TypeKind.Void) |
---|
2627 | return resolver.Compilation.FindType(KnownTypeCode.Task); |
---|
2628 | |
---|
2629 | ITypeDefinition def = resolver.Compilation.FindType(KnownTypeCode.TaskOfT).GetDefinition(); |
---|
2630 | if (def != null) |
---|
2631 | return new ParameterizedType(def, new[] { resultType }); |
---|
2632 | else |
---|
2633 | return SpecialType.UnknownType; |
---|
2634 | } |
---|
2635 | |
---|
2636 | void AnalyzeLambda(AstNode body, bool isAsync, out bool isValidAsVoidMethod, out bool isEndpointUnreachable, out IType inferredReturnType, out IList<Expression> returnExpressions, out IList<ResolveResult> returnValues) |
---|
2637 | { |
---|
2638 | isEndpointUnreachable = false; |
---|
2639 | Expression expr = body as Expression; |
---|
2640 | if (expr != null) { |
---|
2641 | isValidAsVoidMethod = ExpressionPermittedAsStatement(expr); |
---|
2642 | returnExpressions = new [] { expr }; |
---|
2643 | returnValues = new[] { Resolve(expr) }; |
---|
2644 | inferredReturnType = returnValues[0].Type; |
---|
2645 | } else { |
---|
2646 | Scan(body); |
---|
2647 | |
---|
2648 | AnalyzeLambdaVisitor alv = new AnalyzeLambdaVisitor(); |
---|
2649 | body.AcceptVisitor(alv); |
---|
2650 | isValidAsVoidMethod = (alv.ReturnExpressions.Count == 0); |
---|
2651 | if (alv.HasVoidReturnStatements) { |
---|
2652 | returnExpressions = EmptyList<Expression>.Instance; |
---|
2653 | returnValues = EmptyList<ResolveResult>.Instance; |
---|
2654 | inferredReturnType = resolver.Compilation.FindType(KnownTypeCode.Void); |
---|
2655 | } else { |
---|
2656 | returnExpressions = alv.ReturnExpressions; |
---|
2657 | returnValues = new ResolveResult[returnExpressions.Count]; |
---|
2658 | for (int i = 0; i < returnValues.Count; i++) { |
---|
2659 | returnValues[i] = resolveResultCache[returnExpressions[i]]; |
---|
2660 | } |
---|
2661 | |
---|
2662 | // async lambdas without return statements are resolved as Task return types. |
---|
2663 | if (returnExpressions.Count == 0 && isAsync) { |
---|
2664 | inferredReturnType = resolver.Compilation.FindType(KnownTypeCode.Task); |
---|
2665 | Log.WriteLine("Lambda return type was inferred to: " + inferredReturnType); |
---|
2666 | return; |
---|
2667 | } |
---|
2668 | |
---|
2669 | TypeInference ti = new TypeInference(resolver.Compilation, resolver.conversions); |
---|
2670 | bool tiSuccess; |
---|
2671 | inferredReturnType = ti.GetBestCommonType(returnValues, out tiSuccess); |
---|
2672 | // Failure to infer a return type does not make the lambda invalid, |
---|
2673 | // so we can ignore the 'tiSuccess' value |
---|
2674 | if (isValidAsVoidMethod && returnExpressions.Count == 0 && body is Statement) { |
---|
2675 | var reachabilityAnalysis = ReachabilityAnalysis.Create( |
---|
2676 | (Statement)body, (node, _) => resolveResultCache[node], |
---|
2677 | resolver.CurrentTypeResolveContext, cancellationToken); |
---|
2678 | isEndpointUnreachable = !reachabilityAnalysis.IsEndpointReachable((Statement)body); |
---|
2679 | } |
---|
2680 | } |
---|
2681 | } |
---|
2682 | if (isAsync) |
---|
2683 | inferredReturnType = GetTaskType(inferredReturnType); |
---|
2684 | Log.WriteLine("Lambda return type was inferred to: " + inferredReturnType); |
---|
2685 | } |
---|
2686 | |
---|
2687 | static bool ExpressionPermittedAsStatement(Expression expr) |
---|
2688 | { |
---|
2689 | UnaryOperatorExpression uoe = expr as UnaryOperatorExpression; |
---|
2690 | if (uoe != null) { |
---|
2691 | switch (uoe.Operator) { |
---|
2692 | case UnaryOperatorType.Increment: |
---|
2693 | case UnaryOperatorType.Decrement: |
---|
2694 | case UnaryOperatorType.PostIncrement: |
---|
2695 | case UnaryOperatorType.PostDecrement: |
---|
2696 | case UnaryOperatorType.Await: |
---|
2697 | return true; |
---|
2698 | default: |
---|
2699 | return false; |
---|
2700 | } |
---|
2701 | } |
---|
2702 | return expr is InvocationExpression |
---|
2703 | || expr is ObjectCreateExpression |
---|
2704 | || expr is AssignmentExpression; |
---|
2705 | } |
---|
2706 | |
---|
2707 | static bool IsValidLambda(bool isValidAsVoidMethod, bool isEndpointUnreachable, bool isAsync, IList<ResolveResult> returnValues, IType returnType, CSharpConversions conversions) |
---|
2708 | { |
---|
2709 | if (returnType.Kind == TypeKind.Void) { |
---|
2710 | // Lambdas that are valid statement lambdas or expression lambdas with a statement-expression |
---|
2711 | // can be converted to delegates with void return type. |
---|
2712 | // This holds for both async and regular lambdas. |
---|
2713 | return isValidAsVoidMethod; |
---|
2714 | } else if (isAsync && TaskType.IsTask(returnType) && returnType.TypeParameterCount == 0) { |
---|
2715 | // Additionally, async lambdas with the above property can be converted to non-generic Task. |
---|
2716 | return isValidAsVoidMethod; |
---|
2717 | } else { |
---|
2718 | if (returnValues.Count == 0) |
---|
2719 | return isEndpointUnreachable; |
---|
2720 | if (isAsync) { |
---|
2721 | // async lambdas must return Task<T> |
---|
2722 | if (!(TaskType.IsTask(returnType) && returnType.TypeParameterCount == 1)) |
---|
2723 | return false; |
---|
2724 | // unpack Task<T> for testing the implicit conversions |
---|
2725 | returnType = ((ParameterizedType)returnType).GetTypeArgument(0); |
---|
2726 | } |
---|
2727 | foreach (ResolveResult returnRR in returnValues) { |
---|
2728 | if (!conversions.ImplicitConversion(returnRR, returnType).IsValid) |
---|
2729 | return false; |
---|
2730 | } |
---|
2731 | return true; |
---|
2732 | } |
---|
2733 | } |
---|
2734 | |
---|
2735 | IType UnpackTask(IType type) |
---|
2736 | { |
---|
2737 | return TaskType.UnpackTask(resolver.Compilation, type); |
---|
2738 | } |
---|
2739 | |
---|
2740 | sealed class AnalyzeLambdaVisitor : DepthFirstAstVisitor |
---|
2741 | { |
---|
2742 | public bool HasVoidReturnStatements; |
---|
2743 | public List<Expression> ReturnExpressions = new List<Expression>(); |
---|
2744 | |
---|
2745 | public override void VisitReturnStatement(ReturnStatement returnStatement) |
---|
2746 | { |
---|
2747 | Expression expr = returnStatement.Expression; |
---|
2748 | if (expr.IsNull) { |
---|
2749 | HasVoidReturnStatements = true; |
---|
2750 | } else { |
---|
2751 | ReturnExpressions.Add(expr); |
---|
2752 | } |
---|
2753 | } |
---|
2754 | |
---|
2755 | public override void VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression) |
---|
2756 | { |
---|
2757 | // don't go into nested lambdas |
---|
2758 | } |
---|
2759 | |
---|
2760 | public override void VisitLambdaExpression(LambdaExpression lambdaExpression) |
---|
2761 | { |
---|
2762 | // don't go into nested lambdas |
---|
2763 | } |
---|
2764 | } |
---|
2765 | #endregion |
---|
2766 | #endregion |
---|
2767 | |
---|
2768 | #region ForEach Statement |
---|
2769 | ResolveResult IAstVisitor<ResolveResult>.VisitForeachStatement(ForeachStatement foreachStatement) |
---|
2770 | { |
---|
2771 | var compilation = resolver.Compilation; |
---|
2772 | ResolveResult expression = Resolve(foreachStatement.InExpression); |
---|
2773 | bool isImplicitlyTypedVariable = foreachStatement.VariableType.IsVar(); |
---|
2774 | var memberLookup = resolver.CreateMemberLookup(); |
---|
2775 | |
---|
2776 | IType collectionType, enumeratorType, elementType; |
---|
2777 | ResolveResult getEnumeratorInvocation; |
---|
2778 | ResolveResult currentRR = null; |
---|
2779 | // C# 4.0 spec: §8.8.4 The foreach statement |
---|
2780 | if (expression.Type.Kind == TypeKind.Array || expression.Type.Kind == TypeKind.Dynamic) { |
---|
2781 | collectionType = compilation.FindType(KnownTypeCode.IEnumerable); |
---|
2782 | enumeratorType = compilation.FindType(KnownTypeCode.IEnumerator); |
---|
2783 | if (expression.Type.Kind == TypeKind.Array) { |
---|
2784 | elementType = ((ArrayType)expression.Type).ElementType; |
---|
2785 | } else { |
---|
2786 | elementType = isImplicitlyTypedVariable ? SpecialType.Dynamic : compilation.FindType(KnownTypeCode.Object); |
---|
2787 | } |
---|
2788 | getEnumeratorInvocation = resolver.ResolveCast(collectionType, expression); |
---|
2789 | getEnumeratorInvocation = resolver.ResolveMemberAccess(getEnumeratorInvocation, "GetEnumerator", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget); |
---|
2790 | getEnumeratorInvocation = resolver.ResolveInvocation(getEnumeratorInvocation, new ResolveResult[0]); |
---|
2791 | } else { |
---|
2792 | var getEnumeratorMethodGroup = memberLookup.Lookup(expression, "GetEnumerator", EmptyList<IType>.Instance, true) as MethodGroupResolveResult; |
---|
2793 | if (getEnumeratorMethodGroup != null) { |
---|
2794 | var or = getEnumeratorMethodGroup.PerformOverloadResolution( |
---|
2795 | compilation, new ResolveResult[0], |
---|
2796 | allowExtensionMethods: false, allowExpandingParams: false, allowOptionalParameters: false); |
---|
2797 | if (or.FoundApplicableCandidate && !or.IsAmbiguous && !or.BestCandidate.IsStatic && or.BestCandidate.IsPublic) { |
---|
2798 | collectionType = expression.Type; |
---|
2799 | getEnumeratorInvocation = or.CreateResolveResult(expression); |
---|
2800 | enumeratorType = getEnumeratorInvocation.Type; |
---|
2801 | currentRR = memberLookup.Lookup(new ResolveResult(enumeratorType), "Current", EmptyList<IType>.Instance, false); |
---|
2802 | elementType = currentRR.Type; |
---|
2803 | } else { |
---|
2804 | CheckForEnumerableInterface(expression, out collectionType, out enumeratorType, out elementType, out getEnumeratorInvocation); |
---|
2805 | } |
---|
2806 | } else { |
---|
2807 | CheckForEnumerableInterface(expression, out collectionType, out enumeratorType, out elementType, out getEnumeratorInvocation); |
---|
2808 | } |
---|
2809 | } |
---|
2810 | IMethod moveNextMethod = null; |
---|
2811 | var moveNextMethodGroup = memberLookup.Lookup(new ResolveResult(enumeratorType), "MoveNext", EmptyList<IType>.Instance, false) as MethodGroupResolveResult; |
---|
2812 | if (moveNextMethodGroup != null) { |
---|
2813 | var or = moveNextMethodGroup.PerformOverloadResolution( |
---|
2814 | compilation, new ResolveResult[0], |
---|
2815 | allowExtensionMethods: false, allowExpandingParams: false, allowOptionalParameters: false); |
---|
2816 | moveNextMethod = or.GetBestCandidateWithSubstitutedTypeArguments() as IMethod; |
---|
2817 | } |
---|
2818 | |
---|
2819 | if (currentRR == null) |
---|
2820 | currentRR = memberLookup.Lookup(new ResolveResult(enumeratorType), "Current", EmptyList<IType>.Instance, false); |
---|
2821 | IProperty currentProperty = null; |
---|
2822 | if (currentRR is MemberResolveResult) |
---|
2823 | currentProperty = ((MemberResolveResult)currentRR).Member as IProperty; |
---|
2824 | // end of foreach resolve logic |
---|
2825 | // back to resolve visitor: |
---|
2826 | |
---|
2827 | resolver = resolver.PushBlock(); |
---|
2828 | IVariable v; |
---|
2829 | if (isImplicitlyTypedVariable) { |
---|
2830 | StoreCurrentState(foreachStatement.VariableType); |
---|
2831 | StoreResult(foreachStatement.VariableType, new TypeResolveResult(elementType)); |
---|
2832 | v = MakeVariable(elementType, foreachStatement.VariableNameToken); |
---|
2833 | } else { |
---|
2834 | IType variableType = ResolveType(foreachStatement.VariableType); |
---|
2835 | v = MakeVariable(variableType, foreachStatement.VariableNameToken); |
---|
2836 | } |
---|
2837 | StoreCurrentState(foreachStatement.VariableNameToken); |
---|
2838 | resolver = resolver.AddVariable(v); |
---|
2839 | |
---|
2840 | StoreResult(foreachStatement.VariableNameToken, new LocalResolveResult(v)); |
---|
2841 | |
---|
2842 | Scan(foreachStatement.EmbeddedStatement); |
---|
2843 | resolver = resolver.PopBlock(); |
---|
2844 | return new ForEachResolveResult(getEnumeratorInvocation, collectionType, enumeratorType, elementType, |
---|
2845 | v, currentProperty, moveNextMethod, voidResult.Type); |
---|
2846 | } |
---|
2847 | |
---|
2848 | void CheckForEnumerableInterface(ResolveResult expression, out IType collectionType, out IType enumeratorType, out IType elementType, out ResolveResult getEnumeratorInvocation) |
---|
2849 | { |
---|
2850 | var compilation = resolver.Compilation; |
---|
2851 | bool? isGeneric; |
---|
2852 | elementType = GetElementTypeFromIEnumerable(expression.Type, compilation, false, out isGeneric); |
---|
2853 | if (isGeneric == true) { |
---|
2854 | ITypeDefinition enumerableOfT = compilation.FindType(KnownTypeCode.IEnumerableOfT).GetDefinition(); |
---|
2855 | if (enumerableOfT != null) |
---|
2856 | collectionType = new ParameterizedType(enumerableOfT, new [] { elementType }); |
---|
2857 | else |
---|
2858 | collectionType = SpecialType.UnknownType; |
---|
2859 | |
---|
2860 | ITypeDefinition enumeratorOfT = compilation.FindType(KnownTypeCode.IEnumeratorOfT).GetDefinition(); |
---|
2861 | if (enumeratorOfT != null) |
---|
2862 | enumeratorType = new ParameterizedType(enumeratorOfT, new [] { elementType }); |
---|
2863 | else |
---|
2864 | enumeratorType = SpecialType.UnknownType; |
---|
2865 | } else if (isGeneric == false) { |
---|
2866 | collectionType = compilation.FindType(KnownTypeCode.IEnumerable); |
---|
2867 | enumeratorType = compilation.FindType(KnownTypeCode.IEnumerator); |
---|
2868 | } else { |
---|
2869 | collectionType = SpecialType.UnknownType; |
---|
2870 | enumeratorType = SpecialType.UnknownType; |
---|
2871 | } |
---|
2872 | getEnumeratorInvocation = resolver.ResolveCast(collectionType, expression); |
---|
2873 | getEnumeratorInvocation = resolver.ResolveMemberAccess(getEnumeratorInvocation, "GetEnumerator", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget); |
---|
2874 | getEnumeratorInvocation = resolver.ResolveInvocation(getEnumeratorInvocation, new ResolveResult[0]); |
---|
2875 | } |
---|
2876 | #endregion |
---|
2877 | |
---|
2878 | #region Local Variable Scopes (Block Statements) |
---|
2879 | ResolveResult IAstVisitor<ResolveResult>.VisitBlockStatement(BlockStatement blockStatement) |
---|
2880 | { |
---|
2881 | resolver = resolver.PushBlock(); |
---|
2882 | ScanChildren(blockStatement); |
---|
2883 | resolver = resolver.PopBlock(); |
---|
2884 | return voidResult; |
---|
2885 | } |
---|
2886 | |
---|
2887 | ResolveResult IAstVisitor<ResolveResult>.VisitUsingStatement(UsingStatement usingStatement) |
---|
2888 | { |
---|
2889 | resolver = resolver.PushBlock(); |
---|
2890 | if (resolverEnabled) { |
---|
2891 | for (AstNode child = usingStatement.FirstChild; child != null; child = child.NextSibling) { |
---|
2892 | if (child.Role == UsingStatement.ResourceAcquisitionRole && child is Expression) { |
---|
2893 | ResolveAndProcessConversion((Expression)child, resolver.Compilation.FindType(KnownTypeCode.IDisposable)); |
---|
2894 | } else { |
---|
2895 | Scan(child); |
---|
2896 | } |
---|
2897 | } |
---|
2898 | } else { |
---|
2899 | ScanChildren(usingStatement); |
---|
2900 | } |
---|
2901 | resolver = resolver.PopBlock(); |
---|
2902 | return resolverEnabled ? voidResult : null; |
---|
2903 | } |
---|
2904 | |
---|
2905 | ResolveResult IAstVisitor<ResolveResult>.VisitFixedStatement(FixedStatement fixedStatement) |
---|
2906 | { |
---|
2907 | resolver = resolver.PushBlock(); |
---|
2908 | IType type = ResolveType(fixedStatement.Type); |
---|
2909 | foreach (VariableInitializer vi in fixedStatement.Variables) { |
---|
2910 | resolver = resolver.AddVariable(MakeVariable(type, vi.NameToken)); |
---|
2911 | Scan(vi); |
---|
2912 | } |
---|
2913 | Scan(fixedStatement.EmbeddedStatement); |
---|
2914 | resolver = resolver.PopBlock(); |
---|
2915 | return voidResult; |
---|
2916 | } |
---|
2917 | |
---|
2918 | ResolveResult IAstVisitor<ResolveResult>.VisitSwitchStatement(SwitchStatement switchStatement) |
---|
2919 | { |
---|
2920 | resolver = resolver.PushBlock(); |
---|
2921 | ScanChildren(switchStatement); |
---|
2922 | resolver = resolver.PopBlock(); |
---|
2923 | return voidResult; |
---|
2924 | } |
---|
2925 | |
---|
2926 | ResolveResult IAstVisitor<ResolveResult>.VisitCatchClause(CatchClause catchClause) |
---|
2927 | { |
---|
2928 | resolver = resolver.PushBlock(); |
---|
2929 | if (string.IsNullOrEmpty(catchClause.VariableName)) { |
---|
2930 | Scan(catchClause.Type); |
---|
2931 | } else { |
---|
2932 | //DomRegion region = MakeRegion(catchClause.VariableNameToken); |
---|
2933 | StoreCurrentState(catchClause.VariableNameToken); |
---|
2934 | IVariable v = MakeVariable(ResolveType(catchClause.Type), catchClause.VariableNameToken); |
---|
2935 | resolver = resolver.AddVariable(v); |
---|
2936 | StoreResult(catchClause.VariableNameToken, new LocalResolveResult(v)); |
---|
2937 | } |
---|
2938 | Scan(catchClause.Body); |
---|
2939 | resolver = resolver.PopBlock(); |
---|
2940 | return voidResult; |
---|
2941 | } |
---|
2942 | #endregion |
---|
2943 | |
---|
2944 | #region VariableDeclarationStatement |
---|
2945 | ResolveResult IAstVisitor<ResolveResult>.VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement) |
---|
2946 | { |
---|
2947 | bool isConst = (variableDeclarationStatement.Modifiers & Modifiers.Const) != 0; |
---|
2948 | if (!isConst && variableDeclarationStatement.Type.IsVar() && variableDeclarationStatement.Variables.Count == 1) { |
---|
2949 | VariableInitializer vi = variableDeclarationStatement.Variables.Single(); |
---|
2950 | StoreCurrentState(variableDeclarationStatement.Type); |
---|
2951 | IType type = Resolve(vi.Initializer).Type; |
---|
2952 | StoreResult(variableDeclarationStatement.Type, new TypeResolveResult(type)); |
---|
2953 | IVariable v = MakeVariable(type, vi.NameToken); |
---|
2954 | resolver = resolver.AddVariable(v); |
---|
2955 | Scan(vi); |
---|
2956 | } else { |
---|
2957 | IType type = ResolveType(variableDeclarationStatement.Type); |
---|
2958 | |
---|
2959 | foreach (VariableInitializer vi in variableDeclarationStatement.Variables) { |
---|
2960 | IVariable v; |
---|
2961 | if (isConst) { |
---|
2962 | ResolveResult rr = Resolve(vi.Initializer); |
---|
2963 | rr = resolver.ResolveCast(type, rr); |
---|
2964 | v = MakeConstant(type, vi.NameToken, rr.ConstantValue); |
---|
2965 | } else { |
---|
2966 | v = MakeVariable(type, vi.NameToken); |
---|
2967 | } |
---|
2968 | resolver = resolver.AddVariable(v); |
---|
2969 | Scan(vi); |
---|
2970 | } |
---|
2971 | } |
---|
2972 | return voidResult; |
---|
2973 | } |
---|
2974 | #endregion |
---|
2975 | |
---|
2976 | #region Condition Statements |
---|
2977 | ResolveResult IAstVisitor<ResolveResult>.VisitForStatement(ForStatement forStatement) |
---|
2978 | { |
---|
2979 | resolver = resolver.PushBlock(); |
---|
2980 | var result = HandleConditionStatement(forStatement); |
---|
2981 | resolver = resolver.PopBlock(); |
---|
2982 | return result; |
---|
2983 | } |
---|
2984 | |
---|
2985 | ResolveResult IAstVisitor<ResolveResult>.VisitIfElseStatement(IfElseStatement ifElseStatement) |
---|
2986 | { |
---|
2987 | return HandleConditionStatement(ifElseStatement); |
---|
2988 | } |
---|
2989 | |
---|
2990 | ResolveResult IAstVisitor<ResolveResult>.VisitWhileStatement(WhileStatement whileStatement) |
---|
2991 | { |
---|
2992 | return HandleConditionStatement(whileStatement); |
---|
2993 | } |
---|
2994 | |
---|
2995 | ResolveResult IAstVisitor<ResolveResult>.VisitDoWhileStatement(DoWhileStatement doWhileStatement) |
---|
2996 | { |
---|
2997 | return HandleConditionStatement(doWhileStatement); |
---|
2998 | } |
---|
2999 | |
---|
3000 | ResolveResult HandleConditionStatement(Statement conditionStatement) |
---|
3001 | { |
---|
3002 | if (resolverEnabled) { |
---|
3003 | for (AstNode child = conditionStatement.FirstChild; child != null; child = child.NextSibling) { |
---|
3004 | if (child.Role == Roles.Condition) { |
---|
3005 | Expression condition = (Expression)child; |
---|
3006 | ResolveResult conditionRR = Resolve(condition); |
---|
3007 | ResolveResult convertedRR = resolver.ResolveCondition(conditionRR); |
---|
3008 | if (convertedRR != conditionRR) |
---|
3009 | ProcessConversionResult(condition, convertedRR as ConversionResolveResult); |
---|
3010 | } else { |
---|
3011 | Scan(child); |
---|
3012 | } |
---|
3013 | } |
---|
3014 | return voidResult; |
---|
3015 | } else { |
---|
3016 | ScanChildren(conditionStatement); |
---|
3017 | return null; |
---|
3018 | } |
---|
3019 | } |
---|
3020 | #endregion |
---|
3021 | |
---|
3022 | #region Return Statements |
---|
3023 | ResolveResult IAstVisitor<ResolveResult>.VisitReturnStatement(ReturnStatement returnStatement) |
---|
3024 | { |
---|
3025 | if (resolverEnabled && !resolver.IsWithinLambdaExpression && resolver.CurrentMember != null) { |
---|
3026 | IType type = resolver.CurrentMember.ReturnType; |
---|
3027 | if (TaskType.IsTask(type)) { |
---|
3028 | var methodDecl = returnStatement.Ancestors.OfType<EntityDeclaration>().FirstOrDefault(); |
---|
3029 | if (methodDecl != null && (methodDecl.Modifiers & Modifiers.Async) == Modifiers.Async) |
---|
3030 | type = UnpackTask(type); |
---|
3031 | } |
---|
3032 | ResolveAndProcessConversion(returnStatement.Expression, type); |
---|
3033 | } else { |
---|
3034 | Scan(returnStatement.Expression); |
---|
3035 | } |
---|
3036 | return resolverEnabled ? voidResult : null; |
---|
3037 | } |
---|
3038 | |
---|
3039 | ResolveResult IAstVisitor<ResolveResult>.VisitYieldReturnStatement(YieldReturnStatement yieldStatement) |
---|
3040 | { |
---|
3041 | if (resolverEnabled && resolver.CurrentMember != null) { |
---|
3042 | IType returnType = resolver.CurrentMember.ReturnType; |
---|
3043 | bool? isGeneric; |
---|
3044 | IType elementType = GetElementTypeFromIEnumerable(returnType, resolver.Compilation, true, out isGeneric); |
---|
3045 | ResolveAndProcessConversion(yieldStatement.Expression, elementType); |
---|
3046 | } else { |
---|
3047 | Scan(yieldStatement.Expression); |
---|
3048 | } |
---|
3049 | return resolverEnabled ? voidResult : null; |
---|
3050 | } |
---|
3051 | |
---|
3052 | ResolveResult IAstVisitor<ResolveResult>.VisitYieldBreakStatement(YieldBreakStatement yieldBreakStatement) |
---|
3053 | { |
---|
3054 | return voidResult; |
---|
3055 | } |
---|
3056 | #endregion |
---|
3057 | |
---|
3058 | #region Other statements |
---|
3059 | ResolveResult IAstVisitor<ResolveResult>.VisitExpressionStatement(ExpressionStatement expressionStatement) |
---|
3060 | { |
---|
3061 | ScanChildren(expressionStatement); |
---|
3062 | return voidResult; |
---|
3063 | } |
---|
3064 | |
---|
3065 | ResolveResult IAstVisitor<ResolveResult>.VisitLockStatement(LockStatement lockStatement) |
---|
3066 | { |
---|
3067 | ScanChildren(lockStatement); |
---|
3068 | return voidResult; |
---|
3069 | } |
---|
3070 | |
---|
3071 | ResolveResult IAstVisitor<ResolveResult>.VisitEmptyStatement(EmptyStatement emptyStatement) |
---|
3072 | { |
---|
3073 | return voidResult; |
---|
3074 | } |
---|
3075 | |
---|
3076 | ResolveResult IAstVisitor<ResolveResult>.VisitBreakStatement(BreakStatement breakStatement) |
---|
3077 | { |
---|
3078 | return voidResult; |
---|
3079 | } |
---|
3080 | |
---|
3081 | ResolveResult IAstVisitor<ResolveResult>.VisitContinueStatement(ContinueStatement continueStatement) |
---|
3082 | { |
---|
3083 | return voidResult; |
---|
3084 | } |
---|
3085 | |
---|
3086 | ResolveResult IAstVisitor<ResolveResult>.VisitThrowStatement(ThrowStatement throwStatement) |
---|
3087 | { |
---|
3088 | if (resolverEnabled) { |
---|
3089 | ResolveAndProcessConversion(throwStatement.Expression, resolver.Compilation.FindType(KnownTypeCode.Exception)); |
---|
3090 | return voidResult; |
---|
3091 | } else { |
---|
3092 | Scan(throwStatement.Expression); |
---|
3093 | return null; |
---|
3094 | } |
---|
3095 | } |
---|
3096 | |
---|
3097 | ResolveResult IAstVisitor<ResolveResult>.VisitTryCatchStatement(TryCatchStatement tryCatchStatement) |
---|
3098 | { |
---|
3099 | ScanChildren(tryCatchStatement); |
---|
3100 | return voidResult; |
---|
3101 | } |
---|
3102 | |
---|
3103 | ResolveResult IAstVisitor<ResolveResult>.VisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement) |
---|
3104 | { |
---|
3105 | ScanChildren(gotoCaseStatement); |
---|
3106 | return voidResult; |
---|
3107 | } |
---|
3108 | |
---|
3109 | ResolveResult IAstVisitor<ResolveResult>.VisitGotoDefaultStatement(GotoDefaultStatement gotoDefaultStatement) |
---|
3110 | { |
---|
3111 | return voidResult; |
---|
3112 | } |
---|
3113 | |
---|
3114 | ResolveResult IAstVisitor<ResolveResult>.VisitGotoStatement(GotoStatement gotoStatement) |
---|
3115 | { |
---|
3116 | return voidResult; |
---|
3117 | } |
---|
3118 | |
---|
3119 | ResolveResult IAstVisitor<ResolveResult>.VisitLabelStatement(LabelStatement labelStatement) |
---|
3120 | { |
---|
3121 | return voidResult; |
---|
3122 | } |
---|
3123 | |
---|
3124 | ResolveResult IAstVisitor<ResolveResult>.VisitUnsafeStatement(UnsafeStatement unsafeStatement) |
---|
3125 | { |
---|
3126 | resolver = resolver.PushBlock(); |
---|
3127 | ScanChildren(unsafeStatement); |
---|
3128 | resolver = resolver.PopBlock(); |
---|
3129 | return voidResult; |
---|
3130 | } |
---|
3131 | #endregion |
---|
3132 | |
---|
3133 | #region Local Variable Type Inference |
---|
3134 | IVariable MakeVariable(IType type, Identifier variableName) |
---|
3135 | { |
---|
3136 | return new SimpleVariable(MakeRegion(variableName), type, variableName.Name); |
---|
3137 | } |
---|
3138 | |
---|
3139 | IVariable MakeConstant(IType type, Identifier variableName, object constantValue) |
---|
3140 | { |
---|
3141 | return new SimpleConstant(MakeRegion(variableName), type, variableName.Name, constantValue); |
---|
3142 | } |
---|
3143 | |
---|
3144 | class SimpleVariable : IVariable |
---|
3145 | { |
---|
3146 | readonly DomRegion region; |
---|
3147 | readonly IType type; |
---|
3148 | readonly string name; |
---|
3149 | |
---|
3150 | public SimpleVariable(DomRegion region, IType type, string name) |
---|
3151 | { |
---|
3152 | Debug.Assert(type != null); |
---|
3153 | Debug.Assert(name != null); |
---|
3154 | this.region = region; |
---|
3155 | this.type = type; |
---|
3156 | this.name = name; |
---|
3157 | } |
---|
3158 | |
---|
3159 | public SymbolKind SymbolKind { |
---|
3160 | get { return SymbolKind.Variable; } |
---|
3161 | } |
---|
3162 | |
---|
3163 | public string Name { |
---|
3164 | get { return name; } |
---|
3165 | } |
---|
3166 | |
---|
3167 | public DomRegion Region { |
---|
3168 | get { return region; } |
---|
3169 | } |
---|
3170 | |
---|
3171 | public IType Type { |
---|
3172 | get { return type; } |
---|
3173 | } |
---|
3174 | |
---|
3175 | public virtual bool IsConst { |
---|
3176 | get { return false; } |
---|
3177 | } |
---|
3178 | |
---|
3179 | public virtual object ConstantValue { |
---|
3180 | get { return null; } |
---|
3181 | } |
---|
3182 | |
---|
3183 | public override string ToString() |
---|
3184 | { |
---|
3185 | return type.ToString() + " " + name + ";"; |
---|
3186 | } |
---|
3187 | |
---|
3188 | public ISymbolReference ToReference() |
---|
3189 | { |
---|
3190 | return new VariableReference(type.ToTypeReference(), name, region, IsConst, ConstantValue); |
---|
3191 | } |
---|
3192 | } |
---|
3193 | |
---|
3194 | sealed class SimpleConstant : SimpleVariable |
---|
3195 | { |
---|
3196 | readonly object constantValue; |
---|
3197 | |
---|
3198 | public SimpleConstant(DomRegion region, IType type, string name, object constantValue) |
---|
3199 | : base(region, type, name) |
---|
3200 | { |
---|
3201 | this.constantValue = constantValue; |
---|
3202 | } |
---|
3203 | |
---|
3204 | public override bool IsConst { |
---|
3205 | get { return true; } |
---|
3206 | } |
---|
3207 | |
---|
3208 | public override object ConstantValue { |
---|
3209 | get { return constantValue; } |
---|
3210 | } |
---|
3211 | |
---|
3212 | public override string ToString() |
---|
3213 | { |
---|
3214 | return Type.ToString() + " " + Name + " = " + new PrimitiveExpression(constantValue).ToString() + ";"; |
---|
3215 | } |
---|
3216 | } |
---|
3217 | |
---|
3218 | static IType GetElementTypeFromIEnumerable(IType collectionType, ICompilation compilation, bool allowIEnumerator, out bool? isGeneric) |
---|
3219 | { |
---|
3220 | bool foundNonGenericIEnumerable = false; |
---|
3221 | foreach (IType baseType in collectionType.GetAllBaseTypes()) { |
---|
3222 | ITypeDefinition baseTypeDef = baseType.GetDefinition(); |
---|
3223 | if (baseTypeDef != null) { |
---|
3224 | KnownTypeCode typeCode = baseTypeDef.KnownTypeCode; |
---|
3225 | if (typeCode == KnownTypeCode.IEnumerableOfT || (allowIEnumerator && typeCode == KnownTypeCode.IEnumeratorOfT)) { |
---|
3226 | ParameterizedType pt = baseType as ParameterizedType; |
---|
3227 | if (pt != null) { |
---|
3228 | isGeneric = true; |
---|
3229 | return pt.GetTypeArgument(0); |
---|
3230 | } |
---|
3231 | } |
---|
3232 | if (typeCode == KnownTypeCode.IEnumerable || (allowIEnumerator && typeCode == KnownTypeCode.IEnumerator)) |
---|
3233 | foundNonGenericIEnumerable = true; |
---|
3234 | } |
---|
3235 | } |
---|
3236 | // System.Collections.IEnumerable found in type hierarchy -> Object is element type. |
---|
3237 | if (foundNonGenericIEnumerable) { |
---|
3238 | isGeneric = false; |
---|
3239 | return compilation.FindType(KnownTypeCode.Object); |
---|
3240 | } |
---|
3241 | isGeneric = null; |
---|
3242 | return SpecialType.UnknownType; |
---|
3243 | } |
---|
3244 | #endregion |
---|
3245 | |
---|
3246 | #region Attributes |
---|
3247 | ResolveResult IAstVisitor<ResolveResult>.VisitAttribute(Attribute attribute) |
---|
3248 | { |
---|
3249 | var type = ResolveType(attribute.Type); |
---|
3250 | |
---|
3251 | // Separate arguments into ctor arguments and non-ctor arguments: |
---|
3252 | var constructorArguments = attribute.Arguments.Where(a => !(a is NamedExpression)); |
---|
3253 | var nonConstructorArguments = attribute.Arguments.OfType<NamedExpression>(); |
---|
3254 | |
---|
3255 | // Scan the non-constructor arguments |
---|
3256 | resolver = resolver.PushObjectInitializer(new InitializedObjectResolveResult(type)); |
---|
3257 | List<ResolveResult> initializerStatements = new List<ResolveResult>(); |
---|
3258 | foreach (var arg in nonConstructorArguments) |
---|
3259 | HandleNamedExpression(arg, initializerStatements); |
---|
3260 | resolver = resolver.PopObjectInitializer(); |
---|
3261 | |
---|
3262 | // Resolve the ctor arguments and find the matching ctor overload |
---|
3263 | string[] argumentNames; |
---|
3264 | ResolveResult[] arguments = GetArguments(constructorArguments, out argumentNames); |
---|
3265 | ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames, false, initializerStatements); |
---|
3266 | ProcessInvocationResult(null, constructorArguments, rr); |
---|
3267 | return rr; |
---|
3268 | } |
---|
3269 | |
---|
3270 | ResolveResult IAstVisitor<ResolveResult>.VisitAttributeSection(AttributeSection attributeSection) |
---|
3271 | { |
---|
3272 | ScanChildren(attributeSection); |
---|
3273 | return voidResult; |
---|
3274 | } |
---|
3275 | #endregion |
---|
3276 | |
---|
3277 | #region Using Declaration |
---|
3278 | ResolveResult IAstVisitor<ResolveResult>.VisitUsingDeclaration(UsingDeclaration usingDeclaration) |
---|
3279 | { |
---|
3280 | ScanChildren(usingDeclaration); |
---|
3281 | return voidResult; |
---|
3282 | } |
---|
3283 | |
---|
3284 | ResolveResult IAstVisitor<ResolveResult>.VisitUsingAliasDeclaration(UsingAliasDeclaration usingDeclaration) |
---|
3285 | { |
---|
3286 | ScanChildren(usingDeclaration); |
---|
3287 | return voidResult; |
---|
3288 | } |
---|
3289 | |
---|
3290 | ResolveResult IAstVisitor<ResolveResult>.VisitExternAliasDeclaration(ExternAliasDeclaration externAliasDeclaration) |
---|
3291 | { |
---|
3292 | return voidResult; |
---|
3293 | } |
---|
3294 | #endregion |
---|
3295 | |
---|
3296 | #region Type References |
---|
3297 | ResolveResult IAstVisitor<ResolveResult>.VisitPrimitiveType(PrimitiveType primitiveType) |
---|
3298 | { |
---|
3299 | if (!resolverEnabled) |
---|
3300 | return null; |
---|
3301 | KnownTypeCode typeCode = primitiveType.KnownTypeCode; |
---|
3302 | if (typeCode == KnownTypeCode.None && primitiveType.Parent is Constraint && primitiveType.Role == Roles.BaseType) { |
---|
3303 | switch (primitiveType.Keyword) { |
---|
3304 | case "class": |
---|
3305 | case "struct": |
---|
3306 | case "new": |
---|
3307 | return voidResult; |
---|
3308 | } |
---|
3309 | } |
---|
3310 | IType type = resolver.Compilation.FindType(typeCode); |
---|
3311 | return new TypeResolveResult(type); |
---|
3312 | } |
---|
3313 | |
---|
3314 | ResolveResult IAstVisitor<ResolveResult>.VisitSimpleType(SimpleType simpleType) |
---|
3315 | { |
---|
3316 | if (!resolverEnabled) { |
---|
3317 | ScanChildren(simpleType); |
---|
3318 | return null; |
---|
3319 | } |
---|
3320 | |
---|
3321 | // Figure out the correct lookup mode: |
---|
3322 | NameLookupMode lookupMode = simpleType.GetNameLookupMode(); |
---|
3323 | |
---|
3324 | var typeArguments = ResolveTypeArguments(simpleType.TypeArguments); |
---|
3325 | Identifier identifier = simpleType.IdentifierToken; |
---|
3326 | if (string.IsNullOrEmpty(identifier.Name)) |
---|
3327 | return new TypeResolveResult(SpecialType.UnboundTypeArgument); |
---|
3328 | ResolveResult rr = resolver.LookupSimpleNameOrTypeName(identifier.Name, typeArguments, lookupMode); |
---|
3329 | if (simpleType.Parent is Attribute && !identifier.IsVerbatim) { |
---|
3330 | var withSuffix = resolver.LookupSimpleNameOrTypeName(identifier.Name + "Attribute", typeArguments, lookupMode); |
---|
3331 | if (AttributeTypeReference.PreferAttributeTypeWithSuffix(rr.Type, withSuffix.Type, resolver.Compilation)) |
---|
3332 | return withSuffix; |
---|
3333 | } |
---|
3334 | return rr; |
---|
3335 | } |
---|
3336 | |
---|
3337 | ResolveResult IAstVisitor<ResolveResult>.VisitMemberType(MemberType memberType) |
---|
3338 | { |
---|
3339 | ResolveResult target; |
---|
3340 | NameLookupMode lookupMode = memberType.GetNameLookupMode(); |
---|
3341 | if (memberType.IsDoubleColon && memberType.Target is SimpleType) { |
---|
3342 | SimpleType t = (SimpleType)memberType.Target; |
---|
3343 | StoreCurrentState(t); |
---|
3344 | target = resolver.ResolveAlias(t.Identifier); |
---|
3345 | StoreResult(t, target); |
---|
3346 | } else { |
---|
3347 | if (!resolverEnabled) { |
---|
3348 | ScanChildren(memberType); |
---|
3349 | return null; |
---|
3350 | } |
---|
3351 | target = Resolve(memberType.Target); |
---|
3352 | } |
---|
3353 | var typeArguments = ResolveTypeArguments(memberType.TypeArguments); |
---|
3354 | Identifier identifier = memberType.MemberNameToken; |
---|
3355 | ResolveResult rr = resolver.ResolveMemberAccess(target, identifier.Name, typeArguments, lookupMode); |
---|
3356 | if (memberType.Parent is Attribute && !identifier.IsVerbatim) { |
---|
3357 | var withSuffix = resolver.ResolveMemberAccess(target, identifier.Name + "Attribute", typeArguments, lookupMode); |
---|
3358 | if (AttributeTypeReference.PreferAttributeTypeWithSuffix(rr.Type, withSuffix.Type, resolver.Compilation)) |
---|
3359 | return withSuffix; |
---|
3360 | } |
---|
3361 | return rr; |
---|
3362 | } |
---|
3363 | |
---|
3364 | ResolveResult IAstVisitor<ResolveResult>.VisitComposedType(ComposedType composedType) |
---|
3365 | { |
---|
3366 | if (!resolverEnabled) { |
---|
3367 | ScanChildren(composedType); |
---|
3368 | return null; |
---|
3369 | } |
---|
3370 | IType t = ResolveType(composedType.BaseType); |
---|
3371 | if (composedType.HasNullableSpecifier) { |
---|
3372 | t = NullableType.Create(resolver.Compilation, t); |
---|
3373 | } |
---|
3374 | for (int i = 0; i < composedType.PointerRank; i++) { |
---|
3375 | t = new PointerType(t); |
---|
3376 | } |
---|
3377 | foreach (var a in composedType.ArraySpecifiers.Reverse()) { |
---|
3378 | t = new ArrayType(resolver.Compilation, t, a.Dimensions); |
---|
3379 | } |
---|
3380 | return new TypeResolveResult(t); |
---|
3381 | } |
---|
3382 | #endregion |
---|
3383 | |
---|
3384 | #region Query Expressions |
---|
3385 | ResolveResult IAstVisitor<ResolveResult>.VisitQueryExpression(QueryExpression queryExpression) |
---|
3386 | { |
---|
3387 | resolver = resolver.PushBlock(); |
---|
3388 | var oldQueryResult = currentQueryResult; |
---|
3389 | var oldCancellationToken = cancellationToken; |
---|
3390 | try { |
---|
3391 | // Because currentQueryResult isn't part of the stored state, |
---|
3392 | // query expressions must be resolved in a single operation. |
---|
3393 | // This means we can't allow cancellation within the query expression. |
---|
3394 | cancellationToken = CancellationToken.None; |
---|
3395 | currentQueryResult = null; |
---|
3396 | foreach (var clause in queryExpression.Clauses) { |
---|
3397 | currentQueryResult = Resolve(clause); |
---|
3398 | } |
---|
3399 | return WrapResult(currentQueryResult); |
---|
3400 | } finally { |
---|
3401 | currentQueryResult = oldQueryResult; |
---|
3402 | cancellationToken = oldCancellationToken; |
---|
3403 | resolver = resolver.PopBlock(); |
---|
3404 | } |
---|
3405 | } |
---|
3406 | |
---|
3407 | IType GetTypeForQueryVariable(IType type) |
---|
3408 | { |
---|
3409 | bool? isGeneric; |
---|
3410 | // This assumes queries are only used on IEnumerable. |
---|
3411 | var result = GetElementTypeFromIEnumerable(type, resolver.Compilation, false, out isGeneric); |
---|
3412 | |
---|
3413 | // If that fails try to resolve the Select method and resolve the projection. |
---|
3414 | if (result.Kind == TypeKind.Unknown) { |
---|
3415 | var selectAccess = resolver.ResolveMemberAccess(new ResolveResult (type), "Select", EmptyList<IType>.Instance); |
---|
3416 | ResolveResult[] arguments = { |
---|
3417 | new QueryExpressionLambda(1, voidResult) |
---|
3418 | }; |
---|
3419 | |
---|
3420 | var rr = resolver.ResolveInvocation(selectAccess, arguments) as CSharpInvocationResolveResult; |
---|
3421 | if (rr != null && rr.Arguments.Count == 2) { |
---|
3422 | var invokeMethod = rr.Arguments[1].Type.GetDelegateInvokeMethod(); |
---|
3423 | if (invokeMethod != null && invokeMethod.Parameters.Count > 0) |
---|
3424 | return invokeMethod.Parameters[0].Type; |
---|
3425 | } |
---|
3426 | } |
---|
3427 | return result; |
---|
3428 | } |
---|
3429 | |
---|
3430 | ResolveResult MakeTransparentIdentifierResolveResult() |
---|
3431 | { |
---|
3432 | return new ResolveResult(new AnonymousType(resolver.Compilation, EmptyList<IUnresolvedProperty>.Instance)); |
---|
3433 | } |
---|
3434 | |
---|
3435 | sealed class QueryExpressionLambdaConversion : Conversion |
---|
3436 | { |
---|
3437 | internal readonly IType[] ParameterTypes; |
---|
3438 | |
---|
3439 | public QueryExpressionLambdaConversion(IType[] parameterTypes) |
---|
3440 | { |
---|
3441 | this.ParameterTypes = parameterTypes; |
---|
3442 | } |
---|
3443 | |
---|
3444 | public override bool IsImplicit { |
---|
3445 | get { return true; } |
---|
3446 | } |
---|
3447 | |
---|
3448 | public override bool IsAnonymousFunctionConversion { |
---|
3449 | get { return true; } |
---|
3450 | } |
---|
3451 | } |
---|
3452 | |
---|
3453 | sealed class QueryExpressionLambda : LambdaResolveResult |
---|
3454 | { |
---|
3455 | readonly IParameter[] parameters; |
---|
3456 | readonly ResolveResult bodyExpression; |
---|
3457 | |
---|
3458 | internal IType[] inferredParameterTypes; |
---|
3459 | |
---|
3460 | public QueryExpressionLambda(int parameterCount, ResolveResult bodyExpression) |
---|
3461 | { |
---|
3462 | this.parameters = new IParameter[parameterCount]; |
---|
3463 | for (int i = 0; i < parameterCount; i++) { |
---|
3464 | parameters[i] = new DefaultParameter(SpecialType.UnknownType, "x" + i); |
---|
3465 | } |
---|
3466 | this.bodyExpression = bodyExpression; |
---|
3467 | } |
---|
3468 | |
---|
3469 | public override IList<IParameter> Parameters { |
---|
3470 | get { return parameters; } |
---|
3471 | } |
---|
3472 | |
---|
3473 | public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions) |
---|
3474 | { |
---|
3475 | if (parameterTypes.Length == parameters.Length) { |
---|
3476 | this.inferredParameterTypes = parameterTypes; |
---|
3477 | return new QueryExpressionLambdaConversion(parameterTypes); |
---|
3478 | } else { |
---|
3479 | return Conversion.None; |
---|
3480 | } |
---|
3481 | } |
---|
3482 | |
---|
3483 | public override bool IsAsync { |
---|
3484 | get { return false; } |
---|
3485 | } |
---|
3486 | |
---|
3487 | public override bool IsImplicitlyTyped { |
---|
3488 | get { return true; } |
---|
3489 | } |
---|
3490 | |
---|
3491 | public override bool IsAnonymousMethod { |
---|
3492 | get { return false; } |
---|
3493 | } |
---|
3494 | |
---|
3495 | public override bool HasParameterList { |
---|
3496 | get { return true; } |
---|
3497 | } |
---|
3498 | |
---|
3499 | public override ResolveResult Body { |
---|
3500 | get { return bodyExpression; } |
---|
3501 | } |
---|
3502 | |
---|
3503 | public override IType GetInferredReturnType(IType[] parameterTypes) |
---|
3504 | { |
---|
3505 | return bodyExpression.Type; |
---|
3506 | } |
---|
3507 | |
---|
3508 | public override IType ReturnType { |
---|
3509 | get { |
---|
3510 | return bodyExpression.Type; |
---|
3511 | } |
---|
3512 | } |
---|
3513 | |
---|
3514 | public override string ToString() |
---|
3515 | { |
---|
3516 | return string.Format("[QueryExpressionLambda ({0}) => {1}]", string.Join(",", parameters.Select(p => p.Name)), bodyExpression); |
---|
3517 | } |
---|
3518 | } |
---|
3519 | |
---|
3520 | QueryClause GetPreviousQueryClause(QueryClause clause) |
---|
3521 | { |
---|
3522 | for (AstNode node = clause.PrevSibling; node != null; node = node.PrevSibling) { |
---|
3523 | if (node.Role == QueryExpression.ClauseRole) |
---|
3524 | return (QueryClause)node; |
---|
3525 | } |
---|
3526 | return null; |
---|
3527 | } |
---|
3528 | |
---|
3529 | QueryClause GetNextQueryClause(QueryClause clause) |
---|
3530 | { |
---|
3531 | for (AstNode node = clause.NextSibling; node != null; node = node.NextSibling) { |
---|
3532 | if (node.Role == QueryExpression.ClauseRole) |
---|
3533 | return (QueryClause)node; |
---|
3534 | } |
---|
3535 | return null; |
---|
3536 | } |
---|
3537 | |
---|
3538 | ResolveResult IAstVisitor<ResolveResult>.VisitQueryFromClause(QueryFromClause queryFromClause) |
---|
3539 | { |
---|
3540 | ResolveResult result = errorResult; |
---|
3541 | ResolveResult expr = Resolve(queryFromClause.Expression); |
---|
3542 | IVariable v; |
---|
3543 | if (queryFromClause.Type.IsNull) { |
---|
3544 | v = MakeVariable(GetTypeForQueryVariable(expr.Type), queryFromClause.IdentifierToken); |
---|
3545 | result = expr; |
---|
3546 | } else { |
---|
3547 | v = MakeVariable(ResolveType(queryFromClause.Type), queryFromClause.IdentifierToken); |
---|
3548 | |
---|
3549 | // resolve the .Cast<>() call |
---|
3550 | ResolveResult methodGroup = resolver.ResolveMemberAccess(expr, "Cast", new[] { v.Type }, NameLookupMode.InvocationTarget); |
---|
3551 | result = resolver.ResolveInvocation(methodGroup, new ResolveResult[0]); |
---|
3552 | } |
---|
3553 | |
---|
3554 | StoreCurrentState(queryFromClause.IdentifierToken); |
---|
3555 | resolver = resolver.AddVariable(v); |
---|
3556 | StoreResult(queryFromClause.IdentifierToken, new LocalResolveResult(v)); |
---|
3557 | |
---|
3558 | if (currentQueryResult != null) { |
---|
3559 | // this is a second 'from': resolve the .SelectMany() call |
---|
3560 | QuerySelectClause selectClause = GetNextQueryClause(queryFromClause) as QuerySelectClause; |
---|
3561 | ResolveResult selectResult; |
---|
3562 | if (selectClause != null) { |
---|
3563 | // from ... from ... select - the SelectMany call also performs the Select operation |
---|
3564 | selectResult = Resolve(selectClause.Expression); |
---|
3565 | } else { |
---|
3566 | // from .. from ... ... - introduce a transparent identifier |
---|
3567 | selectResult = MakeTransparentIdentifierResolveResult(); |
---|
3568 | } |
---|
3569 | ResolveResult methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "SelectMany", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget); |
---|
3570 | ResolveResult[] arguments = { |
---|
3571 | new QueryExpressionLambda(1, result), |
---|
3572 | new QueryExpressionLambda(2, selectResult) |
---|
3573 | }; |
---|
3574 | result = resolver.ResolveInvocation(methodGroup, arguments); |
---|
3575 | } |
---|
3576 | if (result == expr) |
---|
3577 | return WrapResult(result); |
---|
3578 | else |
---|
3579 | return result; |
---|
3580 | } |
---|
3581 | |
---|
3582 | /// <summary> |
---|
3583 | /// Wraps the result in an identity conversion. |
---|
3584 | /// This is necessary so that '$from x in variable$ select x*2' does not resolve |
---|
3585 | /// to the LocalResolveResult for the variable, which would confuse find references. |
---|
3586 | /// </summary> |
---|
3587 | ResolveResult WrapResult(ResolveResult result) |
---|
3588 | { |
---|
3589 | return new CastResolveResult(result.Type, result, Conversion.IdentityConversion, resolver.CheckForOverflow); |
---|
3590 | } |
---|
3591 | |
---|
3592 | ResolveResult IAstVisitor<ResolveResult>.VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause) |
---|
3593 | { |
---|
3594 | ResolveResult rr = Resolve(queryContinuationClause.PrecedingQuery); |
---|
3595 | IType variableType = GetTypeForQueryVariable(rr.Type); |
---|
3596 | StoreCurrentState(queryContinuationClause.IdentifierToken); |
---|
3597 | IVariable v = MakeVariable(variableType, queryContinuationClause.IdentifierToken); |
---|
3598 | resolver = resolver.AddVariable(v); |
---|
3599 | StoreResult(queryContinuationClause.IdentifierToken, new LocalResolveResult(v)); |
---|
3600 | return WrapResult(rr); |
---|
3601 | } |
---|
3602 | |
---|
3603 | ResolveResult IAstVisitor<ResolveResult>.VisitQueryLetClause(QueryLetClause queryLetClause) |
---|
3604 | { |
---|
3605 | ResolveResult expr = Resolve(queryLetClause.Expression); |
---|
3606 | StoreCurrentState(queryLetClause.IdentifierToken); |
---|
3607 | IVariable v = MakeVariable(expr.Type, queryLetClause.IdentifierToken); |
---|
3608 | resolver = resolver.AddVariable(v); |
---|
3609 | StoreResult(queryLetClause.IdentifierToken, new LocalResolveResult(v)); |
---|
3610 | if (currentQueryResult != null) { |
---|
3611 | // resolve the .Select() call |
---|
3612 | ResolveResult methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Select", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget); |
---|
3613 | ResolveResult[] arguments = { new QueryExpressionLambda(1, MakeTransparentIdentifierResolveResult()) }; |
---|
3614 | return resolver.ResolveInvocation(methodGroup, arguments); |
---|
3615 | } else { |
---|
3616 | return errorResult; |
---|
3617 | } |
---|
3618 | } |
---|
3619 | |
---|
3620 | ResolveResult IAstVisitor<ResolveResult>.VisitQueryJoinClause(QueryJoinClause queryJoinClause) |
---|
3621 | { |
---|
3622 | // join v in expr on onExpr equals equalsExpr [into g] |
---|
3623 | ResolveResult inResult = null; |
---|
3624 | ResolveResult expr = Resolve(queryJoinClause.InExpression); |
---|
3625 | IType variableType; |
---|
3626 | if (queryJoinClause.Type.IsNull) { |
---|
3627 | variableType = GetTypeForQueryVariable(expr.Type); |
---|
3628 | inResult = expr; |
---|
3629 | } else { |
---|
3630 | variableType = ResolveType(queryJoinClause.Type); |
---|
3631 | |
---|
3632 | // resolve the .Cast<>() call |
---|
3633 | ResolveResult methodGroup = resolver.ResolveMemberAccess(expr, "Cast", new[] { variableType }, NameLookupMode.InvocationTarget); |
---|
3634 | inResult = resolver.ResolveInvocation(methodGroup, new ResolveResult[0]); |
---|
3635 | } |
---|
3636 | |
---|
3637 | // resolve the 'On' expression in a context that contains only the previously existing range variables: |
---|
3638 | // (before adding any variable) |
---|
3639 | ResolveResult onResult = Resolve(queryJoinClause.OnExpression); |
---|
3640 | |
---|
3641 | // scan the 'Equals' expression in a context that contains only the variable 'v' |
---|
3642 | CSharpResolver resolverOutsideQuery = resolver; |
---|
3643 | resolverOutsideQuery = resolverOutsideQuery.PopBlock(); // pop all variables from the current query expression |
---|
3644 | IVariable v = MakeVariable(variableType, queryJoinClause.JoinIdentifierToken); |
---|
3645 | resolverOutsideQuery = resolverOutsideQuery.AddVariable(v); |
---|
3646 | ResolveResult equalsResult = errorResult; |
---|
3647 | ResetContext(resolverOutsideQuery, delegate { |
---|
3648 | equalsResult = Resolve(queryJoinClause.EqualsExpression); |
---|
3649 | }); |
---|
3650 | StoreCurrentState(queryJoinClause.JoinIdentifierToken); |
---|
3651 | StoreResult(queryJoinClause.JoinIdentifierToken, new LocalResolveResult(v)); |
---|
3652 | |
---|
3653 | if (queryJoinClause.IsGroupJoin) { |
---|
3654 | return ResolveGroupJoin(queryJoinClause, inResult, onResult, equalsResult); |
---|
3655 | } else { |
---|
3656 | resolver = resolver.AddVariable(v); |
---|
3657 | if (currentQueryResult != null) { |
---|
3658 | QuerySelectClause selectClause = GetNextQueryClause(queryJoinClause) as QuerySelectClause; |
---|
3659 | ResolveResult selectResult; |
---|
3660 | if (selectClause != null) { |
---|
3661 | // from ... join ... select - the Join call also performs the Select operation |
---|
3662 | selectResult = Resolve(selectClause.Expression); |
---|
3663 | } else { |
---|
3664 | // from .. join ... ... - introduce a transparent identifier |
---|
3665 | selectResult = MakeTransparentIdentifierResolveResult(); |
---|
3666 | } |
---|
3667 | |
---|
3668 | var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Join", EmptyList<IType>.Instance); |
---|
3669 | ResolveResult[] arguments = { |
---|
3670 | inResult, |
---|
3671 | new QueryExpressionLambda(1, onResult), |
---|
3672 | new QueryExpressionLambda(1, equalsResult), |
---|
3673 | new QueryExpressionLambda(2, selectResult) |
---|
3674 | }; |
---|
3675 | return resolver.ResolveInvocation(methodGroup, arguments); |
---|
3676 | } else { |
---|
3677 | return errorResult; |
---|
3678 | } |
---|
3679 | } |
---|
3680 | } |
---|
3681 | |
---|
3682 | ResolveResult ResolveGroupJoin(QueryJoinClause queryJoinClause, |
---|
3683 | ResolveResult inResult, ResolveResult onResult, ResolveResult equalsResult) |
---|
3684 | { |
---|
3685 | Debug.Assert(queryJoinClause.IsGroupJoin); |
---|
3686 | |
---|
3687 | DomRegion intoIdentifierRegion = MakeRegion(queryJoinClause.IntoIdentifierToken); |
---|
3688 | |
---|
3689 | // We need to declare the group variable, but it's a bit tricky to determine its type: |
---|
3690 | // We'll have to resolve the GroupJoin invocation and take a look at the inferred types |
---|
3691 | // for the lambda given as last parameter. |
---|
3692 | var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "GroupJoin", EmptyList<IType>.Instance); |
---|
3693 | QuerySelectClause selectClause = GetNextQueryClause(queryJoinClause) as QuerySelectClause; |
---|
3694 | LambdaResolveResult groupJoinLambda; |
---|
3695 | if (selectClause != null) { |
---|
3696 | // from ... join ... into g select - the GroupJoin call also performs the Select operation |
---|
3697 | IParameter[] selectLambdaParameters = { |
---|
3698 | new DefaultParameter(SpecialType.UnknownType, "<>transparentIdentifier"), |
---|
3699 | new DefaultParameter(SpecialType.UnknownType, queryJoinClause.IntoIdentifier, region: intoIdentifierRegion) |
---|
3700 | }; |
---|
3701 | groupJoinLambda = new ImplicitlyTypedLambda(selectClause, selectLambdaParameters, this); |
---|
3702 | } else { |
---|
3703 | // from .. join ... ... - introduce a transparent identifier |
---|
3704 | groupJoinLambda = new QueryExpressionLambda(2, MakeTransparentIdentifierResolveResult()); |
---|
3705 | } |
---|
3706 | |
---|
3707 | ResolveResult[] arguments = { |
---|
3708 | inResult, |
---|
3709 | new QueryExpressionLambda(1, onResult), |
---|
3710 | new QueryExpressionLambda(1, equalsResult), |
---|
3711 | groupJoinLambda |
---|
3712 | }; |
---|
3713 | ResolveResult rr = resolver.ResolveInvocation(methodGroup, arguments); |
---|
3714 | InvocationResolveResult invocationRR = rr as InvocationResolveResult; |
---|
3715 | |
---|
3716 | IVariable groupVariable; |
---|
3717 | if (groupJoinLambda is ImplicitlyTypedLambda) { |
---|
3718 | var implicitlyTypedLambda = (ImplicitlyTypedLambda)groupJoinLambda; |
---|
3719 | |
---|
3720 | if (invocationRR != null && invocationRR.Arguments.Count > 0) { |
---|
3721 | ConversionResolveResult crr = invocationRR.Arguments[invocationRR.Arguments.Count - 1] as ConversionResolveResult; |
---|
3722 | if (crr != null) |
---|
3723 | ProcessConversion(null, crr.Input, crr.Conversion, crr.Type); |
---|
3724 | } |
---|
3725 | |
---|
3726 | implicitlyTypedLambda.EnforceMerge(this); |
---|
3727 | if (implicitlyTypedLambda.Parameters.Count == 2) { |
---|
3728 | StoreCurrentState(queryJoinClause.IntoIdentifierToken); |
---|
3729 | groupVariable = implicitlyTypedLambda.Parameters[1]; |
---|
3730 | } else { |
---|
3731 | groupVariable = null; |
---|
3732 | } |
---|
3733 | } else { |
---|
3734 | Debug.Assert(groupJoinLambda is QueryExpressionLambda); |
---|
3735 | |
---|
3736 | // Add the variable if the query expression continues after the group join |
---|
3737 | // (there's no need to do this if there's only a select clause remaining, as |
---|
3738 | // we already handled that in the ImplicitlyTypedLambda). |
---|
3739 | |
---|
3740 | // Get the inferred type of the group variable: |
---|
3741 | IType[] inferredParameterTypes = null; |
---|
3742 | if (invocationRR != null && invocationRR.Arguments.Count > 0) { |
---|
3743 | ConversionResolveResult crr = invocationRR.Arguments[invocationRR.Arguments.Count - 1] as ConversionResolveResult; |
---|
3744 | if (crr != null && crr.Conversion is QueryExpressionLambdaConversion) { |
---|
3745 | inferredParameterTypes = ((QueryExpressionLambdaConversion)crr.Conversion).ParameterTypes; |
---|
3746 | } |
---|
3747 | } |
---|
3748 | if (inferredParameterTypes == null) |
---|
3749 | inferredParameterTypes = ((QueryExpressionLambda)groupJoinLambda).inferredParameterTypes; |
---|
3750 | |
---|
3751 | IType groupParameterType; |
---|
3752 | if (inferredParameterTypes != null && inferredParameterTypes.Length == 2) |
---|
3753 | groupParameterType = inferredParameterTypes[1]; |
---|
3754 | else |
---|
3755 | groupParameterType = SpecialType.UnknownType; |
---|
3756 | |
---|
3757 | StoreCurrentState(queryJoinClause.IntoIdentifierToken); |
---|
3758 | groupVariable = MakeVariable(groupParameterType, queryJoinClause.IntoIdentifierToken); |
---|
3759 | resolver = resolver.AddVariable(groupVariable); |
---|
3760 | } |
---|
3761 | |
---|
3762 | if (groupVariable != null) { |
---|
3763 | StoreResult(queryJoinClause.IntoIdentifierToken, new LocalResolveResult(groupVariable)); |
---|
3764 | } |
---|
3765 | |
---|
3766 | return rr; |
---|
3767 | } |
---|
3768 | |
---|
3769 | ResolveResult IAstVisitor<ResolveResult>.VisitQueryWhereClause(QueryWhereClause queryWhereClause) |
---|
3770 | { |
---|
3771 | ResolveResult condition = Resolve(queryWhereClause.Condition); |
---|
3772 | IType boolType = resolver.Compilation.FindType(KnownTypeCode.Boolean); |
---|
3773 | Conversion conversionToBool = resolver.conversions.ImplicitConversion(condition, boolType); |
---|
3774 | ProcessConversion(queryWhereClause.Condition, condition, conversionToBool, boolType); |
---|
3775 | if (currentQueryResult != null) { |
---|
3776 | if (conversionToBool != Conversion.IdentityConversion && conversionToBool != Conversion.None) { |
---|
3777 | condition = new ConversionResolveResult(boolType, condition, conversionToBool, resolver.CheckForOverflow); |
---|
3778 | } |
---|
3779 | |
---|
3780 | var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Where", EmptyList<IType>.Instance); |
---|
3781 | ResolveResult[] arguments = { new QueryExpressionLambda(1, condition) }; |
---|
3782 | return resolver.ResolveInvocation(methodGroup, arguments); |
---|
3783 | } else { |
---|
3784 | return errorResult; |
---|
3785 | } |
---|
3786 | } |
---|
3787 | |
---|
3788 | ResolveResult IAstVisitor<ResolveResult>.VisitQuerySelectClause(QuerySelectClause querySelectClause) |
---|
3789 | { |
---|
3790 | if (currentQueryResult == null) { |
---|
3791 | ScanChildren(querySelectClause); |
---|
3792 | return errorResult; |
---|
3793 | } |
---|
3794 | QueryClause previousQueryClause = GetPreviousQueryClause(querySelectClause); |
---|
3795 | // If the 'select' follows on a 'SelectMany', 'Join' or 'GroupJoin' clause, then the 'select' portion |
---|
3796 | // was already done as part of the previous clause. |
---|
3797 | if (((previousQueryClause is QueryFromClause && GetPreviousQueryClause(previousQueryClause) != null)) |
---|
3798 | || previousQueryClause is QueryJoinClause) |
---|
3799 | { |
---|
3800 | // GroupJoin already scans the following select clause in a different context, |
---|
3801 | // so we must not scan it again. |
---|
3802 | if (!(previousQueryClause is QueryJoinClause && ((QueryJoinClause)previousQueryClause).IsGroupJoin)) |
---|
3803 | Scan(querySelectClause.Expression); |
---|
3804 | return WrapResult(currentQueryResult); |
---|
3805 | } |
---|
3806 | |
---|
3807 | QueryExpression query = querySelectClause.Parent as QueryExpression; |
---|
3808 | string rangeVariable = GetSingleRangeVariable(query); |
---|
3809 | if (rangeVariable != null) { |
---|
3810 | IdentifierExpression ident = ParenthesizedExpression.UnpackParenthesizedExpression(querySelectClause.Expression) as IdentifierExpression; |
---|
3811 | if (ident != null && ident.Identifier == rangeVariable && !ident.TypeArguments.Any()) { |
---|
3812 | // selecting the single identifier that is the range variable |
---|
3813 | if (query.Clauses.Count > 2) { |
---|
3814 | // only if the query is not degenerate: |
---|
3815 | // the Select call will be optimized away, so directly return the previous result |
---|
3816 | Scan(querySelectClause.Expression); |
---|
3817 | return WrapResult(currentQueryResult); |
---|
3818 | } |
---|
3819 | } |
---|
3820 | } |
---|
3821 | |
---|
3822 | ResolveResult expr = Resolve(querySelectClause.Expression); |
---|
3823 | var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Select", EmptyList<IType>.Instance); |
---|
3824 | ResolveResult[] arguments = { new QueryExpressionLambda(1, expr) }; |
---|
3825 | return resolver.ResolveInvocation(methodGroup, arguments); |
---|
3826 | } |
---|
3827 | |
---|
3828 | /// <summary> |
---|
3829 | /// Gets the name of the range variable in the specified query. |
---|
3830 | /// If the query has multiple range variables, this method returns null. |
---|
3831 | /// </summary> |
---|
3832 | string GetSingleRangeVariable(QueryExpression query) |
---|
3833 | { |
---|
3834 | if (query == null) |
---|
3835 | return null; |
---|
3836 | foreach (QueryClause clause in query.Clauses.Skip(1)) { |
---|
3837 | if (clause is QueryFromClause || clause is QueryJoinClause || clause is QueryLetClause) { |
---|
3838 | // query has more than 1 range variable |
---|
3839 | return null; |
---|
3840 | } |
---|
3841 | } |
---|
3842 | QueryFromClause fromClause = query.Clauses.FirstOrDefault() as QueryFromClause; |
---|
3843 | if (fromClause != null) |
---|
3844 | return fromClause.Identifier; |
---|
3845 | QueryContinuationClause continuationClause = query.Clauses.FirstOrDefault() as QueryContinuationClause; |
---|
3846 | if (continuationClause != null) |
---|
3847 | return continuationClause.Identifier; |
---|
3848 | return null; |
---|
3849 | } |
---|
3850 | |
---|
3851 | ResolveResult IAstVisitor<ResolveResult>.VisitQueryGroupClause(QueryGroupClause queryGroupClause) |
---|
3852 | { |
---|
3853 | if (currentQueryResult == null) { |
---|
3854 | ScanChildren(queryGroupClause); |
---|
3855 | return errorResult; |
---|
3856 | } |
---|
3857 | |
---|
3858 | // ... group projection by key |
---|
3859 | ResolveResult projection = Resolve(queryGroupClause.Projection); |
---|
3860 | ResolveResult key = Resolve(queryGroupClause.Key); |
---|
3861 | |
---|
3862 | var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "GroupBy", EmptyList<IType>.Instance); |
---|
3863 | ResolveResult[] arguments = { |
---|
3864 | new QueryExpressionLambda(1, key), |
---|
3865 | new QueryExpressionLambda(1, projection) |
---|
3866 | }; |
---|
3867 | return resolver.ResolveInvocation(methodGroup, arguments); |
---|
3868 | } |
---|
3869 | |
---|
3870 | ResolveResult IAstVisitor<ResolveResult>.VisitQueryOrderClause(QueryOrderClause queryOrderClause) |
---|
3871 | { |
---|
3872 | foreach (QueryOrdering ordering in queryOrderClause.Orderings) { |
---|
3873 | currentQueryResult = Resolve(ordering); |
---|
3874 | } |
---|
3875 | return WrapResult(currentQueryResult); |
---|
3876 | } |
---|
3877 | |
---|
3878 | ResolveResult IAstVisitor<ResolveResult>.VisitQueryOrdering(QueryOrdering queryOrdering) |
---|
3879 | { |
---|
3880 | if (currentQueryResult == null) { |
---|
3881 | ScanChildren(queryOrdering); |
---|
3882 | return errorResult; |
---|
3883 | } |
---|
3884 | // ... orderby sortKey [descending] |
---|
3885 | ResolveResult sortKey = Resolve(queryOrdering.Expression); |
---|
3886 | |
---|
3887 | QueryOrderClause parentClause = queryOrdering.Parent as QueryOrderClause; |
---|
3888 | bool isFirst = (parentClause == null || parentClause.Orderings.FirstOrDefault() == queryOrdering); |
---|
3889 | string methodName = isFirst ? "OrderBy" : "ThenBy"; |
---|
3890 | if (queryOrdering.Direction == QueryOrderingDirection.Descending) |
---|
3891 | methodName += "Descending"; |
---|
3892 | |
---|
3893 | var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, methodName, EmptyList<IType>.Instance); |
---|
3894 | ResolveResult[] arguments = { |
---|
3895 | new QueryExpressionLambda(1, sortKey), |
---|
3896 | }; |
---|
3897 | return resolver.ResolveInvocation(methodGroup, arguments); |
---|
3898 | } |
---|
3899 | #endregion |
---|
3900 | |
---|
3901 | #region Constructor Initializer |
---|
3902 | ResolveResult IAstVisitor<ResolveResult>.VisitConstructorInitializer(ConstructorInitializer constructorInitializer) |
---|
3903 | { |
---|
3904 | ResolveResult target; |
---|
3905 | if (constructorInitializer.ConstructorInitializerType == ConstructorInitializerType.Base) { |
---|
3906 | target = resolver.ResolveBaseReference(); |
---|
3907 | } else { |
---|
3908 | target = resolver.ResolveThisReference(); |
---|
3909 | } |
---|
3910 | string[] argumentNames; |
---|
3911 | ResolveResult[] arguments = GetArguments(constructorInitializer.Arguments, out argumentNames); |
---|
3912 | ResolveResult rr = resolver.ResolveObjectCreation(target.Type, arguments, argumentNames, allowProtectedAccess: true); |
---|
3913 | ProcessInvocationResult(null, constructorInitializer.Arguments, rr); |
---|
3914 | return rr; |
---|
3915 | } |
---|
3916 | #endregion |
---|
3917 | |
---|
3918 | #region Other Nodes |
---|
3919 | // Token nodes |
---|
3920 | ResolveResult IAstVisitor<ResolveResult>.VisitIdentifier(Identifier identifier) |
---|
3921 | { |
---|
3922 | return null; |
---|
3923 | } |
---|
3924 | |
---|
3925 | ResolveResult IAstVisitor<ResolveResult>.VisitComment (Comment comment) |
---|
3926 | { |
---|
3927 | return null; |
---|
3928 | } |
---|
3929 | |
---|
3930 | ResolveResult IAstVisitor<ResolveResult>.VisitNewLine (NewLineNode comment) |
---|
3931 | { |
---|
3932 | return null; |
---|
3933 | } |
---|
3934 | |
---|
3935 | ResolveResult IAstVisitor<ResolveResult>.VisitWhitespace(WhitespaceNode whitespaceNode) |
---|
3936 | { |
---|
3937 | return null; |
---|
3938 | } |
---|
3939 | |
---|
3940 | ResolveResult IAstVisitor<ResolveResult>.VisitText(TextNode textNode) |
---|
3941 | { |
---|
3942 | return null; |
---|
3943 | } |
---|
3944 | |
---|
3945 | ResolveResult IAstVisitor<ResolveResult>.VisitPreProcessorDirective (PreProcessorDirective preProcessorDirective) |
---|
3946 | { |
---|
3947 | return null; |
---|
3948 | } |
---|
3949 | |
---|
3950 | ResolveResult IAstVisitor<ResolveResult>.VisitCSharpTokenNode(CSharpTokenNode cSharpTokenNode) |
---|
3951 | { |
---|
3952 | return null; |
---|
3953 | } |
---|
3954 | |
---|
3955 | ResolveResult IAstVisitor<ResolveResult>.VisitArraySpecifier(ArraySpecifier arraySpecifier) |
---|
3956 | { |
---|
3957 | return null; |
---|
3958 | } |
---|
3959 | |
---|
3960 | ResolveResult IAstVisitor<ResolveResult>.VisitNullNode(AstNode nullNode) |
---|
3961 | { |
---|
3962 | return null; |
---|
3963 | } |
---|
3964 | |
---|
3965 | ResolveResult IAstVisitor<ResolveResult>.VisitErrorNode(AstNode errorNode) |
---|
3966 | { |
---|
3967 | return null; |
---|
3968 | } |
---|
3969 | |
---|
3970 | ResolveResult IAstVisitor<ResolveResult>.VisitPatternPlaceholder(AstNode placeholder, ICSharpCode.NRefactory.PatternMatching.Pattern pattern) |
---|
3971 | { |
---|
3972 | return null; |
---|
3973 | } |
---|
3974 | |
---|
3975 | // Nodes where we just need to visit the children: |
---|
3976 | ResolveResult IAstVisitor<ResolveResult>.VisitAccessor(Accessor accessor) |
---|
3977 | { |
---|
3978 | ScanChildren(accessor); |
---|
3979 | return voidResult; |
---|
3980 | } |
---|
3981 | |
---|
3982 | ResolveResult IAstVisitor<ResolveResult>.VisitSwitchSection(SwitchSection switchSection) |
---|
3983 | { |
---|
3984 | ScanChildren(switchSection); |
---|
3985 | return voidResult; |
---|
3986 | } |
---|
3987 | |
---|
3988 | ResolveResult IAstVisitor<ResolveResult>.VisitCaseLabel(CaseLabel caseLabel) |
---|
3989 | { |
---|
3990 | ScanChildren(caseLabel); |
---|
3991 | return voidResult; |
---|
3992 | } |
---|
3993 | |
---|
3994 | ResolveResult IAstVisitor<ResolveResult>.VisitConstraint(Constraint constraint) |
---|
3995 | { |
---|
3996 | ScanChildren(constraint); |
---|
3997 | return voidResult; |
---|
3998 | } |
---|
3999 | #endregion |
---|
4000 | |
---|
4001 | #region Documentation Reference |
---|
4002 | ResolveResult IAstVisitor<ResolveResult>.VisitDocumentationReference(DocumentationReference documentationReference) |
---|
4003 | { |
---|
4004 | // Resolve child nodes: |
---|
4005 | ITypeDefinition declaringTypeDef; |
---|
4006 | if (documentationReference.DeclaringType.IsNull) |
---|
4007 | declaringTypeDef = resolver.CurrentTypeDefinition; |
---|
4008 | else |
---|
4009 | declaringTypeDef = ResolveType(documentationReference.DeclaringType).GetDefinition(); |
---|
4010 | IType[] typeArguments = documentationReference.TypeArguments.Select(ResolveType).ToArray(); |
---|
4011 | IType conversionOperatorReturnType = ResolveType(documentationReference.ConversionOperatorReturnType); |
---|
4012 | IParameter[] parameters = documentationReference.Parameters.Select(ResolveXmlDocParameter).ToArray(); |
---|
4013 | |
---|
4014 | if (documentationReference.SymbolKind == SymbolKind.TypeDefinition) { |
---|
4015 | if (declaringTypeDef != null) |
---|
4016 | return new TypeResolveResult(declaringTypeDef); |
---|
4017 | else |
---|
4018 | return errorResult; |
---|
4019 | } |
---|
4020 | |
---|
4021 | if (documentationReference.SymbolKind == SymbolKind.None) { |
---|
4022 | // might be a type, member or ctor |
---|
4023 | string memberName = documentationReference.MemberName; |
---|
4024 | ResolveResult rr; |
---|
4025 | if (documentationReference.DeclaringType.IsNull) { |
---|
4026 | rr = resolver.LookupSimpleNameOrTypeName(memberName, typeArguments, NameLookupMode.Expression); |
---|
4027 | } else { |
---|
4028 | var target = Resolve(documentationReference.DeclaringType); |
---|
4029 | rr = resolver.ResolveMemberAccess(target, memberName, typeArguments); |
---|
4030 | } |
---|
4031 | // reduce to definition: |
---|
4032 | if (rr.IsError) { |
---|
4033 | return rr; |
---|
4034 | } else if (rr is TypeResolveResult) { |
---|
4035 | var typeDef = rr.Type.GetDefinition(); |
---|
4036 | if (typeDef == null) |
---|
4037 | return errorResult; |
---|
4038 | if (documentationReference.HasParameterList) { |
---|
4039 | var ctors = typeDef.GetConstructors(options: GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions); |
---|
4040 | return FindByParameters(ctors, parameters); |
---|
4041 | } else { |
---|
4042 | return new TypeResolveResult(typeDef); |
---|
4043 | } |
---|
4044 | } else if (rr is MemberResolveResult) { |
---|
4045 | var mrr = (MemberResolveResult)rr; |
---|
4046 | return new MemberResolveResult(null, mrr.Member.MemberDefinition); |
---|
4047 | } else if (rr is MethodGroupResolveResult) { |
---|
4048 | var mgrr = (MethodGroupResolveResult)rr; |
---|
4049 | var methods = mgrr.MethodsGroupedByDeclaringType.Reverse() |
---|
4050 | .SelectMany(ml => ml.Select(m => (IParameterizedMember)m.MemberDefinition)); |
---|
4051 | return FindByParameters(methods, parameters); |
---|
4052 | } |
---|
4053 | return rr; |
---|
4054 | } |
---|
4055 | |
---|
4056 | // Indexer or operator |
---|
4057 | if (declaringTypeDef == null) |
---|
4058 | return errorResult; |
---|
4059 | if (documentationReference.SymbolKind == SymbolKind.Indexer) { |
---|
4060 | var indexers = declaringTypeDef.Properties.Where(p => p.IsIndexer && !p.IsExplicitInterfaceImplementation); |
---|
4061 | return FindByParameters(indexers, parameters); |
---|
4062 | } else if (documentationReference.SymbolKind == SymbolKind.Operator) { |
---|
4063 | var opType = documentationReference.OperatorType; |
---|
4064 | string memberName = OperatorDeclaration.GetName(opType); |
---|
4065 | var methods = declaringTypeDef.Methods.Where(m => m.IsOperator && m.Name == memberName); |
---|
4066 | if (opType == OperatorType.Implicit || opType == OperatorType.Explicit) { |
---|
4067 | // conversion operator |
---|
4068 | foreach (var method in methods) { |
---|
4069 | if (ParameterListComparer.Instance.Equals(method.Parameters, parameters)) { |
---|
4070 | if (method.ReturnType.Equals(conversionOperatorReturnType)) |
---|
4071 | return new MemberResolveResult(null, method); |
---|
4072 | } |
---|
4073 | } |
---|
4074 | return new MemberResolveResult(null, methods.FirstOrDefault()); |
---|
4075 | } else { |
---|
4076 | // not a conversion operator |
---|
4077 | return FindByParameters(methods, parameters); |
---|
4078 | } |
---|
4079 | } else { |
---|
4080 | throw new NotSupportedException(); // unknown entity type |
---|
4081 | } |
---|
4082 | } |
---|
4083 | |
---|
4084 | IParameter ResolveXmlDocParameter(ParameterDeclaration p) |
---|
4085 | { |
---|
4086 | var lrr = Resolve(p) as LocalResolveResult; |
---|
4087 | if (lrr != null && lrr.IsParameter) |
---|
4088 | return (IParameter)lrr.Variable; |
---|
4089 | else |
---|
4090 | return new DefaultParameter(SpecialType.UnknownType, string.Empty); |
---|
4091 | } |
---|
4092 | |
---|
4093 | ResolveResult FindByParameters(IEnumerable<IParameterizedMember> methods, IList<IParameter> parameters) |
---|
4094 | { |
---|
4095 | foreach (var method in methods) { |
---|
4096 | if (ParameterListComparer.Instance.Equals(method.Parameters, parameters)) |
---|
4097 | return new MemberResolveResult(null, method); |
---|
4098 | } |
---|
4099 | return new MemberResolveResult(null, methods.FirstOrDefault()); |
---|
4100 | } |
---|
4101 | #endregion |
---|
4102 | } |
---|
4103 | } |
---|