1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
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:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
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.
20
using System.Collections.Generic;
21
using System.Diagnostics;
23
using System.Threading;
24
using ICSharpCode.NRefactory.TypeSystem;
25
using ICSharpCode.NRefactory.TypeSystem.Implementation;
26
using ICSharpCode.NRefactory.Utils;
28
namespace ICSharpCode.NRefactory.CSharp.TypeSystem
30
public class CSharpAssembly : IAssembly
32
readonly ICompilation compilation;
33
readonly ITypeResolveContext context;
34
readonly CSharpProjectContent projectContent;
35
IList<IAttribute> assemblyAttributes;
36
IList<IAttribute> moduleAttributes;
38
internal CSharpAssembly(ICompilation compilation, CSharpProjectContent projectContent)
40
this.compilation = compilation;
41
this.projectContent = projectContent;
42
this.context = new SimpleTypeResolveContext(this);
45
public bool IsMainAssembly {
46
get { return compilation.MainAssembly == this; }
49
public IUnresolvedAssembly UnresolvedAssembly {
50
get { return projectContent; }
53
public string AssemblyName {
54
get { return projectContent.AssemblyName; }
57
public string FullAssemblyName {
58
get { return projectContent.FullAssemblyName; }
61
public IList<IAttribute> AssemblyAttributes {
63
return GetAttributes(ref assemblyAttributes, true);
67
public IList<IAttribute> ModuleAttributes {
69
return GetAttributes(ref moduleAttributes, false);
73
IList<IAttribute> GetAttributes(ref IList<IAttribute> field, bool assemblyAttributes)
75
IList<IAttribute> result = LazyInit.VolatileRead(ref field);
79
result = new List<IAttribute>();
80
foreach (var unresolvedFile in projectContent.Files.OfType<CSharpUnresolvedFile>()) {
81
var attributes = assemblyAttributes ? unresolvedFile.AssemblyAttributes : unresolvedFile.ModuleAttributes;
82
var context = new CSharpTypeResolveContext(this, unresolvedFile.RootUsingScope.Resolve(compilation));
83
foreach (var unresolvedAttr in attributes) {
84
result.Add(unresolvedAttr.CreateResolvedAttribute(context));
87
return LazyInit.GetOrSet(ref field, result);
93
public INamespace RootNamespace {
95
NS root = LazyInit.VolatileRead(ref this.rootNamespace);
100
Dictionary<string, NS> dict = new Dictionary<string, NS>(compilation.NameComparer);
101
dict.Add(string.Empty, root);
102
// Add namespaces declared in C# files, even if they're empty:
103
foreach (var usingScope in projectContent.Files.OfType<CSharpUnresolvedFile>().SelectMany(f => f.UsingScopes)) {
104
GetOrAddNamespace(dict, usingScope.NamespaceName);
106
foreach (var pair in GetTypes()) {
107
NS ns = GetOrAddNamespace(dict, pair.Key.Namespace);
108
if (ns.types != null)
109
ns.types[pair.Key] = pair.Value;
111
return LazyInit.GetOrSet(ref this.rootNamespace, root);
116
static NS GetOrAddNamespace(Dictionary<string, NS> dict, string fullName)
119
if (dict.TryGetValue(fullName, out ns))
121
int pos = fullName.LastIndexOf('.');
125
parent = dict[string.Empty]; // root
128
parent = GetOrAddNamespace(dict, fullName.Substring(0, pos));
129
name = fullName.Substring(pos + 1);
131
ns = new NS(parent, fullName, name);
132
parent.childNamespaces.Add(ns);
133
dict.Add(fullName, ns);
137
public ICompilation Compilation {
138
get { return compilation; }
141
public bool InternalsVisibleTo(IAssembly assembly)
143
if (this == assembly)
145
foreach (string shortName in GetInternalsVisibleTo()) {
146
if (assembly.AssemblyName == shortName)
152
volatile string[] internalsVisibleTo;
154
string[] GetInternalsVisibleTo()
156
var result = this.internalsVisibleTo;
157
if (result != null) {
160
using (var busyLock = BusyManager.Enter(this)) {
161
Debug.Assert(busyLock.Success);
162
if (!busyLock.Success) {
163
return new string[0];
165
internalsVisibleTo = (
166
from attr in this.AssemblyAttributes
167
where attr.AttributeType.Name == "InternalsVisibleToAttribute"
168
&& attr.AttributeType.Namespace == "System.Runtime.CompilerServices"
169
&& attr.PositionalArguments.Count == 1
170
select GetShortName(attr.PositionalArguments.Single().ConstantValue as string)
173
return internalsVisibleTo;
177
static string GetShortName(string fullAssemblyName)
179
if (fullAssemblyName == null)
181
int pos = fullAssemblyName.IndexOf(',');
183
return fullAssemblyName;
185
return fullAssemblyName.Substring(0, pos);
188
Dictionary<TopLevelTypeName, ITypeDefinition> typeDict;
190
Dictionary<TopLevelTypeName, ITypeDefinition> GetTypes()
192
var dict = LazyInit.VolatileRead(ref this.typeDict);
196
// Always use the ordinal comparer for the main dictionary so that partial classes
197
// get merged correctly.
198
// The compilation's comparer will be used for the per-namespace dictionaries.
199
var comparer = TopLevelTypeNameComparer.Ordinal;
200
dict = projectContent.TopLevelTypeDefinitions
201
.GroupBy(t => new TopLevelTypeName(t.Namespace, t.Name, t.TypeParameters.Count), comparer)
202
.ToDictionary(g => g.Key, g => CreateResolvedTypeDefinition(g.ToArray()), comparer);
203
return LazyInit.GetOrSet(ref this.typeDict, dict);
207
ITypeDefinition CreateResolvedTypeDefinition(IUnresolvedTypeDefinition[] parts)
209
return new DefaultResolvedTypeDefinition(context, parts);
212
public ITypeDefinition GetTypeDefinition(TopLevelTypeName topLevelTypeName)
215
if (GetTypes().TryGetValue(topLevelTypeName, out def))
221
public IEnumerable<ITypeDefinition> TopLevelTypeDefinitions {
223
return GetTypes().Values;
227
public override string ToString()
229
return "[CSharpAssembly " + this.AssemblyName + "]";
232
sealed class NS : INamespace
234
readonly CSharpAssembly assembly;
235
readonly NS parentNamespace;
236
readonly string fullName;
237
readonly string name;
238
internal readonly List<NS> childNamespaces = new List<NS>();
239
internal readonly Dictionary<TopLevelTypeName, ITypeDefinition> types;
241
public NS(CSharpAssembly assembly)
243
this.assembly = assembly;
244
this.fullName = string.Empty;
245
this.name = string.Empty;
246
// Our main dictionary for the CSharpAssembly is using an ordinal comparer.
247
// If the compilation's comparer isn't ordinal, we need to create a new dictionary with the compilation's comparer.
248
if (assembly.compilation.NameComparer != StringComparer.Ordinal) {
249
this.types = new Dictionary<TopLevelTypeName, ITypeDefinition>(new TopLevelTypeNameComparer(assembly.compilation.NameComparer));
253
public NS(NS parentNamespace, string fullName, string name)
255
this.assembly = parentNamespace.assembly;
256
this.parentNamespace = parentNamespace;
257
this.fullName = fullName;
259
if (parentNamespace.types != null)
260
this.types = new Dictionary<TopLevelTypeName, ITypeDefinition>(parentNamespace.types.Comparer);
263
string INamespace.ExternAlias {
267
string INamespace.FullName {
268
get { return fullName; }
271
string INamespace.Name {
275
INamespace INamespace.ParentNamespace {
276
get { return parentNamespace; }
279
IEnumerable<INamespace> INamespace.ChildNamespaces {
280
get { return childNamespaces; }
283
IEnumerable<ITypeDefinition> INamespace.Types {
289
from t in assembly.GetTypes()
290
where t.Key.Namespace == fullName
296
ICompilation ICompilationProvider.Compilation {
297
get { return assembly.Compilation; }
300
IEnumerable<IAssembly> INamespace.ContributingAssemblies {
301
get { return new [] { assembly }; }
304
INamespace INamespace.GetChildNamespace(string name)
306
var nameComparer = assembly.compilation.NameComparer;
307
foreach (NS childNamespace in childNamespaces) {
308
if (nameComparer.Equals(name, childNamespace.name))
309
return childNamespace;
314
ITypeDefinition INamespace.GetTypeDefinition(string name, int typeParameterCount)
316
var key = new TopLevelTypeName(fullName, name, typeParameterCount);
318
ITypeDefinition typeDef;
319
if (types.TryGetValue(key, out typeDef))
324
return assembly.GetTypeDefinition(key);