PageRenderTime 84ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs

https://gitlab.com/sharadag/Roslyn
C# | 302 lines | 235 code | 48 blank | 19 comment | 50 complexity | 113fefe64f8a11505c4cd1e78eada275 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 System.Collections.Generic;
  3. using System.Collections.Immutable;
  4. using System.Diagnostics;
  5. using System.Threading;
  6. using Microsoft.CodeAnalysis.CSharp.Symbols;
  7. using Microsoft.CodeAnalysis.CSharp.Syntax;
  8. using Roslyn.Utilities;
  9. namespace Microsoft.CodeAnalysis.CSharp
  10. {
  11. /// <summary>
  12. /// A binder for a method body, which places the method's parameters in scope
  13. /// and notes if the method is an iterator method.
  14. /// </summary>
  15. internal sealed class InMethodBinder : LocalScopeBinder
  16. {
  17. private readonly MultiDictionary<string, ParameterSymbol> _parameterMap;
  18. private readonly MethodSymbol _methodSymbol;
  19. private SmallDictionary<string, Symbol> _definitionMap;
  20. private IteratorInfo _iteratorInfo;
  21. private static readonly HashSet<string> s_emptySet = new HashSet<string>();
  22. private class IteratorInfo
  23. {
  24. public static readonly IteratorInfo Empty = new IteratorInfo(null, default(ImmutableArray<Diagnostic>));
  25. public readonly TypeSymbol ElementType;
  26. public readonly ImmutableArray<Diagnostic> ElementTypeDiagnostics;
  27. public IteratorInfo(TypeSymbol elementType, ImmutableArray<Diagnostic> elementTypeDiagnostics)
  28. {
  29. this.ElementType = elementType;
  30. this.ElementTypeDiagnostics = elementTypeDiagnostics;
  31. }
  32. }
  33. public InMethodBinder(MethodSymbol owner, Binder enclosing)
  34. : base(enclosing)
  35. {
  36. Debug.Assert((object)owner != null);
  37. _methodSymbol = owner;
  38. var parameters = owner.Parameters;
  39. if (!parameters.IsEmpty)
  40. {
  41. RecordDefinition(parameters);
  42. _parameterMap = new MultiDictionary<string, ParameterSymbol>(parameters.Length, EqualityComparer<string>.Default);
  43. foreach (var parameter in parameters)
  44. {
  45. _parameterMap.Add(parameter.Name, parameter);
  46. }
  47. }
  48. var typeParameters = owner.TypeParameters;
  49. if (!typeParameters.IsDefaultOrEmpty)
  50. {
  51. RecordDefinition(typeParameters);
  52. }
  53. }
  54. private void RecordDefinition<T>(ImmutableArray<T> definitions) where T : Symbol
  55. {
  56. var declarationMap = _definitionMap ?? (_definitionMap = new SmallDictionary<string, Symbol>());
  57. foreach (Symbol s in definitions)
  58. {
  59. if (!declarationMap.ContainsKey(s.Name))
  60. {
  61. declarationMap.Add(s.Name, s);
  62. }
  63. }
  64. }
  65. protected override SourceLocalSymbol LookupLocal(SyntaxToken nameToken)
  66. {
  67. return null;
  68. }
  69. internal override Symbol ContainingMemberOrLambda
  70. {
  71. get
  72. {
  73. return _methodSymbol;
  74. }
  75. }
  76. internal override bool IsInMethodBody
  77. {
  78. get
  79. {
  80. return true;
  81. }
  82. }
  83. internal void MakeIterator()
  84. {
  85. if (_iteratorInfo == null)
  86. {
  87. _iteratorInfo = IteratorInfo.Empty;
  88. }
  89. }
  90. internal override bool IsDirectlyInIterator
  91. {
  92. get
  93. {
  94. return _iteratorInfo != null;
  95. }
  96. }
  97. internal override bool IsIndirectlyInIterator
  98. {
  99. get
  100. {
  101. return IsDirectlyInIterator; // Sic: indirectly iff directly
  102. }
  103. }
  104. internal override GeneratedLabelSymbol BreakLabel
  105. {
  106. get
  107. {
  108. return null;
  109. }
  110. }
  111. internal override GeneratedLabelSymbol ContinueLabel
  112. {
  113. get
  114. {
  115. return null;
  116. }
  117. }
  118. internal override TypeSymbol GetIteratorElementType(YieldStatementSyntax node, DiagnosticBag diagnostics)
  119. {
  120. TypeSymbol returnType = _methodSymbol.ReturnType;
  121. if (!this.IsDirectlyInIterator)
  122. {
  123. // This should only happen when speculating, but we don't have a good way to assert that since the
  124. // original binder isn't available here.
  125. // If we're speculating about a yield statement inside a non-iterator method, we'll try to be nice
  126. // and deduce an iterator element type from the return type. If we didn't do this, the
  127. // TypeInfo.ConvertedType of the yield statement would always be an error type. However, we will
  128. // not mutate any state (i.e. we won't store the result).
  129. return GetIteratorElementTypeFromReturnType(returnType, node, diagnostics) ?? CreateErrorType();
  130. }
  131. if (_iteratorInfo == IteratorInfo.Empty)
  132. {
  133. TypeSymbol elementType = null;
  134. DiagnosticBag elementTypeDiagnostics = DiagnosticBag.GetInstance();
  135. elementType = GetIteratorElementTypeFromReturnType(returnType, node, elementTypeDiagnostics);
  136. if ((object)elementType == null)
  137. {
  138. Error(elementTypeDiagnostics, ErrorCode.ERR_BadIteratorReturn, _methodSymbol.Locations[0], _methodSymbol, returnType);
  139. elementType = CreateErrorType();
  140. }
  141. var info = new IteratorInfo(elementType, elementTypeDiagnostics.ToReadOnlyAndFree());
  142. Interlocked.CompareExchange(ref _iteratorInfo, info, IteratorInfo.Empty);
  143. }
  144. if (node == null)
  145. {
  146. // node==null indicates this we are being called from the top-level of processing of a method. We report
  147. // the diagnostic, if any, at that time to ensure it is reported exactly once.
  148. diagnostics.AddRange(_iteratorInfo.ElementTypeDiagnostics);
  149. }
  150. return _iteratorInfo.ElementType;
  151. }
  152. private TypeSymbol GetIteratorElementTypeFromReturnType(TypeSymbol returnType, CSharpSyntaxNode errorLocationNode, DiagnosticBag diagnostics)
  153. {
  154. if (returnType.Kind == SymbolKind.NamedType)
  155. {
  156. switch (returnType.OriginalDefinition.SpecialType)
  157. {
  158. case SpecialType.System_Collections_IEnumerable:
  159. case SpecialType.System_Collections_IEnumerator:
  160. return GetSpecialType(SpecialType.System_Object, diagnostics, errorLocationNode);
  161. case SpecialType.System_Collections_Generic_IEnumerable_T:
  162. case SpecialType.System_Collections_Generic_IEnumerator_T:
  163. return ((NamedTypeSymbol)returnType).TypeArgumentsNoUseSiteDiagnostics[0];
  164. }
  165. }
  166. return null;
  167. }
  168. internal override void LookupSymbolsInSingleBinder(
  169. LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
  170. {
  171. Debug.Assert(result.IsClear);
  172. if (_parameterMap == null || (options & LookupOptions.NamespaceAliasesOnly) != 0)
  173. {
  174. return;
  175. }
  176. foreach (var parameterSymbol in _parameterMap[name])
  177. {
  178. result.MergeEqual(originalBinder.CheckViability(parameterSymbol, arity, options, null, diagnose, ref useSiteDiagnostics));
  179. }
  180. }
  181. protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder)
  182. {
  183. if (options.CanConsiderMembers())
  184. {
  185. foreach (var parameter in _methodSymbol.Parameters)
  186. {
  187. if (originalBinder.CanAddLookupSymbolInfo(parameter, options, null))
  188. {
  189. result.AddSymbol(parameter, parameter.Name, 0);
  190. }
  191. }
  192. }
  193. }
  194. internal static bool ReportConflictWithParameter(Symbol parameter, Symbol newSymbol, string name, Location newLocation, DiagnosticBag diagnostics)
  195. {
  196. var oldLocation = parameter.Locations[0];
  197. Debug.Assert(oldLocation != newLocation || oldLocation == Location.None, "same nonempty location refers to different symbols?");
  198. SymbolKind parameterKind = parameter.Kind;
  199. // Quirk of the way we represent lambda parameters.
  200. SymbolKind newSymbolKind = (object)newSymbol == null ? SymbolKind.Parameter : newSymbol.Kind;
  201. if (newSymbolKind == SymbolKind.ErrorType)
  202. {
  203. return true;
  204. }
  205. if (parameterKind == SymbolKind.Parameter)
  206. {
  207. if (newSymbolKind == SymbolKind.Parameter || newSymbolKind == SymbolKind.Local)
  208. {
  209. // A local or parameter named '{0}' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
  210. diagnostics.Add(ErrorCode.ERR_LocalIllegallyOverrides, newLocation, name);
  211. return true;
  212. }
  213. if (newSymbolKind == SymbolKind.RangeVariable)
  214. {
  215. // The range variable '{0}' conflicts with a previous declaration of '{0}'
  216. diagnostics.Add(ErrorCode.ERR_QueryRangeVariableOverrides, newLocation, name);
  217. return true;
  218. }
  219. }
  220. if (parameterKind == SymbolKind.TypeParameter)
  221. {
  222. if (newSymbolKind == SymbolKind.Parameter || newSymbolKind == SymbolKind.Local)
  223. {
  224. // CS0412: 'X': a parameter or local variable cannot have the same name as a method type parameter
  225. diagnostics.Add(ErrorCode.ERR_LocalSameNameAsTypeParam, newLocation, name);
  226. return true;
  227. }
  228. if (newSymbolKind == SymbolKind.TypeParameter)
  229. {
  230. // Type parameter declaration name conflicts are detected elsewhere
  231. return false;
  232. }
  233. if (newSymbolKind == SymbolKind.RangeVariable)
  234. {
  235. // The range variable '{0}' cannot have the same name as a method type parameter
  236. diagnostics.Add(ErrorCode.ERR_QueryRangeVariableSameAsTypeParam, newLocation, name);
  237. return true;
  238. }
  239. }
  240. Debug.Assert(false, "what else could be defined in a method?");
  241. return true;
  242. }
  243. internal override bool EnsureSingleDefinition(Symbol symbol, string name, Location location, DiagnosticBag diagnostics)
  244. {
  245. Symbol existingDeclaration;
  246. var map = _definitionMap;
  247. if (map != null && map.TryGetValue(name, out existingDeclaration))
  248. {
  249. return ReportConflictWithParameter(existingDeclaration, symbol, name, location, diagnostics);
  250. }
  251. return false;
  252. }
  253. }
  254. }