PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs

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