PageRenderTime 57ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Compilers/CSharp/Portable/Symbols/AliasSymbol.cs

https://gitlab.com/sharadag/Roslyn
C# | 385 lines | 272 code | 53 blank | 60 comment | 17 complexity | f1957b458c9dc7245a0637aadab3f9b2 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.Immutable;
  3. using System.Diagnostics;
  4. using System.Linq;
  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.Symbols
  10. {
  11. /// <summary>
  12. /// Symbol representing a using alias appearing in a compilation unit or within a namespace
  13. /// declaration. Generally speaking, these symbols do not appear in the set of symbols reachable
  14. /// from the unnamed namespace declaration. In other words, when a using alias is used in a
  15. /// program, it acts as a transparent alias, and the symbol to which it is an alias is used in
  16. /// the symbol table. For example, in the source code
  17. /// <pre>
  18. /// namespace NS
  19. /// {
  20. /// using o = System.Object;
  21. /// partial class C : o {}
  22. /// partial class C : object {}
  23. /// partial class C : System.Object {}
  24. /// }
  25. /// </pre>
  26. /// all three declarations for class C are equivalent and result in the same symbol table object
  27. /// for C. However, these using alias symbols do appear in the results of certain SemanticModel
  28. /// APIs. Specifically, for the base clause of the first of C's class declarations, the
  29. /// following APIs may produce a result that contains an AliasSymbol:
  30. /// <pre>
  31. /// SemanticInfo SemanticModel.GetSemanticInfo(ExpressionSyntax expression);
  32. /// SemanticInfo SemanticModel.BindExpression(CSharpSyntaxNode location, ExpressionSyntax expression);
  33. /// SemanticInfo SemanticModel.BindType(CSharpSyntaxNode location, ExpressionSyntax type);
  34. /// SemanticInfo SemanticModel.BindNamespaceOrType(CSharpSyntaxNode location, ExpressionSyntax type);
  35. /// </pre>
  36. /// Also, the following are affected if container==null (and, for the latter, when arity==null
  37. /// or arity==0):
  38. /// <pre>
  39. /// IList&lt;string&gt; SemanticModel.LookupNames(CSharpSyntaxNode location, NamespaceOrTypeSymbol container = null, LookupOptions options = LookupOptions.Default, List&lt;string> result = null);
  40. /// IList&lt;Symbol&gt; SemanticModel.LookupSymbols(CSharpSyntaxNode location, NamespaceOrTypeSymbol container = null, string name = null, int? arity = null, LookupOptions options = LookupOptions.Default, List&lt;Symbol> results = null);
  41. /// </pre>
  42. /// </summary>
  43. internal sealed class AliasSymbol : Symbol, IAliasSymbol
  44. {
  45. private readonly SyntaxToken _aliasName;
  46. private readonly Binder _binder;
  47. private SymbolCompletionState _state;
  48. private NamespaceOrTypeSymbol _aliasTarget;
  49. private readonly ImmutableArray<Location> _locations; // NOTE: can be empty for the "global" alias.
  50. // lazy binding
  51. private readonly NameSyntax _aliasTargetName;
  52. private readonly bool _isExtern;
  53. private DiagnosticBag _aliasTargetDiagnostics;
  54. private AliasSymbol(Binder binder, NamespaceOrTypeSymbol target, SyntaxToken aliasName, ImmutableArray<Location> locations)
  55. {
  56. _aliasName = aliasName;
  57. _locations = locations;
  58. _aliasTarget = target;
  59. _binder = binder;
  60. _state.NotePartComplete(CompletionPart.AliasTarget);
  61. }
  62. private AliasSymbol(Binder binder, SyntaxToken aliasName)
  63. {
  64. _aliasName = aliasName;
  65. _locations = ImmutableArray.Create(aliasName.GetLocation());
  66. _binder = binder;
  67. }
  68. internal AliasSymbol(Binder binder, UsingDirectiveSyntax syntax)
  69. : this(binder, syntax.Alias.Name.Identifier)
  70. {
  71. _aliasTargetName = syntax.Name;
  72. }
  73. internal AliasSymbol(Binder binder, ExternAliasDirectiveSyntax syntax)
  74. : this(binder, syntax.Identifier)
  75. {
  76. _isExtern = true;
  77. }
  78. // For the purposes of SemanticModel, it is convenient to have an AliasSymbol for the "global" namespace that "global::" binds
  79. // to. This alias symbol is returned only when binding "global::" (special case code).
  80. internal static AliasSymbol CreateGlobalNamespaceAlias(NamespaceSymbol globalNamespace, Binder globalNamespaceBinder)
  81. {
  82. SyntaxToken aliasName = SyntaxFactory.Identifier(SyntaxFactory.TriviaList(), SyntaxKind.GlobalKeyword, "global", "global", SyntaxFactory.TriviaList());
  83. return new AliasSymbol(globalNamespaceBinder, globalNamespace, aliasName, ImmutableArray<Location>.Empty);
  84. }
  85. internal static AliasSymbol CreateCustomDebugInfoAlias(NamespaceOrTypeSymbol targetSymbol, SyntaxToken aliasToken, Binder binder)
  86. {
  87. return new AliasSymbol(binder, targetSymbol, aliasToken, ImmutableArray.Create(aliasToken.GetLocation()));
  88. }
  89. internal AliasSymbol ToNewSubmission(CSharpCompilation compilation)
  90. {
  91. Debug.Assert(_binder.Compilation.IsSubmission);
  92. // We can pass basesBeingResolved: null because base type cycles can't cross
  93. // submission boundaries - there's no way to depend on a subsequent submission.
  94. var previousTarget = GetAliasTarget(basesBeingResolved: null);
  95. if (previousTarget.Kind != SymbolKind.Namespace)
  96. {
  97. return this;
  98. }
  99. var expandedGlobalNamespace = compilation.GlobalNamespace;
  100. var expandedNamespace = Imports.ExpandPreviousSubmissionNamespace((NamespaceSymbol)previousTarget, expandedGlobalNamespace);
  101. var binder = new InContainerBinder(expandedGlobalNamespace, new BuckStopsHereBinder(compilation));
  102. return new AliasSymbol(binder, expandedNamespace, _aliasName, _locations);
  103. }
  104. public override string Name
  105. {
  106. get
  107. {
  108. return _aliasName.ValueText;
  109. }
  110. }
  111. public override SymbolKind Kind
  112. {
  113. get
  114. {
  115. return SymbolKind.Alias;
  116. }
  117. }
  118. /// <summary>
  119. /// Gets the <see cref="NamespaceOrTypeSymbol"/> for the
  120. /// namespace or type referenced by the alias.
  121. /// </summary>
  122. public NamespaceOrTypeSymbol Target
  123. {
  124. get
  125. {
  126. return GetAliasTarget(basesBeingResolved: null);
  127. }
  128. }
  129. public override ImmutableArray<Location> Locations
  130. {
  131. get
  132. {
  133. return _locations;
  134. }
  135. }
  136. public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
  137. {
  138. get
  139. {
  140. return GetDeclaringSyntaxReferenceHelper<UsingDirectiveSyntax>(_locations);
  141. }
  142. }
  143. public override bool IsExtern
  144. {
  145. get
  146. {
  147. return _isExtern;
  148. }
  149. }
  150. public override bool IsSealed
  151. {
  152. get
  153. {
  154. return false;
  155. }
  156. }
  157. public override bool IsAbstract
  158. {
  159. get
  160. {
  161. return false;
  162. }
  163. }
  164. public override bool IsOverride
  165. {
  166. get
  167. {
  168. return false;
  169. }
  170. }
  171. public override bool IsVirtual
  172. {
  173. get
  174. {
  175. return false;
  176. }
  177. }
  178. public override bool IsStatic
  179. {
  180. get
  181. {
  182. return false;
  183. }
  184. }
  185. /// <summary>
  186. /// Returns data decoded from Obsolete attribute or null if there is no Obsolete attribute.
  187. /// This property returns ObsoleteAttributeData.Uninitialized if attribute arguments haven't been decoded yet.
  188. /// </summary>
  189. internal sealed override ObsoleteAttributeData ObsoleteAttributeData
  190. {
  191. get { return null; }
  192. }
  193. public override Accessibility DeclaredAccessibility
  194. {
  195. get
  196. {
  197. return Accessibility.NotApplicable;
  198. }
  199. }
  200. /// <summary>
  201. /// Using aliases in C# are always contained within a namespace declaration, or at the top
  202. /// level within a compilation unit, within the implicit unnamed namespace declaration. We
  203. /// return that as the "containing" symbol, even though the alias isn't a member of the
  204. /// namespace as such.
  205. /// </summary>
  206. public override Symbol ContainingSymbol
  207. {
  208. get
  209. {
  210. return _binder.ContainingMemberOrLambda;
  211. }
  212. }
  213. internal override TResult Accept<TArg, TResult>(CSharpSymbolVisitor<TArg, TResult> visitor, TArg a)
  214. {
  215. return visitor.VisitAlias(this, a);
  216. }
  217. public override void Accept(CSharpSymbolVisitor visitor)
  218. {
  219. visitor.VisitAlias(this);
  220. }
  221. public override TResult Accept<TResult>(CSharpSymbolVisitor<TResult> visitor)
  222. {
  223. return visitor.VisitAlias(this);
  224. }
  225. // basesBeingResolved is only used to break circular references.
  226. internal NamespaceOrTypeSymbol GetAliasTarget(ConsList<Symbol> basesBeingResolved)
  227. {
  228. if (!_state.HasComplete(CompletionPart.AliasTarget))
  229. {
  230. // the target is not yet bound. If it is an ordinary alias, bind the target
  231. // symbol. If it is an extern alias then find the target in the list of metadata references.
  232. var newDiagnostics = DiagnosticBag.GetInstance();
  233. NamespaceOrTypeSymbol symbol = this.IsExtern ?
  234. ResolveExternAliasTarget(newDiagnostics) :
  235. ResolveAliasTarget(_binder, _aliasTargetName, newDiagnostics, basesBeingResolved);
  236. if ((object)Interlocked.CompareExchange(ref _aliasTarget, symbol, null) == null)
  237. {
  238. // Note: It's important that we don't call newDiagnosticsToReadOnlyAndFree here. That call
  239. // can force the prompt evaluation of lazy initialized diagnostics. That in turn can
  240. // call back into GetAliasTarget on the same thread resulting in a dead lock scenario.
  241. bool won = Interlocked.Exchange(ref _aliasTargetDiagnostics, newDiagnostics) == null;
  242. Debug.Assert(won, "Only one thread can win the alias target CompareExchange");
  243. _state.NotePartComplete(CompletionPart.AliasTarget);
  244. // we do not clear this.aliasTargetName, as another thread might be about to use it for ResolveAliasTarget(...)
  245. }
  246. else
  247. {
  248. newDiagnostics.Free();
  249. // Wait for diagnostics to have been reported if another thread resolves the alias
  250. _state.SpinWaitComplete(CompletionPart.AliasTarget, default(CancellationToken));
  251. }
  252. }
  253. return _aliasTarget;
  254. }
  255. internal DiagnosticBag AliasTargetDiagnostics
  256. {
  257. get
  258. {
  259. GetAliasTarget(null);
  260. Debug.Assert(_aliasTargetDiagnostics != null);
  261. return _aliasTargetDiagnostics;
  262. }
  263. }
  264. internal void CheckConstraints(DiagnosticBag diagnostics)
  265. {
  266. var target = this.Target as TypeSymbol;
  267. if ((object)target != null && _locations.Length > 0)
  268. {
  269. var corLibrary = this.ContainingAssembly.CorLibrary;
  270. var conversions = new TypeConversions(corLibrary);
  271. target.CheckAllConstraints(conversions, _locations[0], diagnostics);
  272. }
  273. }
  274. private NamespaceSymbol ResolveExternAliasTarget(DiagnosticBag diagnostics)
  275. {
  276. NamespaceSymbol target;
  277. if (!_binder.Compilation.GetExternAliasTarget(_aliasName.ValueText, out target))
  278. {
  279. diagnostics.Add(ErrorCode.ERR_BadExternAlias, _aliasName.GetLocation(), _aliasName.ValueText);
  280. }
  281. Debug.Assert((object)target != null);
  282. return target;
  283. }
  284. private static NamespaceOrTypeSymbol ResolveAliasTarget(Binder binder, NameSyntax syntax, DiagnosticBag diagnostics, ConsList<Symbol> basesBeingResolved)
  285. {
  286. var declarationBinder = binder.WithAdditionalFlags(BinderFlags.SuppressConstraintChecks | BinderFlags.SuppressObsoleteChecks);
  287. return declarationBinder.BindNamespaceOrTypeSymbol(syntax, diagnostics, basesBeingResolved);
  288. }
  289. public override bool Equals(object obj)
  290. {
  291. if (ReferenceEquals(this, obj))
  292. {
  293. return true;
  294. }
  295. if (ReferenceEquals(obj, null))
  296. {
  297. return false;
  298. }
  299. AliasSymbol other = obj as AliasSymbol;
  300. return (object)other != null &&
  301. Equals(this.Locations.FirstOrDefault(), other.Locations.FirstOrDefault()) &&
  302. this.ContainingAssembly == other.ContainingAssembly;
  303. }
  304. public override int GetHashCode()
  305. {
  306. if (this.Locations.Length > 0)
  307. return this.Locations.First().GetHashCode();
  308. else
  309. return Name.GetHashCode();
  310. }
  311. internal override bool RequiresCompletion
  312. {
  313. get { return true; }
  314. }
  315. #region IAliasSymbol Members
  316. INamespaceOrTypeSymbol IAliasSymbol.Target
  317. {
  318. get { return this.Target; }
  319. }
  320. #endregion
  321. #region ISymbol Members
  322. public override void Accept(SymbolVisitor visitor)
  323. {
  324. visitor.VisitAlias(this);
  325. }
  326. public override TResult Accept<TResult>(SymbolVisitor<TResult> visitor)
  327. {
  328. return visitor.VisitAlias(this);
  329. }
  330. #endregion
  331. }
  332. }