1
// Copyright (c) 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;
25
using ICSharpCode.NRefactory.CSharp.Analysis;
26
using ICSharpCode.NRefactory.CSharp.Resolver;
27
using ICSharpCode.NRefactory.CSharp.TypeSystem;
28
using ICSharpCode.NRefactory.CSharp.TypeSystem.ConstantValues;
29
using ICSharpCode.NRefactory.TypeSystem;
30
using ICSharpCode.NRefactory.TypeSystem.Implementation;
31
using ICSharpCode.NRefactory.Utils;
33
namespace ICSharpCode.NRefactory.CSharp.TypeSystem
36
/// Produces type and member definitions from the DOM.
38
public class TypeSystemConvertVisitor : DepthFirstAstVisitor<IUnresolvedEntity>
40
readonly CSharpParsedFile parsedFile;
41
UsingScope usingScope;
42
CSharpUnresolvedTypeDefinition currentTypeDefinition;
43
DefaultUnresolvedMethod currentMethod;
45
IInterningProvider interningProvider = new SimpleInterningProvider();
48
/// Gets/Sets the interning provider to use.
49
/// The default value is a new <see cref="SimpleInterningProvider"/> instance.
51
public IInterningProvider InterningProvider {
52
get { return interningProvider; }
53
set { interningProvider = value; }
57
/// Gets/Sets whether to ignore XML documentation.
58
/// The default value is false.
60
public bool SkipXmlDocumentation { get; set; }
63
/// Creates a new TypeSystemConvertVisitor.
65
/// <param name="fileName">The file name (used for DomRegions).</param>
66
public TypeSystemConvertVisitor(string fileName)
69
throw new ArgumentNullException("fileName");
70
this.parsedFile = new CSharpParsedFile(fileName);
71
this.usingScope = parsedFile.RootUsingScope;
75
/// Creates a new TypeSystemConvertVisitor and initializes it with a given context.
77
/// <param name="parsedFile">The parsed file to which members should be added.</param>
78
/// <param name="currentUsingScope">The current using scope.</param>
79
/// <param name="currentTypeDefinition">The current type definition.</param>
80
public TypeSystemConvertVisitor(CSharpParsedFile parsedFile, UsingScope currentUsingScope = null, CSharpUnresolvedTypeDefinition currentTypeDefinition = null)
82
if (parsedFile == null)
83
throw new ArgumentNullException("parsedFile");
84
this.parsedFile = parsedFile;
85
this.usingScope = currentUsingScope ?? parsedFile.RootUsingScope;
86
this.currentTypeDefinition = currentTypeDefinition;
89
public CSharpParsedFile ParsedFile {
90
get { return parsedFile; }
93
DomRegion MakeRegion(TextLocation start, TextLocation end)
95
return new DomRegion(parsedFile.FileName, start.Line, start.Column, end.Line, end.Column);
98
DomRegion MakeRegion(AstNode node)
100
if (node == null || node.IsNull)
101
return DomRegion.Empty;
103
return MakeRegion(node.StartLocation, node.EndLocation);
106
DomRegion MakeBraceRegion(AstNode node)
108
if (node == null || node.IsNull)
109
return DomRegion.Empty;
111
return MakeRegion(node.GetChildByRole(Roles.LBrace).StartLocation,
112
node.GetChildByRole(Roles.RBrace).EndLocation);
115
#region Compilation Unit
116
public override IUnresolvedEntity VisitCompilationUnit (CompilationUnit unit)
118
parsedFile.Errors = unit.Errors;
119
return base.VisitCompilationUnit (unit);
123
#region Using Declarations
124
public override IUnresolvedEntity VisitExternAliasDeclaration(ExternAliasDeclaration externAliasDeclaration)
126
usingScope.ExternAliases.Add(externAliasDeclaration.Name);
130
public override IUnresolvedEntity VisitUsingDeclaration(UsingDeclaration usingDeclaration)
132
TypeOrNamespaceReference u = usingDeclaration.Import.ToTypeReference(NameLookupMode.TypeInUsingDeclaration) as TypeOrNamespaceReference;
134
if (interningProvider != null)
135
u = interningProvider.Intern(u);
136
usingScope.Usings.Add(u);
141
public override IUnresolvedEntity VisitUsingAliasDeclaration(UsingAliasDeclaration usingDeclaration)
143
TypeOrNamespaceReference u = usingDeclaration.Import.ToTypeReference(NameLookupMode.TypeInUsingDeclaration) as TypeOrNamespaceReference;
145
if (interningProvider != null)
146
u = interningProvider.Intern(u);
147
usingScope.UsingAliases.Add(new KeyValuePair<string, TypeOrNamespaceReference>(usingDeclaration.Alias, u));
153
#region Namespace Declaration
154
public override IUnresolvedEntity VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration)
156
DomRegion region = MakeRegion(namespaceDeclaration);
157
UsingScope previousUsingScope = usingScope;
158
foreach (Identifier ident in namespaceDeclaration.Identifiers) {
159
usingScope = new UsingScope(usingScope, ident.Name);
160
usingScope.Region = region;
162
base.VisitNamespaceDeclaration(namespaceDeclaration);
163
parsedFile.UsingScopes.Add(usingScope); // add after visiting children so that nested scopes come first
164
usingScope = previousUsingScope;
169
#region Type Definitions
170
CSharpUnresolvedTypeDefinition CreateTypeDefinition(string name)
172
CSharpUnresolvedTypeDefinition newType;
173
if (currentTypeDefinition != null) {
174
newType = new CSharpUnresolvedTypeDefinition(currentTypeDefinition, name);
175
foreach (var typeParameter in currentTypeDefinition.TypeParameters)
176
newType.TypeParameters.Add(typeParameter);
177
currentTypeDefinition.NestedTypes.Add(newType);
179
newType = new CSharpUnresolvedTypeDefinition(usingScope, name);
180
parsedFile.TopLevelTypeDefinitions.Add(newType);
182
newType.ParsedFile = parsedFile;
183
newType.HasExtensionMethods = false; // gets set to true when an extension method is added
187
public override IUnresolvedEntity VisitTypeDeclaration(TypeDeclaration typeDeclaration)
189
var td = currentTypeDefinition = CreateTypeDefinition(typeDeclaration.Name);
190
td.Region = MakeRegion(typeDeclaration);
191
td.BodyRegion = MakeBraceRegion(typeDeclaration);
192
AddXmlDocumentation(td, typeDeclaration);
194
ApplyModifiers(td, typeDeclaration.Modifiers);
195
switch (typeDeclaration.ClassType) {
197
td.Kind = TypeKind.Enum;
199
case ClassType.Interface:
200
td.Kind = TypeKind.Interface;
201
td.IsAbstract = true; // interfaces are implicitly abstract
203
case ClassType.Struct:
204
td.Kind = TypeKind.Struct;
205
td.IsSealed = true; // enums/structs are implicitly sealed
209
ConvertAttributes(td.Attributes, typeDeclaration.Attributes);
211
ConvertTypeParameters(td.TypeParameters, typeDeclaration.TypeParameters, typeDeclaration.Constraints, EntityType.TypeDefinition);
213
foreach (AstType baseType in typeDeclaration.BaseTypes) {
214
td.BaseTypes.Add(baseType.ToTypeReference(NameLookupMode.BaseTypeReference));
217
foreach (EntityDeclaration member in typeDeclaration.Members) {
218
member.AcceptVisitor(this);
221
currentTypeDefinition = (CSharpUnresolvedTypeDefinition)currentTypeDefinition.DeclaringTypeDefinition;
222
if (interningProvider != null) {
223
td.ApplyInterningProvider(interningProvider);
228
public override IUnresolvedEntity VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration)
230
var td = currentTypeDefinition = CreateTypeDefinition(delegateDeclaration.Name);
231
td.Kind = TypeKind.Delegate;
232
td.Region = MakeRegion(delegateDeclaration);
233
td.BaseTypes.Add(KnownTypeReference.MulticastDelegate);
234
AddXmlDocumentation(td, delegateDeclaration);
236
ApplyModifiers(td, delegateDeclaration.Modifiers);
237
td.IsSealed = true; // delegates are implicitly sealed
239
ConvertTypeParameters(td.TypeParameters, delegateDeclaration.TypeParameters, delegateDeclaration.Constraints, EntityType.TypeDefinition);
241
ITypeReference returnType = delegateDeclaration.ReturnType.ToTypeReference();
242
List<IUnresolvedParameter> parameters = new List<IUnresolvedParameter>();
243
ConvertParameters(parameters, delegateDeclaration.Parameters);
244
AddDefaultMethodsToDelegate(td, returnType, parameters);
246
foreach (AttributeSection section in delegateDeclaration.Attributes) {
247
if (section.AttributeTarget == "return") {
248
List<IUnresolvedAttribute> returnTypeAttributes = new List<IUnresolvedAttribute>();
249
ConvertAttributes(returnTypeAttributes, section);
250
IUnresolvedMethod invokeMethod = (IUnresolvedMethod)td.Members.Single(m => m.Name == "Invoke");
251
IUnresolvedMethod endInvokeMethod = (IUnresolvedMethod)td.Members.Single(m => m.Name == "EndInvoke");
252
foreach (IUnresolvedAttribute attr in returnTypeAttributes) {
253
invokeMethod.ReturnTypeAttributes.Add(attr);
254
endInvokeMethod.ReturnTypeAttributes.Add(attr);
257
ConvertAttributes(td.Attributes, section);
261
currentTypeDefinition = (CSharpUnresolvedTypeDefinition)currentTypeDefinition.DeclaringTypeDefinition;
262
if (interningProvider != null) {
263
td.ApplyInterningProvider(interningProvider);
268
static readonly IUnresolvedParameter delegateObjectParameter = MakeParameter(KnownTypeReference.Object, "object");
269
static readonly IUnresolvedParameter delegateIntPtrMethodParameter = MakeParameter(KnownTypeReference.IntPtr, "method");
270
static readonly IUnresolvedParameter delegateAsyncCallbackParameter = MakeParameter(typeof(AsyncCallback).ToTypeReference(), "callback");
271
static readonly IUnresolvedParameter delegateResultParameter = MakeParameter(typeof(IAsyncResult).ToTypeReference(), "result");
273
static IUnresolvedParameter MakeParameter(ITypeReference type, string name)
275
DefaultUnresolvedParameter p = new DefaultUnresolvedParameter(type, name);
281
/// Adds the 'Invoke', 'BeginInvoke', 'EndInvoke' methods, and a constructor, to the <paramref name="delegateType"/>.
283
public static void AddDefaultMethodsToDelegate(DefaultUnresolvedTypeDefinition delegateType, ITypeReference returnType, IEnumerable<IUnresolvedParameter> parameters)
285
if (delegateType == null)
286
throw new ArgumentNullException("delegateType");
287
if (returnType == null)
288
throw new ArgumentNullException("returnType");
289
if (parameters == null)
290
throw new ArgumentNullException("parameters");
292
DomRegion region = delegateType.Region;
293
region = new DomRegion(region.FileName, region.BeginLine, region.BeginColumn); // remove end position
295
DefaultUnresolvedMethod invoke = new DefaultUnresolvedMethod(delegateType, "Invoke");
296
invoke.Accessibility = Accessibility.Public;
297
invoke.IsSynthetic = true;
298
foreach (var p in parameters)
299
invoke.Parameters.Add(p);
300
invoke.ReturnType = returnType;
301
invoke.Region = region;
302
delegateType.Members.Add(invoke);
304
DefaultUnresolvedMethod beginInvoke = new DefaultUnresolvedMethod(delegateType, "BeginInvoke");
305
beginInvoke.Accessibility = Accessibility.Public;
306
beginInvoke.IsSynthetic = true;
307
foreach (var p in parameters)
308
beginInvoke.Parameters.Add(p);
309
beginInvoke.Parameters.Add(delegateAsyncCallbackParameter);
310
beginInvoke.Parameters.Add(delegateObjectParameter);
311
beginInvoke.ReturnType = delegateResultParameter.Type;
312
beginInvoke.Region = region;
313
delegateType.Members.Add(beginInvoke);
315
DefaultUnresolvedMethod endInvoke = new DefaultUnresolvedMethod(delegateType, "EndInvoke");
316
endInvoke.Accessibility = Accessibility.Public;
317
endInvoke.IsSynthetic = true;
318
endInvoke.Parameters.Add(delegateResultParameter);
319
endInvoke.ReturnType = invoke.ReturnType;
320
endInvoke.Region = region;
321
delegateType.Members.Add(endInvoke);
323
DefaultUnresolvedMethod ctor = new DefaultUnresolvedMethod(delegateType, ".ctor");
324
ctor.EntityType = EntityType.Constructor;
325
ctor.Accessibility = Accessibility.Public;
326
ctor.IsSynthetic = true;
327
ctor.Parameters.Add(delegateObjectParameter);
328
ctor.Parameters.Add(delegateIntPtrMethodParameter);
329
ctor.ReturnType = delegateType;
330
ctor.Region = region;
331
delegateType.Members.Add(ctor);
336
public override IUnresolvedEntity VisitFieldDeclaration(FieldDeclaration fieldDeclaration)
338
bool isSingleField = fieldDeclaration.Variables.Count == 1;
339
Modifiers modifiers = fieldDeclaration.Modifiers;
340
DefaultUnresolvedField field = null;
341
foreach (VariableInitializer vi in fieldDeclaration.Variables) {
342
field = new DefaultUnresolvedField(currentTypeDefinition, vi.Name);
344
field.Region = isSingleField ? MakeRegion(fieldDeclaration) : MakeRegion(vi);
345
field.BodyRegion = MakeRegion(vi);
346
ConvertAttributes(field.Attributes, fieldDeclaration.Attributes);
347
AddXmlDocumentation(field, fieldDeclaration);
349
ApplyModifiers(field, modifiers);
350
field.IsVolatile = (modifiers & Modifiers.Volatile) != 0;
351
field.IsReadOnly = (modifiers & Modifiers.Readonly) != 0;
353
field.ReturnType = fieldDeclaration.ReturnType.ToTypeReference();
355
if ((modifiers & Modifiers.Const) != 0) {
356
field.ConstantValue = ConvertConstantValue(field.ReturnType, vi.Initializer);
357
field.IsStatic = true;
360
currentTypeDefinition.Members.Add(field);
361
if (interningProvider != null) {
362
field.ApplyInterningProvider(interningProvider);
365
return isSingleField ? field : null;
368
public override IUnresolvedEntity VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration)
370
// TODO: add support for fixed fields
371
return base.VisitFixedFieldDeclaration(fixedFieldDeclaration);
374
public override IUnresolvedEntity VisitEnumMemberDeclaration(EnumMemberDeclaration enumMemberDeclaration)
376
DefaultUnresolvedField field = new DefaultUnresolvedField(currentTypeDefinition, enumMemberDeclaration.Name);
377
field.Region = field.BodyRegion = MakeRegion(enumMemberDeclaration);
378
ConvertAttributes(field.Attributes, enumMemberDeclaration.Attributes);
379
AddXmlDocumentation(field, enumMemberDeclaration);
381
if (currentTypeDefinition.TypeParameters.Count == 0) {
382
field.ReturnType = currentTypeDefinition;
384
ITypeReference[] typeArgs = new ITypeReference[currentTypeDefinition.TypeParameters.Count];
385
for (int i = 0; i < typeArgs.Length; i++) {
386
typeArgs[i] = new TypeParameterReference(EntityType.TypeDefinition, i);
388
field.ReturnType = new ParameterizedTypeReference(currentTypeDefinition, typeArgs);
390
field.Accessibility = Accessibility.Public;
391
field.IsStatic = true;
392
if (!enumMemberDeclaration.Initializer.IsNull) {
393
field.ConstantValue = ConvertConstantValue(field.ReturnType, enumMemberDeclaration.Initializer);
395
DefaultUnresolvedField prevField = currentTypeDefinition.Members.LastOrDefault() as DefaultUnresolvedField;
396
if (prevField == null || prevField.ConstantValue == null) {
397
field.ConstantValue = ConvertConstantValue(field.ReturnType, new PrimitiveExpression(0));
399
field.ConstantValue = new IncrementConstantValue(prevField.ConstantValue);
403
currentTypeDefinition.Members.Add(field);
404
if (interningProvider != null) {
405
field.ApplyInterningProvider(interningProvider);
412
public override IUnresolvedEntity VisitMethodDeclaration(MethodDeclaration methodDeclaration)
414
DefaultUnresolvedMethod m = new DefaultUnresolvedMethod(currentTypeDefinition, methodDeclaration.Name);
415
currentMethod = m; // required for resolving type parameters
416
m.Region = MakeRegion(methodDeclaration);
417
m.BodyRegion = MakeRegion(methodDeclaration.Body);
418
AddXmlDocumentation(m, methodDeclaration);
420
if (InheritsConstraints(methodDeclaration) && methodDeclaration.Constraints.Count == 0) {
422
foreach (TypeParameterDeclaration tpDecl in methodDeclaration.TypeParameters) {
423
var tp = new MethodTypeParameterWithInheritedConstraints(index++, tpDecl.Name);
424
tp.Region = MakeRegion(tpDecl);
425
ConvertAttributes(tp.Attributes, tpDecl.Attributes);
426
tp.Variance = tpDecl.Variance;
427
m.TypeParameters.Add(tp);
430
ConvertTypeParameters(m.TypeParameters, methodDeclaration.TypeParameters, methodDeclaration.Constraints, EntityType.Method);
432
m.ReturnType = methodDeclaration.ReturnType.ToTypeReference();
433
ConvertAttributes(m.Attributes, methodDeclaration.Attributes.Where(s => s.AttributeTarget != "return"));
434
ConvertAttributes(m.ReturnTypeAttributes, methodDeclaration.Attributes.Where(s => s.AttributeTarget == "return"));
436
ApplyModifiers(m, methodDeclaration.Modifiers);
437
if (methodDeclaration.IsExtensionMethod) {
438
m.IsExtensionMethod = true;
439
currentTypeDefinition.HasExtensionMethods = true;
441
if (methodDeclaration.HasModifier(Modifiers.Partial)) {
442
if (methodDeclaration.Body.IsNull)
443
m.IsPartialMethodDeclaration = true;
445
m.IsPartialMethodImplementation = true;
448
ConvertParameters(m.Parameters, methodDeclaration.Parameters);
449
if (!methodDeclaration.PrivateImplementationType.IsNull) {
450
m.Accessibility = Accessibility.None;
451
m.IsExplicitInterfaceImplementation = true;
452
m.ExplicitInterfaceImplementations.Add(new DefaultMemberReference(
453
m.EntityType, methodDeclaration.PrivateImplementationType.ToTypeReference(), m.Name,
454
m.TypeParameters.Count, GetParameterTypes(m.Parameters)));
457
currentTypeDefinition.Members.Add(m);
458
currentMethod = null;
459
if (interningProvider != null) {
460
m.ApplyInterningProvider(interningProvider);
465
IList<ITypeReference> GetParameterTypes(IList<IUnresolvedParameter> parameters)
467
if (parameters.Count == 0)
468
return EmptyList<ITypeReference>.Instance;
469
ITypeReference[] types = new ITypeReference[parameters.Count];
470
for (int i = 0; i < types.Length; i++) {
471
types[i] = parameters[i].Type;
476
bool InheritsConstraints(MethodDeclaration methodDeclaration)
478
// overrides and explicit interface implementations inherit constraints
479
if ((methodDeclaration.Modifiers & Modifiers.Override) == Modifiers.Override)
481
return !methodDeclaration.PrivateImplementationType.IsNull;
484
void ConvertTypeParameters(IList<IUnresolvedTypeParameter> output, AstNodeCollection<TypeParameterDeclaration> typeParameters,
485
AstNodeCollection<Constraint> constraints, EntityType ownerType)
487
// output might be non-empty when type parameters were copied from an outer class
488
int index = output.Count;
489
List<DefaultUnresolvedTypeParameter> list = new List<DefaultUnresolvedTypeParameter>();
490
foreach (TypeParameterDeclaration tpDecl in typeParameters) {
491
DefaultUnresolvedTypeParameter tp = new DefaultUnresolvedTypeParameter(ownerType, index++, tpDecl.Name);
492
tp.Region = MakeRegion(tpDecl);
493
ConvertAttributes(tp.Attributes, tpDecl.Attributes);
494
tp.Variance = tpDecl.Variance;
496
output.Add(tp); // tp must be added to list here so that it can be referenced by constraints
498
foreach (Constraint c in constraints) {
499
foreach (var tp in list) {
500
if (tp.Name == c.TypeParameter.Identifier) {
501
foreach (AstType type in c.BaseTypes) {
502
PrimitiveType primType = type as PrimitiveType;
503
if (primType != null) {
504
if (primType.Keyword == "new") {
505
tp.HasDefaultConstructorConstraint = true;
507
} else if (primType.Keyword == "class") {
508
tp.HasReferenceTypeConstraint = true;
510
} else if (primType.Keyword == "struct") {
511
tp.HasValueTypeConstraint = true;
515
tp.Constraints.Add(type.ToTypeReference());
523
IMemberReference ConvertInterfaceImplementation(AstType interfaceType, AbstractUnresolvedMember unresolvedMember)
525
ITypeReference interfaceTypeReference = interfaceType.ToTypeReference();
526
int typeParameterCount = 0;
527
IList<ITypeReference> parameterTypes = null;
528
if (unresolvedMember.EntityType == EntityType.Method) {
529
typeParameterCount = ((IUnresolvedMethod)unresolvedMember).TypeParameters.Count;
531
IUnresolvedParameterizedMember parameterizedMember = unresolvedMember as IUnresolvedParameterizedMember;
532
if (parameterizedMember != null) {
533
parameterTypes = new ITypeReference[parameterizedMember.Parameters.Count];
534
for (int i = 0; i < parameterTypes.Count; i++) {
535
parameterTypes[i] = parameterizedMember.Parameters[i].Type;
538
return new DefaultMemberReference(unresolvedMember.EntityType, interfaceTypeReference, unresolvedMember.Name, typeParameterCount, parameterTypes);
543
public override IUnresolvedEntity VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration)
545
DefaultUnresolvedMethod m = new DefaultUnresolvedMethod(currentTypeDefinition, operatorDeclaration.Name);
546
m.EntityType = EntityType.Operator;
547
m.Region = MakeRegion(operatorDeclaration);
548
m.BodyRegion = MakeRegion(operatorDeclaration.Body);
549
AddXmlDocumentation(m, operatorDeclaration);
551
m.ReturnType = operatorDeclaration.ReturnType.ToTypeReference();
552
ConvertAttributes(m.Attributes, operatorDeclaration.Attributes.Where(s => s.AttributeTarget != "return"));
553
ConvertAttributes(m.ReturnTypeAttributes, operatorDeclaration.Attributes.Where(s => s.AttributeTarget == "return"));
555
ApplyModifiers(m, operatorDeclaration.Modifiers);
557
ConvertParameters(m.Parameters, operatorDeclaration.Parameters);
559
currentTypeDefinition.Members.Add(m);
560
if (interningProvider != null) {
561
m.ApplyInterningProvider(interningProvider);
568
public override IUnresolvedEntity VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration)
570
Modifiers modifiers = constructorDeclaration.Modifiers;
571
bool isStatic = (modifiers & Modifiers.Static) != 0;
572
DefaultUnresolvedMethod ctor = new DefaultUnresolvedMethod(currentTypeDefinition, isStatic ? ".cctor" : ".ctor");
573
ctor.EntityType = EntityType.Constructor;
574
ctor.Region = MakeRegion(constructorDeclaration);
575
if (!constructorDeclaration.Initializer.IsNull) {
576
ctor.BodyRegion = MakeRegion(constructorDeclaration.Initializer.StartLocation, constructorDeclaration.EndLocation);
578
ctor.BodyRegion = MakeRegion(constructorDeclaration.Body);
580
ctor.ReturnType = KnownTypeReference.Void;
582
ConvertAttributes(ctor.Attributes, constructorDeclaration.Attributes);
583
ConvertParameters(ctor.Parameters, constructorDeclaration.Parameters);
584
AddXmlDocumentation(ctor, constructorDeclaration);
587
ctor.IsStatic = true;
589
ApplyModifiers(ctor, modifiers);
591
currentTypeDefinition.Members.Add(ctor);
592
if (interningProvider != null) {
593
ctor.ApplyInterningProvider(interningProvider);
600
public override IUnresolvedEntity VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration)
602
DefaultUnresolvedMethod dtor = new DefaultUnresolvedMethod(currentTypeDefinition, "Finalize");
603
dtor.EntityType = EntityType.Destructor;
604
dtor.Region = MakeRegion(destructorDeclaration);
605
dtor.BodyRegion = MakeRegion(destructorDeclaration.Body);
606
dtor.Accessibility = Accessibility.Protected;
607
dtor.IsOverride = true;
608
dtor.ReturnType = KnownTypeReference.Void;
610
ConvertAttributes(dtor.Attributes, destructorDeclaration.Attributes);
611
AddXmlDocumentation(dtor, destructorDeclaration);
613
currentTypeDefinition.Members.Add(dtor);
614
if (interningProvider != null) {
615
dtor.ApplyInterningProvider(interningProvider);
621
#region Properties / Indexers
622
public override IUnresolvedEntity VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration)
624
DefaultUnresolvedProperty p = new DefaultUnresolvedProperty(currentTypeDefinition, propertyDeclaration.Name);
625
p.Region = MakeRegion(propertyDeclaration);
626
p.BodyRegion = MakeBraceRegion(propertyDeclaration);
627
ApplyModifiers(p, propertyDeclaration.Modifiers);
628
p.ReturnType = propertyDeclaration.ReturnType.ToTypeReference();
629
ConvertAttributes(p.Attributes, propertyDeclaration.Attributes);
630
AddXmlDocumentation(p, propertyDeclaration);
631
if (!propertyDeclaration.PrivateImplementationType.IsNull) {
632
p.Accessibility = Accessibility.None;
633
p.IsExplicitInterfaceImplementation = true;
634
p.ExplicitInterfaceImplementations.Add(new DefaultMemberReference(
635
p.EntityType, propertyDeclaration.PrivateImplementationType.ToTypeReference(), p.Name));
637
p.Getter = ConvertAccessor(propertyDeclaration.Getter, p, "get_");
638
p.Setter = ConvertAccessor(propertyDeclaration.Setter, p, "set_");
639
currentTypeDefinition.Members.Add(p);
640
if (interningProvider != null) {
641
p.ApplyInterningProvider(interningProvider);
646
public override IUnresolvedEntity VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration)
648
DefaultUnresolvedProperty p = new DefaultUnresolvedProperty(currentTypeDefinition, "Item");
649
p.EntityType = EntityType.Indexer;
650
p.Region = MakeRegion(indexerDeclaration);
651
p.BodyRegion = MakeBraceRegion(indexerDeclaration);
652
ApplyModifiers(p, indexerDeclaration.Modifiers);
653
p.ReturnType = indexerDeclaration.ReturnType.ToTypeReference();
654
ConvertAttributes(p.Attributes, indexerDeclaration.Attributes);
655
AddXmlDocumentation(p, indexerDeclaration);
657
ConvertParameters(p.Parameters, indexerDeclaration.Parameters);
658
p.Getter = ConvertAccessor(indexerDeclaration.Getter, p, "get_");
659
p.Setter = ConvertAccessor(indexerDeclaration.Setter, p, "set_");
661
if (!indexerDeclaration.PrivateImplementationType.IsNull) {
662
p.Accessibility = Accessibility.None;
663
p.IsExplicitInterfaceImplementation = true;
664
p.ExplicitInterfaceImplementations.Add(new DefaultMemberReference(
665
p.EntityType, indexerDeclaration.PrivateImplementationType.ToTypeReference(), p.Name, 0, GetParameterTypes(p.Parameters)));
668
currentTypeDefinition.Members.Add(p);
669
if (interningProvider != null) {
670
p.ApplyInterningProvider(interningProvider);
675
DefaultUnresolvedMethod ConvertAccessor(Accessor accessor, IUnresolvedMember p, string prefix)
679
var a = new DefaultUnresolvedMethod(currentTypeDefinition, prefix + p.Name);
680
a.Accessibility = GetAccessibility(accessor.Modifiers) ?? p.Accessibility;
681
a.IsAbstract = p.IsAbstract;
682
a.IsOverride = p.IsOverridable;
683
a.IsSealed = p.IsSealed;
684
a.IsStatic = p.IsStatic;
685
a.IsSynthetic = p.IsSynthetic;
686
a.IsVirtual = p.IsVirtual;
688
a.Region = MakeRegion(accessor);
689
if (p.EntityType == EntityType.Indexer) {
690
foreach (var indexerParam in ((IUnresolvedProperty)p).Parameters)
691
a.Parameters.Add(indexerParam);
693
DefaultUnresolvedParameter param = null;
694
if (accessor.Role == PropertyDeclaration.GetterRole) {
695
a.ReturnType = p.ReturnType;
697
param = new DefaultUnresolvedParameter(p.ReturnType, "value");
698
a.Parameters.Add(param);
699
a.ReturnType = KnownTypeReference.Void;
701
foreach (AttributeSection section in accessor.Attributes) {
702
if (section.AttributeTarget == "return") {
703
ConvertAttributes(a.ReturnTypeAttributes, section);
704
} else if (param != null && section.AttributeTarget == "param") {
705
ConvertAttributes(param.Attributes, section);
707
ConvertAttributes(a.Attributes, section);
715
public override IUnresolvedEntity VisitEventDeclaration(EventDeclaration eventDeclaration)
717
bool isSingleEvent = eventDeclaration.Variables.Count == 1;
718
Modifiers modifiers = eventDeclaration.Modifiers;
719
DefaultUnresolvedEvent ev = null;
720
foreach (VariableInitializer vi in eventDeclaration.Variables) {
721
ev = new DefaultUnresolvedEvent(currentTypeDefinition, vi.Name);
723
ev.Region = isSingleEvent ? MakeRegion(eventDeclaration) : MakeRegion(vi);
724
ev.BodyRegion = MakeRegion(vi);
726
ApplyModifiers(ev, modifiers);
727
AddXmlDocumentation(ev, eventDeclaration);
729
ev.ReturnType = eventDeclaration.ReturnType.ToTypeReference();
731
var valueParameter = new DefaultUnresolvedParameter(ev.ReturnType, "value");
732
ev.AddAccessor = CreateDefaultEventAccessor(ev, "add_" + ev.Name, valueParameter);
733
ev.RemoveAccessor = CreateDefaultEventAccessor(ev, "remove_" + ev.Name, valueParameter);
735
foreach (AttributeSection section in eventDeclaration.Attributes) {
736
if (section.AttributeTarget == "method") {
737
foreach (var attrNode in section.Attributes) {
738
IUnresolvedAttribute attr = ConvertAttribute(attrNode);
739
ev.AddAccessor.Attributes.Add(attr);
740
ev.RemoveAccessor.Attributes.Add(attr);
742
} else if (section.AttributeTarget != "field") {
743
ConvertAttributes(ev.Attributes, section);
747
currentTypeDefinition.Members.Add(ev);
748
if (interningProvider != null) {
749
ev.ApplyInterningProvider(interningProvider);
752
return isSingleEvent ? ev : null;
755
DefaultUnresolvedMethod CreateDefaultEventAccessor(IUnresolvedEvent ev, string name, IUnresolvedParameter valueParameter)
757
var a = new DefaultUnresolvedMethod(currentTypeDefinition, name);
758
a.Region = ev.BodyRegion;
759
a.BodyRegion = ev.BodyRegion;
760
a.Accessibility = ev.Accessibility;
761
a.IsAbstract = ev.IsAbstract;
762
a.IsOverride = ev.IsOverridable;
763
a.IsSealed = ev.IsSealed;
764
a.IsStatic = ev.IsStatic;
765
a.IsSynthetic = ev.IsSynthetic;
766
a.IsVirtual = ev.IsVirtual;
767
a.ReturnType = KnownTypeReference.Void;
768
a.Parameters.Add(valueParameter);
772
public override IUnresolvedEntity VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration)
774
DefaultUnresolvedEvent e = new DefaultUnresolvedEvent(currentTypeDefinition, eventDeclaration.Name);
775
e.Region = MakeRegion(eventDeclaration);
776
e.BodyRegion = MakeBraceRegion(eventDeclaration);
777
ApplyModifiers(e, eventDeclaration.Modifiers);
778
e.ReturnType = eventDeclaration.ReturnType.ToTypeReference();
779
ConvertAttributes(e.Attributes, eventDeclaration.Attributes);
780
AddXmlDocumentation(e, eventDeclaration);
782
if (!eventDeclaration.PrivateImplementationType.IsNull) {
783
e.Accessibility = Accessibility.None;
784
e.IsExplicitInterfaceImplementation = true;
785
e.ExplicitInterfaceImplementations.Add(new DefaultMemberReference(
786
e.EntityType, eventDeclaration.PrivateImplementationType.ToTypeReference(), e.Name));
789
e.AddAccessor = ConvertAccessor(eventDeclaration.AddAccessor, e, "add_");
790
e.RemoveAccessor = ConvertAccessor(eventDeclaration.RemoveAccessor, e, "remove_");
792
currentTypeDefinition.Members.Add(e);
793
if (interningProvider != null) {
794
e.ApplyInterningProvider(interningProvider);
801
static void ApplyModifiers(DefaultUnresolvedTypeDefinition td, Modifiers modifiers)
803
td.Accessibility = GetAccessibility(modifiers) ?? (td.DeclaringTypeDefinition != null ? Accessibility.Private : Accessibility.Internal);
804
td.IsAbstract = (modifiers & (Modifiers.Abstract | Modifiers.Static)) != 0;
805
td.IsSealed = (modifiers & (Modifiers.Sealed | Modifiers.Static)) != 0;
806
td.IsShadowing = (modifiers & Modifiers.New) != 0;
809
static void ApplyModifiers(AbstractUnresolvedMember m, Modifiers modifiers)
811
// members from interfaces are always Public+Abstract.
812
if (m.DeclaringTypeDefinition.Kind == TypeKind.Interface) {
813
m.Accessibility = Accessibility.Public;
817
m.Accessibility = GetAccessibility(modifiers) ?? Accessibility.Private;
818
m.IsAbstract = (modifiers & Modifiers.Abstract) != 0;
819
m.IsOverride = (modifiers & Modifiers.Override) != 0;
820
m.IsSealed = (modifiers & Modifiers.Sealed) != 0;
821
m.IsShadowing = (modifiers & Modifiers.New) != 0;
822
m.IsStatic = (modifiers & Modifiers.Static) != 0;
823
m.IsVirtual = (modifiers & Modifiers.Virtual) != 0;
824
//m.IsPartial = (modifiers & Modifiers.Partial) != 0;
827
static Accessibility? GetAccessibility(Modifiers modifiers)
829
switch (modifiers & Modifiers.VisibilityMask) {
830
case Modifiers.Private:
831
return Accessibility.Private;
832
case Modifiers.Internal:
833
return Accessibility.Internal;
834
case Modifiers.Protected | Modifiers.Internal:
835
return Accessibility.ProtectedOrInternal;
836
case Modifiers.Protected:
837
return Accessibility.Protected;
838
case Modifiers.Public:
839
return Accessibility.Public;
847
public override IUnresolvedEntity VisitAttributeSection(AttributeSection attributeSection)
849
// non-assembly attributes are handled by their parent entity
850
if (attributeSection.AttributeTarget == "assembly") {
851
ConvertAttributes(parsedFile.AssemblyAttributes, attributeSection);
852
} else if (attributeSection.AttributeTarget == "module") {
853
ConvertAttributes(parsedFile.ModuleAttributes, attributeSection);
858
void ConvertAttributes(IList<IUnresolvedAttribute> outputList, IEnumerable<AttributeSection> attributes)
860
foreach (AttributeSection section in attributes) {
861
ConvertAttributes(outputList, section);
865
void ConvertAttributes(IList<IUnresolvedAttribute> outputList, AttributeSection attributeSection)
867
foreach (CSharp.Attribute attr in attributeSection.Attributes) {
868
outputList.Add(ConvertAttribute(attr));
872
internal static ITypeReference ConvertAttributeType(AstType type)
874
ITypeReference tr = type.ToTypeReference();
875
if (!type.GetChildByRole(Roles.Identifier).IsVerbatim) {
876
// Try to add "Attribute" suffix, but only if the identifier
877
// (=last identifier in fully qualified name) isn't a verbatim identifier.
878
SimpleTypeOrNamespaceReference st = tr as SimpleTypeOrNamespaceReference;
879
MemberTypeOrNamespaceReference mt = tr as MemberTypeOrNamespaceReference;
881
return new AttributeTypeReference(st, st.AddSuffix("Attribute"));
883
return new AttributeTypeReference(mt, mt.AddSuffix("Attribute"));
888
CSharpAttribute ConvertAttribute(CSharp.Attribute attr)
890
DomRegion region = MakeRegion(attr);
891
ITypeReference type = ConvertAttributeType(attr.Type);
892
List<IConstantValue> positionalArguments = null;
893
List<KeyValuePair<string, IConstantValue>> namedCtorArguments = null;
894
List<KeyValuePair<string, IConstantValue>> namedArguments = null;
895
foreach (Expression expr in attr.Arguments) {
896
NamedArgumentExpression nae = expr as NamedArgumentExpression;
898
if (namedCtorArguments == null)
899
namedCtorArguments = new List<KeyValuePair<string, IConstantValue>>();
900
namedCtorArguments.Add(new KeyValuePair<string, IConstantValue>(nae.Name, ConvertAttributeArgument(nae.Expression)));
902
NamedExpression namedExpression = expr as NamedExpression;
903
if (namedExpression != null) {
904
string name = namedExpression.Name;
905
if (namedArguments == null)
906
namedArguments = new List<KeyValuePair<string, IConstantValue>>();
907
namedArguments.Add(new KeyValuePair<string, IConstantValue>(name, ConvertAttributeArgument(namedExpression.Expression)));
909
if (positionalArguments == null)
910
positionalArguments = new List<IConstantValue>();
911
positionalArguments.Add(ConvertAttributeArgument(expr));
915
return new CSharpAttribute(type, region, positionalArguments, namedCtorArguments, namedArguments);
920
[Obsolete("Use AstType.ToTypeReference() instead.")]
921
public static ITypeReference ConvertType(AstType type, NameLookupMode lookupMode = NameLookupMode.Type)
923
return type.ToTypeReference(lookupMode);
927
#region Constant Values
928
IConstantValue ConvertConstantValue(ITypeReference targetType, AstNode expression)
930
return ConvertConstantValue(targetType, expression, currentTypeDefinition, currentMethod, usingScope);
933
internal static IConstantValue ConvertConstantValue(
934
ITypeReference targetType, AstNode expression,
935
IUnresolvedTypeDefinition parentTypeDefinition, IUnresolvedMethod parentMethodDefinition, UsingScope parentUsingScope)
937
ConstantValueBuilder b = new ConstantValueBuilder(false);
938
ConstantExpression c = expression.AcceptVisitor(b);
940
return new ErrorConstantValue(targetType);
941
PrimitiveConstantExpression pc = c as PrimitiveConstantExpression;
942
if (pc != null && pc.Type == targetType) {
943
// Save memory by directly using a SimpleConstantValue.
944
return new SimpleConstantValue(targetType, pc.Value);
946
// cast to the desired type
947
return new ConstantCast(targetType, c);
950
IConstantValue ConvertAttributeArgument(Expression expression)
952
ConstantValueBuilder b = new ConstantValueBuilder(true);
953
return expression.AcceptVisitor(b);
956
sealed class ConstantValueBuilder : DepthFirstAstVisitor<ConstantExpression>
958
readonly bool isAttributeArgument;
960
public ConstantValueBuilder(bool isAttributeArgument)
962
this.isAttributeArgument = isAttributeArgument;
965
protected override ConstantExpression VisitChildren(AstNode node)
970
public override ConstantExpression VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression)
972
return new PrimitiveConstantExpression(KnownTypeReference.Object, null);
975
public override ConstantExpression VisitPrimitiveExpression(PrimitiveExpression primitiveExpression)
977
TypeCode typeCode = Type.GetTypeCode(primitiveExpression.Value.GetType());
978
return new PrimitiveConstantExpression(typeCode.ToTypeReference(), primitiveExpression.Value);
981
IList<ITypeReference> ConvertTypeArguments(AstNodeCollection<AstType> types)
983
int count = types.Count;
986
ITypeReference[] result = new ITypeReference[count];
988
foreach (AstType type in types) {
989
result[pos++] = type.ToTypeReference();
994
public override ConstantExpression VisitIdentifierExpression(IdentifierExpression identifierExpression)
996
return new ConstantIdentifierReference(identifierExpression.Identifier, ConvertTypeArguments(identifierExpression.TypeArguments));
999
public override ConstantExpression VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
1001
TypeReferenceExpression tre = memberReferenceExpression.Target as TypeReferenceExpression;
1003
// handle "int.MaxValue"
1004
return new ConstantMemberReference(
1005
tre.Type.ToTypeReference(),
1006
memberReferenceExpression.MemberName,
1007
ConvertTypeArguments(memberReferenceExpression.TypeArguments));
1009
ConstantExpression v = memberReferenceExpression.Target.AcceptVisitor(this);
1012
return new ConstantMemberReference(
1013
v, memberReferenceExpression.MemberName,
1014
ConvertTypeArguments(memberReferenceExpression.TypeArguments));
1017
public override ConstantExpression VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression)
1019
return parenthesizedExpression.Expression.AcceptVisitor(this);
1022
public override ConstantExpression VisitCastExpression(CastExpression castExpression)
1024
ConstantExpression v = castExpression.Expression.AcceptVisitor(this);
1027
return new ConstantCast(castExpression.Type.ToTypeReference(), v);
1030
public override ConstantExpression VisitCheckedExpression(CheckedExpression checkedExpression)
1032
ConstantExpression v = checkedExpression.Expression.AcceptVisitor(this);
1034
return new ConstantCheckedExpression(true, v);
1039
public override ConstantExpression VisitUncheckedExpression(UncheckedExpression uncheckedExpression)
1041
ConstantExpression v = uncheckedExpression.Expression.AcceptVisitor(this);
1043
return new ConstantCheckedExpression(false, v);
1048
public override ConstantExpression VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression)
1050
return new ConstantDefaultValue(defaultValueExpression.Type.ToTypeReference());
1053
public override ConstantExpression VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression)
1055
ConstantExpression v = unaryOperatorExpression.Expression.AcceptVisitor(this);
1058
switch (unaryOperatorExpression.Operator) {
1059
case UnaryOperatorType.Not:
1060
case UnaryOperatorType.BitNot:
1061
case UnaryOperatorType.Minus:
1062
case UnaryOperatorType.Plus:
1063
return new ConstantUnaryOperator(unaryOperatorExpression.Operator, v);
1069
public override ConstantExpression VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression)
1071
ConstantExpression left = binaryOperatorExpression.Left.AcceptVisitor(this);
1072
ConstantExpression right = binaryOperatorExpression.Right.AcceptVisitor(this);
1073
if (left == null || right == null)
1075
return new ConstantBinaryOperator(left, binaryOperatorExpression.Operator, right);
1078
public override ConstantExpression VisitTypeOfExpression(TypeOfExpression typeOfExpression)
1080
if (isAttributeArgument) {
1081
return new TypeOfConstantExpression(typeOfExpression.Type.ToTypeReference());
1087
public override ConstantExpression VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression)
1089
var initializer = arrayCreateExpression.Initializer;
1090
// Attributes only allow one-dimensional arrays
1091
if (isAttributeArgument && !initializer.IsNull && arrayCreateExpression.Arguments.Count < 2) {
1092
ITypeReference type;
1093
if (arrayCreateExpression.Type.IsNull) {
1096
type = arrayCreateExpression.Type.ToTypeReference();
1097
foreach (var spec in arrayCreateExpression.AdditionalArraySpecifiers.Reverse()) {
1098
type = new ArrayTypeReference(type, spec.Dimensions);
1101
ConstantExpression[] elements = new ConstantExpression[initializer.Elements.Count];
1103
foreach (Expression expr in initializer.Elements) {
1104
ConstantExpression c = expr.AcceptVisitor(this);
1107
elements[pos++] = c;
1109
return new ConstantArrayCreation(type, elements);
1118
void ConvertParameters(IList<IUnresolvedParameter> outputList, IEnumerable<ParameterDeclaration> parameters)
1120
foreach (ParameterDeclaration pd in parameters) {
1121
DefaultUnresolvedParameter p = new DefaultUnresolvedParameter(pd.Type.ToTypeReference(), pd.Name);
1122
p.Region = MakeRegion(pd);
1123
ConvertAttributes(p.Attributes, pd.Attributes);
1124
switch (pd.ParameterModifier) {
1125
case ParameterModifier.Ref:
1127
p.Type = new ByReferenceTypeReference(p.Type);
1129
case ParameterModifier.Out:
1131
p.Type = new ByReferenceTypeReference(p.Type);
1133
case ParameterModifier.Params:
1137
if (!pd.DefaultExpression.IsNull)
1138
p.DefaultValue = ConvertConstantValue(p.Type, pd.DefaultExpression);
1143
internal static IList<ITypeReference> GetParameterTypes(IEnumerable<ParameterDeclaration> parameters)
1145
List<ITypeReference> result = new List<ITypeReference>();
1146
foreach (ParameterDeclaration pd in parameters) {
1147
ITypeReference type = pd.Type.ToTypeReference();
1148
if (pd.ParameterModifier == ParameterModifier.Ref || pd.ParameterModifier == ParameterModifier.Out)
1149
type = new ByReferenceTypeReference(type);
1156
#region XML Documentation
1157
void AddXmlDocumentation(IUnresolvedEntity entity, AstNode entityDeclaration)
1159
if (this.SkipXmlDocumentation)
1161
List<string> documentation = null;
1162
// traverse AST backwards until the next non-whitespace node
1163
for (AstNode node = entityDeclaration.PrevSibling; node != null && node.NodeType == NodeType.Whitespace; node = node.PrevSibling) {
1164
Comment c = node as Comment;
1165
if (c != null && (c.CommentType == CommentType.Documentation || c.CommentType == CommentType.MultiLineDocumentation)) {
1166
if (documentation == null)
1167
documentation = new List<string>();
1168
if (c.CommentType == CommentType.MultiLineDocumentation) {
1169
documentation.Add(PrepareMultilineDocumentation(c.Content));
1171
if (c.Content.Length > 0 && c.Content[0] == ' ')
1172
documentation.Add(c.Content.Substring(1));
1174
documentation.Add(c.Content);
1178
if (documentation != null) {
1179
documentation.Reverse(); // bring documentation in correct order
1180
parsedFile.AddDocumentation(entity, string.Join(Environment.NewLine, documentation));
1184
string PrepareMultilineDocumentation(string content)
1186
StringBuilder b = new StringBuilder();
1187
using (var reader = new StringReader(content)) {
1188
string firstLine = reader.ReadLine();
1189
// Add first line only if it's not empty:
1190
if (!string.IsNullOrWhiteSpace(firstLine)) {
1191
if (firstLine[0] == ' ')
1192
b.Append(firstLine, 1, firstLine.Length - 1);
1194
b.Append(firstLine);
1196
// Read lines into list:
1197
List<string> lines = new List<string>();
1199
while ((line = reader.ReadLine()) != null)
1201
// If the last line (the line with '*/' delimiter) is white space only, ignore it.
1202
if (lines.Count > 0 && string.IsNullOrWhiteSpace(lines[lines.Count - 1]))
1203
lines.RemoveAt(lines.Count - 1);
1204
if (lines.Count > 0) {
1205
// Extract pattern from lines[0]: whitespace, asterisk, whitespace
1206
int patternLength = 0;
1207
string secondLine = lines[0];
1208
while (patternLength < secondLine.Length && char.IsWhiteSpace(secondLine[patternLength]))
1210
if (patternLength < secondLine.Length && secondLine[patternLength] == '*') {
1212
while (patternLength < secondLine.Length && char.IsWhiteSpace(secondLine[patternLength]))
1218
// Now reduce pattern length to the common pattern:
1219
for (int i = 1; i < lines.Count; i++) {
1221
if (line.Length < patternLength)
1222
patternLength = line.Length;
1223
for (int j = 0; j < patternLength; j++) {
1224
if (secondLine[j] != line[j])
1228
// Append the lines to the string builder:
1229
for (int i = 0; i < lines.Count; i++) {
1230
if (b.Length > 0 || i > 0)
1231
b.Append(Environment.NewLine);
1232
b.Append(lines[i], patternLength, lines[i].Length - patternLength);
1236
return b.ToString();