Free cookie consent management tool by TermsFeed Policy Generator

source: branches/CodeEditor/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory-5.5.0/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs @ 11700

Last change on this file since 11700 was 11700, checked in by jkarder, 9 years ago

#2077: created branch and added first version

File size: 18.5 KB
Line 
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
19using System;
20using System.Collections.Concurrent;
21using System.Collections.Generic;
22using System.Diagnostics;
23using System.Linq;
24using System.Runtime.Serialization;
25using System.Threading;
26
27using ICSharpCode.NRefactory.Semantics;
28using ICSharpCode.NRefactory.Utils;
29
30namespace ICSharpCode.NRefactory.TypeSystem.Implementation
31{
32  /// <summary>
33  /// Default implementation for <see cref="IUnresolvedAssembly"/>.
34  /// </summary>
35  [Serializable]
36  public class DefaultUnresolvedAssembly : AbstractFreezable, IUnresolvedAssembly
37  {
38    string assemblyName;
39    string fullAssemblyName;
40    IList<IUnresolvedAttribute> assemblyAttributes;
41    IList<IUnresolvedAttribute> moduleAttributes;
42    Dictionary<TopLevelTypeName, IUnresolvedTypeDefinition> typeDefinitions = new Dictionary<TopLevelTypeName, IUnresolvedTypeDefinition>(TopLevelTypeNameComparer.Ordinal);
43    Dictionary<TopLevelTypeName, ITypeReference> typeForwarders = new Dictionary<TopLevelTypeName, ITypeReference>(TopLevelTypeNameComparer.Ordinal);
44   
45    protected override void FreezeInternal()
46    {
47      base.FreezeInternal();
48      assemblyAttributes = FreezableHelper.FreezeListAndElements(assemblyAttributes);
49      moduleAttributes = FreezableHelper.FreezeListAndElements(moduleAttributes);
50      foreach (var type in typeDefinitions.Values) {
51        FreezableHelper.Freeze(type);
52      }
53    }
54   
55    /// <summary>
56    /// Creates a new unresolved assembly.
57    /// </summary>
58    /// <param name="assemblyName">Full assembly name</param>
59    public DefaultUnresolvedAssembly(string assemblyName)
60    {
61      if (assemblyName == null)
62        throw new ArgumentNullException("assemblyName");
63      this.fullAssemblyName = assemblyName;
64      int pos = assemblyName != null ? assemblyName.IndexOf(',') : -1;
65      this.assemblyName = pos < 0 ? assemblyName : assemblyName.Substring(0, pos);
66      this.assemblyAttributes = new List<IUnresolvedAttribute>();
67      this.moduleAttributes = new List<IUnresolvedAttribute>();
68    }
69   
70    /// <summary>
71    /// Gets/Sets the short assembly name.
72    /// </summary>
73    /// <remarks>
74    /// This class handles the short and the full name independently;
75    /// if you change the short name, you should also change the full name.
76    /// </remarks>
77    public string AssemblyName {
78      get { return assemblyName; }
79      set {
80        if (value == null)
81          throw new ArgumentNullException("value");
82        FreezableHelper.ThrowIfFrozen(this);
83        assemblyName = value;
84      }
85    }
86   
87    /// <summary>
88    /// Gets/Sets the full assembly name.
89    /// </summary>
90    /// <remarks>
91    /// This class handles the short and the full name independently;
92    /// if you change the full name, you should also change the short name.
93    /// </remarks>
94    public string FullAssemblyName {
95      get { return fullAssemblyName; }
96      set {
97        if (value == null)
98          throw new ArgumentNullException("value");
99        FreezableHelper.ThrowIfFrozen(this);
100        fullAssemblyName = value;
101      }
102    }
103   
104    string location;
105    public string Location {
106      get {
107        return location;
108      }
109      set {
110        FreezableHelper.ThrowIfFrozen(this);
111        location = value;
112      }
113    }
114
115    public IList<IUnresolvedAttribute> AssemblyAttributes {
116      get { return assemblyAttributes; }
117    }
118   
119    IEnumerable<IUnresolvedAttribute> IUnresolvedAssembly.AssemblyAttributes {
120      get { return assemblyAttributes; }
121    }
122   
123    public IList<IUnresolvedAttribute> ModuleAttributes {
124      get { return moduleAttributes; }
125    }
126   
127    IEnumerable<IUnresolvedAttribute> IUnresolvedAssembly.ModuleAttributes {
128      get { return moduleAttributes; }
129    }
130   
131    public IEnumerable<IUnresolvedTypeDefinition> TopLevelTypeDefinitions {
132      get { return typeDefinitions.Values; }
133    }
134   
135    /// <summary>
136    /// Adds a new top-level type definition to this assembly.
137    /// </summary>
138    /// <remarks>DefaultUnresolvedAssembly does not support partial classes.
139    /// Adding more than one part of a type will cause an ArgumentException.</remarks>
140    public void AddTypeDefinition(IUnresolvedTypeDefinition typeDefinition)
141    {
142      if (typeDefinition == null)
143        throw new ArgumentNullException("typeDefinition");
144      if (typeDefinition.DeclaringTypeDefinition != null)
145        throw new ArgumentException("Cannot add nested types.");
146      FreezableHelper.ThrowIfFrozen(this);
147      var key = new TopLevelTypeName(typeDefinition.Namespace, typeDefinition.Name, typeDefinition.TypeParameters.Count);
148      typeDefinitions.Add(key, typeDefinition);
149    }
150   
151    static readonly ITypeReference typeForwardedToAttributeTypeRef = typeof(System.Runtime.CompilerServices.TypeForwardedToAttribute).ToTypeReference();
152   
153    /// <summary>
154    /// Adds a type forwarder.
155    /// This adds both an assembly attribute and an internal forwarder entry, which will be used
156    /// by the resolved assembly to provide the forwarded types.
157    /// </summary>
158    /// <param name="typeName">The name of the type.</param>
159    /// <param name="referencedType">The reference used to look up the type in the target assembly.</param>
160    public void AddTypeForwarder(TopLevelTypeName typeName, ITypeReference referencedType)
161    {
162      if (referencedType == null)
163        throw new ArgumentNullException("referencedType");
164      FreezableHelper.ThrowIfFrozen(this);
165      var attribute = new DefaultUnresolvedAttribute(typeForwardedToAttributeTypeRef, new[] { KnownTypeReference.Type });
166      attribute.PositionalArguments.Add(new TypeOfConstantValue(referencedType));
167      assemblyAttributes.Add(attribute);
168     
169      typeForwarders[typeName] = referencedType;
170    }
171   
172    [Serializable]
173    sealed class TypeOfConstantValue : IConstantValue
174    {
175      readonly ITypeReference typeRef;
176     
177      public TypeOfConstantValue(ITypeReference typeRef)
178      {
179        this.typeRef = typeRef;
180      }
181     
182      public ResolveResult Resolve(ITypeResolveContext context)
183      {
184        return new TypeOfResolveResult(context.Compilation.FindType(KnownTypeCode.Type), typeRef.Resolve(context));
185      }
186    }
187   
188    public IUnresolvedTypeDefinition GetTypeDefinition(string ns, string name, int typeParameterCount)
189    {
190      var key = new TopLevelTypeName(ns ?? string.Empty, name, typeParameterCount);
191      IUnresolvedTypeDefinition td;
192      if (typeDefinitions.TryGetValue(key, out td))
193        return td;
194      else
195        return null;
196    }
197   
198    public IAssembly Resolve(ITypeResolveContext context)
199    {
200      if (context == null)
201        throw new ArgumentNullException("context");
202      Freeze();
203      var cache = context.Compilation.CacheManager;
204      IAssembly asm = (IAssembly)cache.GetShared(this);
205      if (asm != null) {
206        return asm;
207      } else {
208        asm = new DefaultResolvedAssembly(context.Compilation, this);
209        return (IAssembly)cache.GetOrAddShared(this, asm);
210      }
211    }
212   
213    public override string ToString()
214    {
215      return "[" + GetType().Name + " " + assemblyName + "]";
216    }
217   
218    //[NonSerialized]
219    //List<Dictionary<TopLevelTypeName, IUnresolvedTypeDefinition>> cachedTypeDictionariesPerNameComparer;
220   
221    Dictionary<TopLevelTypeName, IUnresolvedTypeDefinition> GetTypeDictionary(StringComparer nameComparer)
222    {
223      Debug.Assert(IsFrozen);
224      if (nameComparer == StringComparer.Ordinal)
225        return typeDefinitions;
226      else
227        throw new NotImplementedException();
228    }
229   
230    #region UnresolvedNamespace
231    sealed class UnresolvedNamespace
232    {
233      internal readonly string FullName;
234      internal readonly string Name;
235      internal readonly List<UnresolvedNamespace> Children = new List<UnresolvedNamespace>();
236     
237      public UnresolvedNamespace(string fullName, string name)
238      {
239        this.FullName = fullName;
240        this.Name = name;
241      }
242    }
243   
244    [NonSerialized]
245    List<KeyValuePair<StringComparer, UnresolvedNamespace>> unresolvedNamespacesPerNameComparer;
246   
247    UnresolvedNamespace GetUnresolvedRootNamespace(StringComparer nameComparer)
248    {
249      Debug.Assert(IsFrozen);
250      LazyInitializer.EnsureInitialized(ref unresolvedNamespacesPerNameComparer);
251      lock (unresolvedNamespacesPerNameComparer) {
252        foreach (var pair in unresolvedNamespacesPerNameComparer) {
253          if (pair.Key == nameComparer)
254            return pair.Value;
255        }
256        var root = new UnresolvedNamespace(string.Empty, string.Empty);
257        var dict = new Dictionary<string, UnresolvedNamespace>(nameComparer);
258        dict.Add(root.FullName, root);
259        foreach (var typeName in typeDefinitions.Keys) {
260          GetOrAddNamespace(dict, typeName.Namespace);
261        }
262        unresolvedNamespacesPerNameComparer.Add(new KeyValuePair<StringComparer, UnresolvedNamespace>(nameComparer, root));
263        return root;
264      }
265    }
266   
267    static UnresolvedNamespace GetOrAddNamespace(Dictionary<string, UnresolvedNamespace> dict, string fullName)
268    {
269      UnresolvedNamespace ns;
270      if (dict.TryGetValue(fullName, out ns))
271        return ns;
272      int pos = fullName.LastIndexOf('.');
273      UnresolvedNamespace parent;
274      string name;
275      if (pos < 0) {
276        parent = dict[string.Empty]; // root
277        name = fullName;
278      } else {
279        parent = GetOrAddNamespace(dict, fullName.Substring(0, pos));
280        name = fullName.Substring(pos + 1);
281      }
282      ns = new UnresolvedNamespace(fullName, name);
283      parent.Children.Add(ns);
284      dict.Add(fullName, ns);
285      return ns;
286    }
287    #endregion
288   
289    sealed class DefaultResolvedAssembly : IAssembly
290    {
291      readonly DefaultUnresolvedAssembly unresolvedAssembly;
292      readonly ICompilation compilation;
293      readonly ITypeResolveContext context;
294      readonly Dictionary<TopLevelTypeName, IUnresolvedTypeDefinition> unresolvedTypeDict;
295      readonly ConcurrentDictionary<IUnresolvedTypeDefinition, ITypeDefinition> typeDict = new ConcurrentDictionary<IUnresolvedTypeDefinition, ITypeDefinition>();
296      readonly INamespace rootNamespace;
297     
298      public DefaultResolvedAssembly(ICompilation compilation, DefaultUnresolvedAssembly unresolved)
299      {
300        this.compilation = compilation;
301        this.unresolvedAssembly = unresolved;
302        this.unresolvedTypeDict = unresolved.GetTypeDictionary(compilation.NameComparer);
303        this.rootNamespace = new NS(this, unresolved.GetUnresolvedRootNamespace(compilation.NameComparer), null);
304        this.context = new SimpleTypeResolveContext(this);
305        this.AssemblyAttributes = unresolved.AssemblyAttributes.CreateResolvedAttributes(context);
306        this.ModuleAttributes = unresolved.ModuleAttributes.CreateResolvedAttributes(context);
307      }
308     
309      public IUnresolvedAssembly UnresolvedAssembly {
310        get { return unresolvedAssembly; }
311      }
312     
313      public bool IsMainAssembly {
314        get { return this.Compilation.MainAssembly == this; }
315      }
316     
317      public string AssemblyName {
318        get { return unresolvedAssembly.AssemblyName; }
319      }
320     
321      public string FullAssemblyName {
322        get { return unresolvedAssembly.FullAssemblyName; }
323      }
324     
325      public IList<IAttribute> AssemblyAttributes { get; private set; }
326      public IList<IAttribute> ModuleAttributes { get; private set; }
327     
328      public INamespace RootNamespace {
329        get { return rootNamespace; }
330      }
331     
332      public ICompilation Compilation {
333        get { return compilation; }
334      }
335 
336      public bool InternalsVisibleTo(IAssembly assembly)
337      {
338        if (this == assembly)
339          return true;
340        foreach (string shortName in GetInternalsVisibleTo()) {
341          if (assembly.AssemblyName == shortName)
342            return true;
343        }
344        return false;
345      }
346
347      volatile string[] internalsVisibleTo;
348
349      string[] GetInternalsVisibleTo()
350      {
351        var result = this.internalsVisibleTo;
352        if (result != null) {
353          return result;
354        } else {
355          using (var busyLock = BusyManager.Enter(this)) {
356            Debug.Assert(busyLock.Success);
357            if (!busyLock.Success) {
358              return new string[0];
359            }
360            internalsVisibleTo = (
361              from attr in this.AssemblyAttributes
362              where attr.AttributeType.Name == "InternalsVisibleToAttribute"
363              && attr.AttributeType.Namespace == "System.Runtime.CompilerServices"
364              && attr.PositionalArguments.Count == 1
365              select GetShortName(attr.PositionalArguments.Single().ConstantValue as string)
366            ).ToArray();
367          }
368          return internalsVisibleTo;
369        }
370      }
371
372      static string GetShortName(string fullAssemblyName)
373      {
374        if (fullAssemblyName == null)
375          return null;
376        int pos = fullAssemblyName.IndexOf(',');
377        if (pos < 0)
378          return fullAssemblyName;
379        else
380          return fullAssemblyName.Substring(0, pos);
381      }
382
383      public ITypeDefinition GetTypeDefinition(TopLevelTypeName topLevelTypeName)
384      {
385        IUnresolvedTypeDefinition td;
386        ITypeReference typeRef;
387        if (unresolvedAssembly.typeDefinitions.TryGetValue(topLevelTypeName, out td))
388          return GetTypeDefinition(td);
389        if (unresolvedAssembly.typeForwarders.TryGetValue(topLevelTypeName, out typeRef)) {
390          // Protect against cyclic type forwarders:
391          using (var busyLock = BusyManager.Enter(typeRef)) {
392            if (busyLock.Success)
393              return typeRef.Resolve(compilation.TypeResolveContext).GetDefinition();
394          }
395        }
396        return null;
397      }
398     
399      ITypeDefinition GetTypeDefinition(IUnresolvedTypeDefinition unresolved)
400      {
401        return typeDict.GetOrAdd(unresolved, t => CreateTypeDefinition(t));
402      }
403     
404      ITypeDefinition CreateTypeDefinition(IUnresolvedTypeDefinition unresolved)
405      {
406        if (unresolved.DeclaringTypeDefinition != null) {
407          ITypeDefinition declaringType = GetTypeDefinition(unresolved.DeclaringTypeDefinition);
408          return new DefaultResolvedTypeDefinition(context.WithCurrentTypeDefinition(declaringType), unresolved);
409        } else if (unresolved.Name == "Void" && unresolved.Namespace == "System" && unresolved.TypeParameters.Count == 0) {
410          return new VoidTypeDefinition(context, unresolved);
411        } else {
412          return new DefaultResolvedTypeDefinition(context, unresolved);
413        }
414      }
415     
416      public IEnumerable<ITypeDefinition> TopLevelTypeDefinitions {
417        get {
418          return unresolvedAssembly.TopLevelTypeDefinitions.Select(t => GetTypeDefinition(t));
419        }
420      }
421     
422      public override string ToString()
423      {
424        return "[DefaultResolvedAssembly " + AssemblyName + "]";
425      }
426     
427      sealed class NS : INamespace
428      {
429        readonly DefaultResolvedAssembly assembly;
430        readonly UnresolvedNamespace ns;
431        readonly INamespace parentNamespace;
432        readonly IList<NS> childNamespaces;
433        IEnumerable<ITypeDefinition> types;
434       
435        public NS(DefaultResolvedAssembly assembly, UnresolvedNamespace ns, INamespace parentNamespace)
436        {
437          this.assembly = assembly;
438          this.ns = ns;
439          this.parentNamespace = parentNamespace;
440          this.childNamespaces = new ProjectedList<NS, UnresolvedNamespace, NS>(
441            this, ns.Children, (self, c) => new NS(self.assembly, c, self));
442        }
443       
444        string INamespace.ExternAlias {
445          get { return null; }
446        }
447       
448        string INamespace.FullName {
449          get { return ns.FullName; }
450        }
451       
452        SymbolKind ISymbol.SymbolKind {
453          get { return SymbolKind.Namespace; }
454        }
455       
456        public string Name {
457          get { return ns.Name; }
458        }
459       
460        INamespace INamespace.ParentNamespace {
461          get { return parentNamespace; }
462        }
463       
464        IEnumerable<IAssembly> INamespace.ContributingAssemblies {
465          get { return new [] { assembly }; }
466        }
467       
468        IEnumerable<INamespace> INamespace.ChildNamespaces {
469          get { return childNamespaces; }
470        }
471       
472        INamespace INamespace.GetChildNamespace(string name)
473        {
474          var nameComparer = assembly.compilation.NameComparer;
475          for (int i = 0; i < childNamespaces.Count; i++) {
476            if (nameComparer.Equals(name, ns.Children[i].Name))
477              return childNamespaces[i];
478          }
479          return null;
480        }
481       
482        ICompilation ICompilationProvider.Compilation {
483          get { return assembly.compilation; }
484        }
485       
486        IEnumerable<ITypeDefinition> INamespace.Types {
487          get {
488            var result = LazyInit.VolatileRead(ref this.types);
489            if (result != null) {
490              return result;
491            } else {
492              var hashSet = new HashSet<ITypeDefinition>();
493              foreach (IUnresolvedTypeDefinition typeDef in assembly.UnresolvedAssembly.TopLevelTypeDefinitions) {
494                if (typeDef.Namespace == ns.FullName)
495                  hashSet.Add(assembly.GetTypeDefinition(typeDef));
496              }
497              return LazyInit.GetOrSet(ref this.types, hashSet.ToArray());
498            }
499          }
500        }
501       
502        ITypeDefinition INamespace.GetTypeDefinition(string name, int typeParameterCount)
503        {
504          var key = new TopLevelTypeName(ns.FullName, name, typeParameterCount);
505          IUnresolvedTypeDefinition unresolvedTypeDef;
506          if (assembly.unresolvedTypeDict.TryGetValue(key, out unresolvedTypeDef))
507            return assembly.GetTypeDefinition(unresolvedTypeDef);
508          else
509            return null;
510        }
511       
512        public ISymbolReference ToReference()
513        {
514          return new NamespaceReference(new DefaultAssemblyReference(assembly.AssemblyName), ns.FullName);
515        }
516      }
517    }
518  }
519 
520  public sealed class NamespaceReference : ISymbolReference
521  {
522    IAssemblyReference assemblyReference;
523    string fullName;
524   
525    public NamespaceReference(IAssemblyReference assemblyReference, string fullName)
526    {
527      if (assemblyReference == null)
528        throw new ArgumentNullException("assemblyReference");
529      this.assemblyReference = assemblyReference;
530      this.fullName = fullName;
531    }
532   
533    public ISymbol Resolve(ITypeResolveContext context)
534    {
535      IAssembly assembly = assemblyReference.Resolve(context);
536      INamespace parent = assembly.RootNamespace;
537     
538      string[] parts = fullName.Split('.');
539     
540      int i = 0;
541      while (i < parts.Length && parent != null) {
542        parent = parent.GetChildNamespace(parts[i]);
543        i++;
544      }
545     
546      return parent;
547    }
548  }
549 
550  public sealed class MergedNamespaceReference : ISymbolReference
551  {
552    string externAlias;
553    string fullName;
554   
555    public MergedNamespaceReference(string externAlias, string fullName)
556    {
557      this.externAlias = externAlias;
558      this.fullName = fullName;
559    }
560   
561    public ISymbol Resolve(ITypeResolveContext context)
562    {
563      string[] parts = fullName.Split('.');
564      INamespace parent = context.Compilation.GetNamespaceForExternAlias(externAlias);
565     
566      int i = 0;
567      while (i < parts.Length && parent != null) {
568        parent = parent.GetChildNamespace(parts[i]);
569        i++;
570      }
571     
572      return parent;
573    }
574  }
575}
Note: See TracBrowser for help on using the repository browser.