PageRenderTime 52ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs

https://gitlab.com/sharadag/TestProject2
C# | 263 lines | 218 code | 24 blank | 21 comment | 47 complexity | 7087333a1d4db73c8eea6fb202f109fc MD5 | raw file
  1. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  2. using Microsoft.CodeAnalysis.CSharp.Symbols;
  3. using Microsoft.CodeAnalysis.CSharp.Syntax;
  4. using System.Collections.Generic;
  5. using System.Collections.Immutable;
  6. using System.Linq;
  7. namespace Microsoft.CodeAnalysis.CSharp
  8. {
  9. /// <summary>
  10. /// A region analysis walker that records reads and writes of all variables, both inside and outside the region.
  11. /// </summary>
  12. internal class ReadWriteWalker : AbstractRegionDataFlowPass
  13. {
  14. internal static void Analyze(
  15. CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet<PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes,
  16. out IEnumerable<Symbol> readInside,
  17. out IEnumerable<Symbol> writtenInside,
  18. out IEnumerable<Symbol> readOutside,
  19. out IEnumerable<Symbol> writtenOutside,
  20. out IEnumerable<Symbol> captured,
  21. out IEnumerable<Symbol> unsafeAddressTaken)
  22. {
  23. var walker = new ReadWriteWalker(compilation, member, node, firstInRegion, lastInRegion, unassignedVariableAddressOfSyntaxes);
  24. try
  25. {
  26. bool badRegion = false;
  27. walker.Analyze(ref badRegion);
  28. if (badRegion)
  29. {
  30. readInside = writtenInside = readOutside = writtenOutside = captured = unsafeAddressTaken = Enumerable.Empty<Symbol>();
  31. }
  32. else
  33. {
  34. readInside = walker._readInside;
  35. writtenInside = walker._writtenInside;
  36. readOutside = walker._readOutside;
  37. writtenOutside = walker._writtenOutside;
  38. captured = walker.GetCaptured();
  39. unsafeAddressTaken = walker.GetUnsafeAddressTaken();
  40. }
  41. }
  42. finally
  43. {
  44. walker.Free();
  45. }
  46. }
  47. private readonly HashSet<Symbol> _readInside = new HashSet<Symbol>();
  48. private readonly HashSet<Symbol> _writtenInside = new HashSet<Symbol>();
  49. private readonly HashSet<Symbol> _readOutside = new HashSet<Symbol>();
  50. private readonly HashSet<Symbol> _writtenOutside = new HashSet<Symbol>();
  51. private ReadWriteWalker(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion,
  52. HashSet<PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes)
  53. : base(compilation, member, node, firstInRegion, lastInRegion, unassignedVariableAddressOfSyntaxes: unassignedVariableAddressOfSyntaxes)
  54. {
  55. }
  56. protected override void EnterRegion()
  57. {
  58. for (MethodSymbol m = this.currentMethodOrLambda; (object)m != null; m = m.ContainingSymbol as MethodSymbol)
  59. {
  60. foreach (var p in m.Parameters)
  61. {
  62. if (p.RefKind != RefKind.None) _readOutside.Add(p);
  63. }
  64. var thisParameter = m.ThisParameter;
  65. if ((object)thisParameter != null && thisParameter.RefKind != RefKind.None)
  66. {
  67. _readOutside.Add(thisParameter);
  68. }
  69. }
  70. base.EnterRegion();
  71. }
  72. /// <summary>
  73. /// Note that a variable is read.
  74. /// </summary>
  75. /// <param name="variable">The variable</param>
  76. /// <param name="rangeVariableUnderlyingParameter">If variable.Kind is RangeVariable, its underlying lambda parameter. Else null.</param>
  77. protected override void NoteRead(Symbol variable, ParameterSymbol rangeVariableUnderlyingParameter = null)
  78. {
  79. if ((object)variable == null) return;
  80. if (variable.Kind != SymbolKind.Field) (IsInside ? _readInside : _readOutside).Add(variable);
  81. base.NoteRead(variable, rangeVariableUnderlyingParameter);
  82. }
  83. protected override void NoteWrite(Symbol variable, BoundExpression value, bool read)
  84. {
  85. if ((object)variable == null) return;
  86. (IsInside ? _writtenInside : _writtenOutside).Add(variable);
  87. base.NoteWrite(variable, value, read);
  88. }
  89. protected override void CheckAssigned(BoundExpression expr, FieldSymbol fieldSymbol, CSharpSyntaxNode node)
  90. {
  91. base.CheckAssigned(expr, fieldSymbol, node);
  92. if (!IsInside && node.Span.Contains(RegionSpan) && (expr.Kind == BoundKind.FieldAccess))
  93. {
  94. NoteReceiverRead((BoundFieldAccess)expr);
  95. }
  96. }
  97. private void NoteReceiverWritten(BoundFieldAccess expr)
  98. {
  99. NoteReceiverReadOrWritten(expr, _writtenInside);
  100. }
  101. private void NoteReceiverRead(BoundFieldAccess expr)
  102. {
  103. NoteReceiverReadOrWritten(expr, _readInside);
  104. }
  105. /// <summary>
  106. /// When we read a field from a struct, the receiver isn't seen as being read until we get to the
  107. /// end of the field access expression, because we only read the relevant piece of the struct.
  108. /// But we want the receiver to be considered to be read in the region in that case.
  109. /// For example, if an rvalue expression is x.y.z and the region is x.y, we want x to be included
  110. /// in the ReadInside set. That is implemented here.
  111. /// </summary>
  112. private void NoteReceiverReadOrWritten(BoundFieldAccess expr, HashSet<Symbol> readOrWritten)
  113. {
  114. if (expr.FieldSymbol.IsStatic) return;
  115. if (expr.FieldSymbol.ContainingType.IsReferenceType) return;
  116. var receiver = expr.ReceiverOpt;
  117. if (receiver == null) return;
  118. var receiverSyntax = receiver.Syntax;
  119. if (receiverSyntax == null) return;
  120. switch (receiver.Kind)
  121. {
  122. case BoundKind.Local:
  123. if (RegionContains(receiverSyntax.Span))
  124. {
  125. readOrWritten.Add(((BoundLocal)receiver).LocalSymbol);
  126. }
  127. break;
  128. case BoundKind.ThisReference:
  129. if (RegionContains(receiverSyntax.Span))
  130. {
  131. readOrWritten.Add(this.MethodThisParameter);
  132. }
  133. break;
  134. case BoundKind.BaseReference:
  135. if (RegionContains(receiverSyntax.Span))
  136. {
  137. readOrWritten.Add(this.MethodThisParameter);
  138. }
  139. break;
  140. case BoundKind.Parameter:
  141. if (RegionContains(receiverSyntax.Span))
  142. {
  143. readOrWritten.Add(((BoundParameter)receiver).ParameterSymbol);
  144. }
  145. break;
  146. case BoundKind.RangeVariable:
  147. if (RegionContains(receiverSyntax.Span))
  148. {
  149. readOrWritten.Add(((BoundRangeVariable)receiver).RangeVariableSymbol);
  150. }
  151. break;
  152. case BoundKind.FieldAccess:
  153. if (receiver.Type.IsStructType() && receiverSyntax.Span.OverlapsWith(RegionSpan))
  154. {
  155. NoteReceiverReadOrWritten(receiver as BoundFieldAccess, readOrWritten);
  156. }
  157. break;
  158. }
  159. }
  160. protected override void AssignImpl(BoundNode node, BoundExpression value, RefKind refKind, bool written, bool read)
  161. {
  162. switch (node.Kind)
  163. {
  164. case BoundKind.RangeVariable:
  165. if (written) NoteWrite(((BoundRangeVariable)node).RangeVariableSymbol, value, read);
  166. break;
  167. case BoundKind.QueryClause:
  168. {
  169. base.AssignImpl(node, value, refKind, written, read);
  170. var symbol = ((BoundQueryClause)node).DefinedSymbol;
  171. if ((object)symbol != null)
  172. {
  173. if (written) NoteWrite(symbol, value, read);
  174. }
  175. }
  176. break;
  177. case BoundKind.FieldAccess:
  178. {
  179. base.AssignImpl(node, value, refKind, written, read);
  180. var fieldAccess = node as BoundFieldAccess;
  181. if (!IsInside && node.Syntax != null && node.Syntax.Span.Contains(RegionSpan))
  182. {
  183. NoteReceiverWritten(fieldAccess);
  184. }
  185. }
  186. break;
  187. default:
  188. base.AssignImpl(node, value, refKind, written, read);
  189. break;
  190. }
  191. }
  192. public override BoundNode VisitUnboundLambda(UnboundLambda node)
  193. {
  194. return VisitLambda(node.BindForErrorRecovery());
  195. }
  196. public override void VisitForEachIterationVariable(BoundForEachStatement node)
  197. {
  198. var local = node.IterationVariable;
  199. if ((object)local != null)
  200. {
  201. GetOrCreateSlot(local);
  202. Assign(node, value: null);
  203. }
  204. }
  205. public override BoundNode VisitRangeVariable(BoundRangeVariable node)
  206. {
  207. // Compute the "underlying symbol" for a read of the range variable
  208. ParameterSymbol rangeVariableUnderlyingParameter = GetRangeVariableUnderlyingParameter(node.Value);
  209. NoteRead(node.RangeVariableSymbol, rangeVariableUnderlyingParameter);
  210. return null;
  211. }
  212. /// <summary>
  213. /// Compute the underlying lambda parameter symbol for a range variable, if any.
  214. /// </summary>
  215. /// <param name="underlying">The bound node for the expansion of the range variable</param>
  216. private ParameterSymbol GetRangeVariableUnderlyingParameter(BoundNode underlying)
  217. {
  218. while (underlying != null)
  219. {
  220. switch (underlying.Kind)
  221. {
  222. case BoundKind.Parameter:
  223. return ((BoundParameter)underlying).ParameterSymbol;
  224. case BoundKind.PropertyAccess:
  225. underlying = ((BoundPropertyAccess)underlying).ReceiverOpt;
  226. continue;
  227. default:
  228. return null;
  229. }
  230. }
  231. return null;
  232. }
  233. public override BoundNode VisitQueryClause(BoundQueryClause node)
  234. {
  235. Assign(node, value: null);
  236. return base.VisitQueryClause(node);
  237. }
  238. }
  239. }