.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

3541 lines
98 KiB

//
// class.cs: Class and Struct handlers
//
// Authors: Miguel de Icaza (miguel@gnu.org)
// Martin Baulig (martin@ximian.com)
// Marek Safar (marek.safar@gmail.com)
//
// Dual licensed under the terms of the MIT X11 or GNU GPL
//
// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
// Copyright 2004-2011 Novell, Inc
// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
//
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Linq;
using System.Text;
using System.Diagnostics;
#if NET_2_1
using XmlElement = System.Object;
#endif
#if STATIC
using SecurityType = System.Collections.Generic.List<IKVM.Reflection.Emit.CustomAttributeBuilder>;
using IKVM.Reflection;
using IKVM.Reflection.Emit;
#else
using SecurityType = System.Collections.Generic.Dictionary<System.Security.Permissions.SecurityAction, System.Security.PermissionSet>;
using System.Reflection;
using System.Reflection.Emit;
#endif
namespace Mono.CSharp
{
//
// General types container, used as a base class for all constructs which can hold types
//
public abstract class TypeContainer : MemberCore
{
public readonly MemberKind Kind;
public readonly string Basename;
protected List<TypeContainer> containers;
TypeDefinition main_container;
protected Dictionary<string, MemberCore> defined_names;
protected bool is_defined;
public TypeContainer (TypeContainer parent, MemberName name, Attributes attrs, MemberKind kind)
: base (parent, name, attrs)
{
this.Kind = kind;
if (name != null)
this.Basename = name.Basename;
defined_names = new Dictionary<string, MemberCore> ();
}
public override TypeSpec CurrentType {
get {
return null;
}
}
public TypeDefinition PartialContainer {
get {
return main_container;
}
protected set {
main_container = value;
}
}
public IList<TypeContainer> Containers {
get {
return containers;
}
}
#if FULL_AST
//
// Any unattached attributes during parsing get added here.
//
public Attributes UnattachedAttributes {
get; set;
}
#endif
public virtual void AddCompilerGeneratedClass (CompilerGeneratedClass c)
{
containers.Add (c);
}
public virtual void AddPartial (TypeDefinition next_part)
{
MemberCore mc;
(PartialContainer ?? this).defined_names.TryGetValue (next_part.Basename, out mc);
AddPartial (next_part, mc as TypeDefinition);
}
protected void AddPartial (TypeDefinition next_part, TypeDefinition existing)
{
next_part.ModFlags |= Modifiers.PARTIAL;
if (existing == null) {
AddTypeContainer (next_part);
return;
}
if ((existing.ModFlags & Modifiers.PARTIAL) == 0) {
if (existing.Kind != next_part.Kind) {
AddTypeContainer (next_part);
} else {
Report.SymbolRelatedToPreviousError (next_part);
Error_MissingPartialModifier (existing);
}
return;
}
if (existing.Kind != next_part.Kind) {
Report.SymbolRelatedToPreviousError (existing);
Report.Error (261, next_part.Location,
"Partial declarations of `{0}' must be all classes, all structs or all interfaces",
next_part.GetSignatureForError ());
}
if ((existing.ModFlags & Modifiers.AccessibilityMask) != (next_part.ModFlags & Modifiers.AccessibilityMask) &&
((existing.ModFlags & Modifiers.DEFAULT_ACCESS_MODIFER) == 0 &&
(next_part.ModFlags & Modifiers.DEFAULT_ACCESS_MODIFER) == 0)) {
Report.SymbolRelatedToPreviousError (existing);
Report.Error (262, next_part.Location,
"Partial declarations of `{0}' have conflicting accessibility modifiers",
next_part.GetSignatureForError ());
}
var tc_names = existing.CurrentTypeParameters;
if (tc_names != null) {
for (int i = 0; i < tc_names.Count; ++i) {
var tp = next_part.MemberName.TypeParameters[i];
if (tc_names[i].MemberName.Name != tp.MemberName.Name) {
Report.SymbolRelatedToPreviousError (existing.Location, "");
Report.Error (264, next_part.Location, "Partial declarations of `{0}' must have the same type parameter names in the same order",
next_part.GetSignatureForError ());
break;
}
if (tc_names[i].Variance != tp.Variance) {
Report.SymbolRelatedToPreviousError (existing.Location, "");
Report.Error (1067, next_part.Location, "Partial declarations of `{0}' must have the same type parameter variance modifiers",
next_part.GetSignatureForError ());
break;
}
}
}
if ((next_part.ModFlags & Modifiers.DEFAULT_ACCESS_MODIFER) != 0) {
existing.ModFlags |= next_part.ModFlags & ~(Modifiers.DEFAULT_ACCESS_MODIFER | Modifiers.AccessibilityMask);
} else if ((existing.ModFlags & Modifiers.DEFAULT_ACCESS_MODIFER) != 0) {
existing.ModFlags &= ~(Modifiers.DEFAULT_ACCESS_MODIFER | Modifiers.AccessibilityMask);
existing.ModFlags |= next_part.ModFlags;
} else {
existing.ModFlags |= next_part.ModFlags;
}
existing.Definition.Modifiers = existing.ModFlags;
if (next_part.attributes != null) {
if (existing.attributes == null)
existing.attributes = next_part.attributes;
else
existing.attributes.AddAttributes (next_part.attributes.Attrs);
}
next_part.PartialContainer = existing;
if (containers == null)
containers = new List<TypeContainer> ();
containers.Add (next_part);
}
public virtual void AddTypeContainer (TypeContainer tc)
{
containers.Add (tc);
var tparams = tc.MemberName.TypeParameters;
if (tparams != null && tc.PartialContainer != null) {
var td = (TypeDefinition) tc;
for (int i = 0; i < tparams.Count; ++i) {
var tp = tparams[i];
if (tp.MemberName == null)
continue;
td.AddNameToContainer (tp, tp.Name);
}
}
}
public virtual void CloseContainer ()
{
if (containers != null) {
foreach (TypeContainer tc in containers) {
tc.CloseContainer ();
}
}
}
public virtual void CreateMetadataName (StringBuilder sb)
{
if (Parent != null && Parent.MemberName != null)
Parent.CreateMetadataName (sb);
MemberName.CreateMetadataName (sb);
}
public virtual bool CreateContainer ()
{
if (containers != null) {
foreach (TypeContainer tc in containers) {
tc.CreateContainer ();
}
}
return true;
}
public override bool Define ()
{
if (containers != null) {
foreach (TypeContainer tc in containers) {
tc.Define ();
}
}
// Release cache used by parser only
if (Module.Evaluator == null) {
defined_names = null;
} else {
defined_names.Clear ();
}
return true;
}
public virtual void PrepareEmit ()
{
if (containers != null) {
foreach (var t in containers) {
t.PrepareEmit ();
}
}
}
public virtual bool DefineContainer ()
{
if (is_defined)
return true;
is_defined = true;
DoDefineContainer ();
if (containers != null) {
foreach (TypeContainer tc in containers) {
try {
tc.DefineContainer ();
} catch (Exception e) {
if (MemberName == MemberName.Null)
throw;
throw new InternalErrorException (tc, e);
}
}
}
return true;
}
protected virtual void DefineNamespace ()
{
if (containers != null) {
foreach (var tc in containers) {
try {
tc.DefineNamespace ();
} catch (Exception e) {
throw new InternalErrorException (tc, e);
}
}
}
}
protected virtual void DoDefineContainer ()
{
}
public virtual void EmitContainer ()
{
if (containers != null) {
for (int i = 0; i < containers.Count; ++i)
containers[i].EmitContainer ();
}
}
protected void Error_MissingPartialModifier (MemberCore type)
{
Report.Error (260, type.Location,
"Missing partial modifier on declaration of type `{0}'. Another partial declaration of this type exists",
type.GetSignatureForError ());
}
public override string GetSignatureForDocumentation ()
{
if (Parent != null && Parent.MemberName != null)
return Parent.GetSignatureForDocumentation () + "." + MemberName.GetSignatureForDocumentation ();
return MemberName.GetSignatureForDocumentation ();
}
public override string GetSignatureForError ()
{
if (Parent != null && Parent.MemberName != null)
return Parent.GetSignatureForError () + "." + MemberName.GetSignatureForError ();
return MemberName.GetSignatureForError ();
}
public virtual void RemoveContainer (TypeContainer cont)
{
if (containers != null)
containers.Remove (cont);
defined_names.Remove (cont.Basename);
}
public virtual void VerifyMembers ()
{
if (containers != null) {
foreach (TypeContainer tc in containers)
tc.VerifyMembers ();
}
}
}
public abstract class TypeDefinition : TypeContainer, ITypeDefinition
{
//
// Different context is needed when resolving type container base
// types. Type names come from the parent scope but type parameter
// names from the container scope.
//
public struct BaseContext : IMemberContext
{
TypeContainer tc;
public BaseContext (TypeContainer tc)
{
this.tc = tc;
}
#region IMemberContext Members
public CompilerContext Compiler {
get { return tc.Compiler; }
}
public TypeSpec CurrentType {
get { return tc.Parent.CurrentType; }
}
public TypeParameters CurrentTypeParameters {
get { return tc.PartialContainer.CurrentTypeParameters; }
}
public MemberCore CurrentMemberDefinition {
get { return tc; }
}
public bool IsObsolete {
get { return tc.IsObsolete; }
}
public bool IsUnsafe {
get { return tc.IsUnsafe; }
}
public bool IsStatic {
get { return tc.IsStatic; }
}
public ModuleContainer Module {
get { return tc.Module; }
}
public string GetSignatureForError ()
{
return tc.GetSignatureForError ();
}
public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
{
return null;
}
public FullNamedExpression LookupNamespaceAlias (string name)
{
return tc.Parent.LookupNamespaceAlias (name);
}
public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
{
if (arity == 0) {
var tp = CurrentTypeParameters;
if (tp != null) {
TypeParameter t = tp.Find (name);
if (t != null)
return new TypeParameterExpr (t, loc);
}
}
return tc.Parent.LookupNamespaceOrType (name, arity, mode, loc);
}
#endregion
}
[Flags]
enum CachedMethods
{
Equals = 1,
GetHashCode = 1 << 1,
HasStaticFieldInitializer = 1 << 2
}
readonly List<MemberCore> members;
// Holds a list of fields that have initializers
protected List<FieldInitializer> initialized_fields;
// Holds a list of static fields that have initializers
protected List<FieldInitializer> initialized_static_fields;
Dictionary<MethodSpec, Method> hoisted_base_call_proxies;
Dictionary<string, FullNamedExpression> Cache = new Dictionary<string, FullNamedExpression> ();
//
// Points to the first non-static field added to the container.
//
// This is an arbitrary choice. We are interested in looking at _some_ non-static field,
// and the first one's as good as any.
//
protected FieldBase first_nonstatic_field;
//
// This one is computed after we can distinguish interfaces
// from classes from the arraylist `type_bases'
//
protected TypeSpec base_type;
FullNamedExpression base_type_expr; // TODO: It's temporary variable
protected TypeSpec[] iface_exprs;
protected List<FullNamedExpression> type_bases;
TypeDefinition InTransit;
public TypeBuilder TypeBuilder;
GenericTypeParameterBuilder[] all_tp_builders;
//
// All recursive type parameters put together sharing same
// TypeParameter instances
//
TypeParameters all_type_parameters;
public const string DefaultIndexerName = "Item";
bool has_normal_indexers;
string indexer_name;
protected bool requires_delayed_unmanagedtype_check;
bool error;
bool members_defined;
bool members_defined_ok;
protected bool has_static_constructor;
private CachedMethods cached_method;
protected TypeSpec spec;
TypeSpec current_type;
public int DynamicSitesCounter;
public int AnonymousMethodsCounter;
static readonly string[] attribute_targets = new string[] { "type" };
/// <remarks>
/// The pending methods that need to be implemented
// (interfaces or abstract methods)
/// </remarks>
PendingImplementation pending;
public TypeDefinition (TypeContainer parent, MemberName name, Attributes attrs, MemberKind kind)
: base (parent, name, attrs, kind)
{
PartialContainer = this;
members = new List<MemberCore> ();
}
#region Properties
public List<FullNamedExpression> BaseTypeExpressions {
get {
return type_bases;
}
}
public override TypeSpec CurrentType {
get {
if (current_type == null) {
if (IsGenericOrParentIsGeneric) {
//
// Switch to inflated version as it's used by all expressions
//
var targs = CurrentTypeParameters == null ? TypeSpec.EmptyTypes : CurrentTypeParameters.Types;
current_type = spec.MakeGenericType (this, targs);
} else {
current_type = spec;
}
}
return current_type;
}
}
public override TypeParameters CurrentTypeParameters {
get {
return PartialContainer.MemberName.TypeParameters;
}
}
int CurrentTypeParametersStartIndex {
get {
int total = all_tp_builders.Length;
if (CurrentTypeParameters != null) {
return total - CurrentTypeParameters.Count;
}
return total;
}
}
public virtual AssemblyDefinition DeclaringAssembly {
get {
return Module.DeclaringAssembly;
}
}
IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
get {
return Module.DeclaringAssembly;
}
}
public TypeSpec Definition {
get {
return spec;
}
}
public bool HasMembersDefined {
get {
return members_defined;
}
}
public List<FullNamedExpression> TypeBaseExpressions {
get {
return type_bases;
}
}
public bool HasInstanceConstructor {
get {
return (caching_flags & Flags.HasInstanceConstructor) != 0;
}
set {
caching_flags |= Flags.HasInstanceConstructor;
}
}
// Indicated whether container has StructLayout attribute set Explicit
public bool HasExplicitLayout {
get { return (caching_flags & Flags.HasExplicitLayout) != 0; }
set { caching_flags |= Flags.HasExplicitLayout; }
}
public bool HasOperators {
get {
return (caching_flags & Flags.HasUserOperators) != 0;
}
set {
caching_flags |= Flags.HasUserOperators;
}
}
public bool HasStructLayout {
get { return (caching_flags & Flags.HasStructLayout) != 0; }
set { caching_flags |= Flags.HasStructLayout; }
}
public TypeSpec[] Interfaces {
get {
return iface_exprs;
}
}
public bool IsGenericOrParentIsGeneric {
get {
return all_type_parameters != null;
}
}
public bool IsTopLevel {
get {
return !(Parent is TypeDefinition);
}
}
//
// Returns true for secondary partial containers
//
bool IsPartialPart {
get {
return PartialContainer != this;
}
}
public MemberCache MemberCache {
get {
return spec.MemberCache;
}
}
public List<MemberCore> Members {
get {
return members;
}
}
string ITypeDefinition.Namespace {
get {
var p = Parent;
while (p.Kind != MemberKind.Namespace)
p = p.Parent;
return p.MemberName == null ? null : p.GetSignatureForError ();
}
}
public TypeParameters TypeParametersAll {
get {
return all_type_parameters;
}
}
public override string[] ValidAttributeTargets {
get {
return attribute_targets;
}
}
#if FULL_AST
public bool HasOptionalSemicolon {
get;
private set;
}
Location optionalSemicolon;
public Location OptionalSemicolon {
get {
return optionalSemicolon;
}
set {
optionalSemicolon = value;
HasOptionalSemicolon = true;
}
}
#endif
#endregion
public override void Accept (StructuralVisitor visitor)
{
visitor.Visit (this);
}
public void AddMember (MemberCore symbol)
{
if (symbol.MemberName.ExplicitInterface != null) {
if (!(Kind == MemberKind.Class || Kind == MemberKind.Struct)) {
Report.Error (541, symbol.Location,
"`{0}': explicit interface declaration can only be declared in a class or struct",
symbol.GetSignatureForError ());
}
}
AddNameToContainer (symbol, symbol.MemberName.Basename);
members.Add (symbol);
}
public override void AddTypeContainer (TypeContainer tc)
{
AddNameToContainer (tc, tc.Basename);
if (containers == null)
containers = new List<TypeContainer> ();
members.Add (tc);
base.AddTypeContainer (tc);
}
public override void AddCompilerGeneratedClass (CompilerGeneratedClass c)
{
members.Add (c);
if (containers == null)
containers = new List<TypeContainer> ();
base.AddCompilerGeneratedClass (c);
}
//
// Adds the member to defined_names table. It tests for duplications and enclosing name conflicts
//
public virtual void AddNameToContainer (MemberCore symbol, string name)
{
if (((ModFlags | symbol.ModFlags) & Modifiers.COMPILER_GENERATED) != 0)
return;
MemberCore mc;
if (!PartialContainer.defined_names.TryGetValue (name, out mc)) {
PartialContainer.defined_names.Add (name, symbol);
return;
}
if (symbol.EnableOverloadChecks (mc))
return;
InterfaceMemberBase im = mc as InterfaceMemberBase;
if (im != null && im.IsExplicitImpl)
return;
Report.SymbolRelatedToPreviousError (mc);
if ((mc.ModFlags & Modifiers.PARTIAL) != 0 && (symbol is ClassOrStruct || symbol is Interface)) {
Error_MissingPartialModifier (symbol);
return;
}
if (symbol is TypeParameter) {
Report.Error (692, symbol.Location,
"Duplicate type parameter `{0}'", symbol.GetSignatureForError ());
} else {
Report.Error (102, symbol.Location,
"The type `{0}' already contains a definition for `{1}'",
GetSignatureForError (), name);
}
return;
}
public void AddConstructor (Constructor c)
{
AddConstructor (c, false);
}
public void AddConstructor (Constructor c, bool isDefault)
{
bool is_static = (c.ModFlags & Modifiers.STATIC) != 0;
if (!isDefault)
AddNameToContainer (c, is_static ? Constructor.TypeConstructorName : Constructor.ConstructorName);
if (is_static && c.ParameterInfo.IsEmpty) {
PartialContainer.has_static_constructor = true;
} else {
PartialContainer.HasInstanceConstructor = true;
}
members.Add (c);
}
public bool AddField (FieldBase field)
{
AddMember (field);
if ((field.ModFlags & Modifiers.STATIC) != 0)
return true;
var first_field = PartialContainer.first_nonstatic_field;
if (first_field == null) {
PartialContainer.first_nonstatic_field = field;
return true;
}
if (Kind == MemberKind.Struct && first_field.Parent != field.Parent) {
Report.SymbolRelatedToPreviousError (first_field.Parent);
Report.Warning (282, 3, field.Location,
"struct instance field `{0}' found in different declaration from instance field `{1}'",
field.GetSignatureForError (), first_field.GetSignatureForError ());
}
return true;
}
/// <summary>
/// Indexer has special handling in constrast to other AddXXX because the name can be driven by IndexerNameAttribute
/// </summary>
public void AddIndexer (Indexer i)
{
members.Add (i);
}
public void AddOperator (Operator op)
{
PartialContainer.HasOperators = true;
AddMember (op);
}
public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
{
if (has_normal_indexers && a.Type == pa.DefaultMember) {
Report.Error (646, a.Location, "Cannot specify the `DefaultMember' attribute on type containing an indexer");
return;
}
if (a.Type == pa.Required) {
Report.Error (1608, a.Location, "The RequiredAttribute attribute is not permitted on C# types");
return;
}
TypeBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
}
public override AttributeTargets AttributeTargets {
get {
throw new NotSupportedException ();
}
}
public TypeSpec BaseType {
get {
return spec.BaseType;
}
}
protected virtual TypeAttributes TypeAttr {
get {
return ModifiersExtensions.TypeAttr (ModFlags, IsTopLevel);
}
}
public int TypeParametersCount {
get {
return MemberName.Arity;
}
}
TypeParameterSpec[] ITypeDefinition.TypeParameters {
get {
return PartialContainer.CurrentTypeParameters.Types;
}
}
public string GetAttributeDefaultMember ()
{
return indexer_name ?? DefaultIndexerName;
}
public bool IsComImport {
get {
if (OptAttributes == null)
return false;
return OptAttributes.Contains (Module.PredefinedAttributes.ComImport);
}
}
public virtual void RegisterFieldForInitialization (MemberCore field, FieldInitializer expression)
{
if (IsPartialPart)
PartialContainer.RegisterFieldForInitialization (field, expression);
if ((field.ModFlags & Modifiers.STATIC) != 0){
if (initialized_static_fields == null) {
HasStaticFieldInitializer = true;
initialized_static_fields = new List<FieldInitializer> (4);
}
initialized_static_fields.Add (expression);
} else {
if (initialized_fields == null)
initialized_fields = new List<FieldInitializer> (4);
initialized_fields.Add (expression);
}
}
public void ResolveFieldInitializers (BlockContext ec)
{
Debug.Assert (!IsPartialPart);
if (ec.IsStatic) {
if (initialized_static_fields == null)
return;
bool has_complex_initializer = !ec.Module.Compiler.Settings.Optimize;
int i;
ExpressionStatement [] init = new ExpressionStatement [initialized_static_fields.Count];
for (i = 0; i < initialized_static_fields.Count; ++i) {
FieldInitializer fi = initialized_static_fields [i];
ExpressionStatement s = fi.ResolveStatement (ec);
if (s == null) {
s = EmptyExpressionStatement.Instance;
} else if (!fi.IsSideEffectFree) {
has_complex_initializer |= true;
}
init [i] = s;
}
for (i = 0; i < initialized_static_fields.Count; ++i) {
FieldInitializer fi = initialized_static_fields [i];
//
// Need special check to not optimize code like this
// static int a = b = 5;
// static int b = 0;
//
if (!has_complex_initializer && fi.IsDefaultInitializer)
continue;
ec.CurrentBlock.AddScopeStatement (new StatementExpression (init [i]));
}
return;
}
if (initialized_fields == null)
return;
for (int i = 0; i < initialized_fields.Count; ++i) {
FieldInitializer fi = initialized_fields [i];
ExpressionStatement s = fi.ResolveStatement (ec);
if (s == null)
continue;
//
// Field is re-initialized to its default value => removed
//
if (fi.IsDefaultInitializer && ec.Module.Compiler.Settings.Optimize)
continue;
ec.CurrentBlock.AddScopeStatement (new StatementExpression (s));
}
}
public override string DocComment {
get {
return comment;
}
set {
if (value == null)
return;
comment += value;
}
}
public PendingImplementation PendingImplementations {
get { return pending; }
}
internal override void GenerateDocComment (DocumentationBuilder builder)
{
base.GenerateDocComment (builder);
foreach (var member in members)
member.GenerateDocComment (builder);
}
public TypeSpec GetAttributeCoClass ()
{
if (OptAttributes == null)
return null;
Attribute a = OptAttributes.Search (Module.PredefinedAttributes.CoClass);
if (a == null)
return null;
return a.GetCoClassAttributeValue ();
}
public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
{
Attribute a = null;
if (OptAttributes != null) {
a = OptAttributes.Search (pa);
}
if (a == null)
return null;
return a.GetAttributeUsageAttribute ();
}
public virtual CompilationSourceFile GetCompilationSourceFile ()
{
TypeContainer ns = Parent;
while (true) {
var sf = ns as CompilationSourceFile;
if (sf != null)
return sf;
ns = ns.Parent;
}
}
public virtual void AddBasesForPart (List<FullNamedExpression> bases)
{
type_bases = bases;
}
/// <summary>
/// This function computes the Base class and also the
/// list of interfaces that the class or struct @c implements.
///
/// The return value is an array (might be null) of
/// interfaces implemented (as Types).
///
/// The @base_class argument is set to the base object or null
/// if this is `System.Object'.
/// </summary>
protected virtual TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class)
{
base_class = null;
if (type_bases == null)
return null;
int count = type_bases.Count;
TypeSpec[] ifaces = null;
var base_context = new BaseContext (this);
for (int i = 0, j = 0; i < count; i++){
FullNamedExpression fne = type_bases [i];
var fne_resolved = fne.ResolveAsType (base_context);
if (fne_resolved == null)
continue;
if (i == 0 && Kind == MemberKind.Class && !fne_resolved.IsInterface) {
if (fne_resolved.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
Report.Error (1965, Location, "Class `{0}' cannot derive from the dynamic type",
GetSignatureForError ());
continue;
}
base_type = fne_resolved;
base_class = fne;
continue;
}
if (ifaces == null)
ifaces = new TypeSpec [count - i];
if (fne_resolved.IsInterface) {
for (int ii = 0; ii < j; ++ii) {
if (fne_resolved == ifaces [ii]) {
Report.Error (528, Location, "`{0}' is already listed in interface list",
fne_resolved.GetSignatureForError ());
break;
}
}
if (Kind == MemberKind.Interface && !IsAccessibleAs (fne_resolved)) {
Report.Error (61, fne.Location,
"Inconsistent accessibility: base interface `{0}' is less accessible than interface `{1}'",
fne_resolved.GetSignatureForError (), GetSignatureForError ());
}
} else {
Report.SymbolRelatedToPreviousError (fne_resolved);
if (Kind != MemberKind.Class) {
Report.Error (527, fne.Location, "Type `{0}' in interface list is not an interface", fne_resolved.GetSignatureForError ());
} else if (base_class != null)
Report.Error (1721, fne.Location, "`{0}': Classes cannot have multiple base classes (`{1}' and `{2}')",
GetSignatureForError (), base_class.GetSignatureForError (), fne_resolved.GetSignatureForError ());
else {
Report.Error (1722, fne.Location, "`{0}': Base class `{1}' must be specified as first",
GetSignatureForError (), fne_resolved.GetSignatureForError ());
}
}
ifaces [j++] = fne_resolved;
}
return ifaces;
}
//
// Checks that some operators come in pairs:
// == and !=
// > and <
// >= and <=
// true and false
//
// They are matched based on the return type and the argument types
//
void CheckPairedOperators ()
{
bool has_equality_or_inequality = false;
List<Operator.OpType> found_matched = new List<Operator.OpType> ();
for (int i = 0; i < members.Count; ++i) {
var o_a = members[i] as Operator;
if (o_a == null)
continue;
var o_type = o_a.OperatorType;
if (o_type == Operator.OpType.Equality || o_type == Operator.OpType.Inequality)
has_equality_or_inequality = true;
if (found_matched.Contains (o_type))
continue;
var matching_type = o_a.GetMatchingOperator ();
if (matching_type == Operator.OpType.TOP) {
continue;
}
bool pair_found = false;
for (int ii = i + 1; ii < members.Count; ++ii) {
var o_b = members[ii] as Operator;
if (o_b == null || o_b.OperatorType != matching_type)
continue;
if (!TypeSpecComparer.IsEqual (o_a.ReturnType, o_b.ReturnType))
continue;
if (!TypeSpecComparer.Equals (o_a.ParameterTypes, o_b.ParameterTypes))
continue;
found_matched.Add (matching_type);
pair_found = true;
break;
}
if (!pair_found) {
Report.Error (216, o_a.Location,
"The operator `{0}' requires a matching operator `{1}' to also be defined",
o_a.GetSignatureForError (), Operator.GetName (matching_type));
}
}
if (has_equality_or_inequality) {
if (!HasEquals)
Report.Warning (660, 2, Location, "`{0}' defines operator == or operator != but does not override Object.Equals(object o)",
GetSignatureForError ());
if (!HasGetHashCode)
Report.Warning (661, 2, Location, "`{0}' defines operator == or operator != but does not override Object.GetHashCode()",
GetSignatureForError ());
}
}
public override void CreateMetadataName (StringBuilder sb)
{
if (Parent.MemberName != null) {
Parent.CreateMetadataName (sb);
if (sb.Length != 0) {
sb.Append (".");
}
}
sb.Append (MemberName.Basename);
}
bool CreateTypeBuilder ()
{
//
// Sets .size to 1 for structs with no instance fields
//
int type_size = Kind == MemberKind.Struct && first_nonstatic_field == null ? 1 : 0;
var parent_def = Parent as TypeDefinition;
if (parent_def == null) {
var sb = new StringBuilder ();
CreateMetadataName (sb);
TypeBuilder = Module.CreateBuilder (sb.ToString (), TypeAttr, type_size);
} else {
TypeBuilder = parent_def.TypeBuilder.DefineNestedType (Basename, TypeAttr, null, type_size);
}
if (DeclaringAssembly.Importer != null)
DeclaringAssembly.Importer.AddCompiledType (TypeBuilder, spec);
spec.SetMetaInfo (TypeBuilder);
spec.MemberCache = new MemberCache (this);
TypeParameters parentAllTypeParameters = null;
if (parent_def != null) {
spec.DeclaringType = Parent.CurrentType;
parent_def.MemberCache.AddMember (spec);
parentAllTypeParameters = parent_def.all_type_parameters;
}
if (MemberName.TypeParameters != null || parentAllTypeParameters != null) {
var tparam_names = CreateTypeParameters (parentAllTypeParameters);
all_tp_builders = TypeBuilder.DefineGenericParameters (tparam_names);
if (CurrentTypeParameters != null)
CurrentTypeParameters.Define (all_tp_builders, spec, CurrentTypeParametersStartIndex, this);
}
return true;
}
string[] CreateTypeParameters (TypeParameters parentAllTypeParameters)
{
string[] names;
int parent_offset = 0;
if (parentAllTypeParameters != null) {
if (CurrentTypeParameters == null) {
all_type_parameters = parentAllTypeParameters;
return parentAllTypeParameters.GetAllNames ();
}
names = new string[parentAllTypeParameters.Count + CurrentTypeParameters.Count];
all_type_parameters = new TypeParameters (names.Length);
all_type_parameters.Add (parentAllTypeParameters);
parent_offset = all_type_parameters.Count;
for (int i = 0; i < parent_offset; ++i)
names[i] = all_type_parameters[i].MemberName.Name;
} else {
names = new string[CurrentTypeParameters.Count];
}
for (int i = 0; i < CurrentTypeParameters.Count; ++i) {
if (all_type_parameters != null)
all_type_parameters.Add (MemberName.TypeParameters[i]);
var name = CurrentTypeParameters[i].MemberName.Name;
names[parent_offset + i] = name;
for (int ii = 0; ii < parent_offset + i; ++ii) {
if (names[ii] != name)
continue;
var tp = CurrentTypeParameters[i];
var conflict = all_type_parameters[ii];
tp.WarningParentNameConflict (conflict);
}
}
if (all_type_parameters == null)
all_type_parameters = CurrentTypeParameters;
return names;
}
//
// Creates a proxy base method call inside this container for hoisted base member calls
//
public MethodSpec CreateHoistedBaseCallProxy (ResolveContext rc, MethodSpec method)
{
Method proxy_method;
//
// One proxy per base method is enough
//
if (hoisted_base_call_proxies == null) {
hoisted_base_call_proxies = new Dictionary<MethodSpec, Method> ();
proxy_method = null;
} else {
hoisted_base_call_proxies.TryGetValue (method, out proxy_method);
}
if (proxy_method == null) {
string name = CompilerGeneratedClass.MakeName (method.Name, null, "BaseCallProxy", hoisted_base_call_proxies.Count);
var base_parameters = new Parameter[method.Parameters.Count];
for (int i = 0; i < base_parameters.Length; ++i) {
var base_param = method.Parameters.FixedParameters[i];
base_parameters[i] = new Parameter (new TypeExpression (method.Parameters.Types[i], Location),
base_param.Name, base_param.ModFlags, null, Location);
base_parameters[i].Resolve (this, i);
}
var cloned_params = ParametersCompiled.CreateFullyResolved (base_parameters, method.Parameters.Types);
if (method.Parameters.HasArglist) {
cloned_params.FixedParameters[0] = new Parameter (null, "__arglist", Parameter.Modifier.NONE, null, Location);
cloned_params.Types[0] = Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
}
MemberName member_name;
TypeArguments targs = null;
if (method.IsGeneric) {
//
// Copy all base generic method type parameters info
//
var hoisted_tparams = method.GenericDefinition.TypeParameters;
var tparams = new TypeParameters ();
targs = new TypeArguments ();
targs.Arguments = new TypeSpec[hoisted_tparams.Length];
for (int i = 0; i < hoisted_tparams.Length; ++i) {
var tp = hoisted_tparams[i];
tparams.Add (new TypeParameter (tp, null, new MemberName (tp.Name, Location), null));
targs.Add (new SimpleName (tp.Name, Location));
targs.Arguments[i] = tp;
}
member_name = new MemberName (name, tparams, Location);
} else {
member_name = new MemberName (name);
}
// Compiler generated proxy
proxy_method = new Method (this, new TypeExpression (method.ReturnType, Location),
Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED | Modifiers.DEBUGGER_HIDDEN,
member_name, cloned_params, null);
var block = new ToplevelBlock (Compiler, proxy_method.ParameterInfo, Location) {
IsCompilerGenerated = true
};
var mg = MethodGroupExpr.CreatePredefined (method, method.DeclaringType, Location);
mg.InstanceExpression = new BaseThis (method.DeclaringType, Location);
if (targs != null)
mg.SetTypeArguments (rc, targs);
// Get all the method parameters and pass them as arguments
var real_base_call = new Invocation (mg, block.GetAllParametersArguments ());
Statement statement;
if (method.ReturnType.Kind == MemberKind.Void)
statement = new StatementExpression (real_base_call);
else
statement = new Return (real_base_call, Location);
block.AddStatement (statement);
proxy_method.Block = block;
members.Add (proxy_method);
proxy_method.Define ();
hoisted_base_call_proxies.Add (method, proxy_method);
}
return proxy_method.Spec;
}
protected bool DefineBaseTypes ()
{
iface_exprs = ResolveBaseTypes (out base_type_expr);
bool set_base_type;
if (IsPartialPart) {
set_base_type = false;
if (base_type_expr != null) {
if (PartialContainer.base_type_expr != null && PartialContainer.base_type != base_type) {
Report.SymbolRelatedToPreviousError (base_type_expr.Location, "");
Report.Error (263, Location,
"Partial declarations of `{0}' must not specify different base classes",
GetSignatureForError ());
} else {
PartialContainer.base_type_expr = base_type_expr;
PartialContainer.base_type = base_type;
set_base_type = true;
}
}
if (iface_exprs != null) {
if (PartialContainer.iface_exprs == null)
PartialContainer.iface_exprs = iface_exprs;
else {
var ifaces = new List<TypeSpec> (PartialContainer.iface_exprs);
foreach (var iface_partial in iface_exprs) {
if (ifaces.Contains (iface_partial))
continue;
ifaces.Add (iface_partial);
}
PartialContainer.iface_exprs = ifaces.ToArray ();
}
}
PartialContainer.members.AddRange (members);
if (containers != null) {
if (PartialContainer.containers == null)
PartialContainer.containers = new List<TypeContainer> ();
PartialContainer.containers.AddRange (containers);
}
members_defined = members_defined_ok = true;
caching_flags |= Flags.CloseTypeCreated;
} else {
set_base_type = true;
}
var cycle = CheckRecursiveDefinition (this);
if (cycle != null) {
Report.SymbolRelatedToPreviousError (cycle);
if (this is Interface) {
Report.Error (529, Location,
"Inherited interface `{0}' causes a cycle in the interface hierarchy of `{1}'",
GetSignatureForError (), cycle.GetSignatureForError ());
iface_exprs = null;
} else {
Report.Error (146, Location,
"Circular base class dependency involving `{0}' and `{1}'",
GetSignatureForError (), cycle.GetSignatureForError ());
base_type = null;
}
}
if (iface_exprs != null) {
foreach (var iface_type in iface_exprs) {
// Prevents a crash, the interface might not have been resolved: 442144
if (iface_type == null)
continue;
if (!spec.AddInterfaceDefined (iface_type))
continue;
TypeBuilder.AddInterfaceImplementation (iface_type.GetMetaInfo ());
// Ensure the base is always setup
var compiled_iface = iface_type.MemberDefinition as Interface;
if (compiled_iface != null) {
// TODO: Need DefineBaseType only
compiled_iface.DefineContainer ();
}
if (iface_type.Interfaces != null) {
var base_ifaces = new List<TypeSpec> (iface_type.Interfaces);
for (int i = 0; i < base_ifaces.Count; ++i) {
var ii_iface_type = base_ifaces[i];
if (spec.AddInterfaceDefined (ii_iface_type)) {
TypeBuilder.AddInterfaceImplementation (ii_iface_type.GetMetaInfo ());
if (ii_iface_type.Interfaces != null)
base_ifaces.AddRange (ii_iface_type.Interfaces);
}
}
}
}
}
if (Kind == MemberKind.Interface) {
spec.BaseType = Compiler.BuiltinTypes.Object;
return true;
}
if (set_base_type) {
if (base_type != null) {
spec.BaseType = base_type;
// Set base type after type creation
TypeBuilder.SetParent (base_type.GetMetaInfo ());
} else {
TypeBuilder.SetParent (null);
}
}
return true;
}
public override void PrepareEmit ()
{
foreach (var member in members) {
var pm = member as IParametersMember;
if (pm != null) {
var p = pm.Parameters;
if (p.IsEmpty)
continue;
((ParametersCompiled) p).ResolveDefaultValues (member);
}
var c = member as Const;
if (c != null)
c.DefineValue ();
}
base.PrepareEmit ();
}
//
// Defines the type in the appropriate ModuleBuilder or TypeBuilder.
//
public override bool CreateContainer ()
{
if (TypeBuilder != null)
return !error;
if (error)
return false;
if (IsPartialPart) {
spec = PartialContainer.spec;
TypeBuilder = PartialContainer.TypeBuilder;
all_tp_builders = PartialContainer.all_tp_builders;
all_type_parameters = PartialContainer.all_type_parameters;
} else {
if (!CreateTypeBuilder ()) {
error = true;
return false;
}
}
return base.CreateContainer ();
}
protected override void DoDefineContainer ()
{
DefineBaseTypes ();
DoResolveTypeParameters ();
}
//
// Replaces normal spec with predefined one when compiling corlib
// and this type container defines predefined type
//
public void SetPredefinedSpec (BuiltinTypeSpec spec)
{
// When compiling build-in types we start with two
// version of same type. One is of BuiltinTypeSpec and
// second one is ordinary TypeSpec. The unification
// happens at later stage when we know which type
// really matches the builtin type signature. However
// that means TypeSpec create during CreateType of this
// type has to be replaced with builtin one
//
spec.SetMetaInfo (TypeBuilder);
spec.MemberCache = this.spec.MemberCache;
spec.DeclaringType = this.spec.DeclaringType;
this.spec = spec;
current_type = null;
}
void UpdateTypeParameterConstraints (TypeDefinition part)
{
for (int i = 0; i < CurrentTypeParameters.Count; i++) {
if (CurrentTypeParameters[i].AddPartialConstraints (part, part.MemberName.TypeParameters[i]))
continue;
Report.SymbolRelatedToPreviousError (Location, "");
Report.Error (265, part.Location,
"Partial declarations of `{0}' have inconsistent constraints for type parameter `{1}'",
GetSignatureForError (), CurrentTypeParameters[i].GetSignatureForError ());
}
}
public override void RemoveContainer (TypeContainer cont)
{
base.RemoveContainer (cont);
Members.Remove (cont);
Cache.Remove (cont.Basename);
}
protected virtual bool DoResolveTypeParameters ()
{
var tparams = CurrentTypeParameters;
if (tparams == null)
return true;
var base_context = new BaseContext (this);
for (int i = 0; i < tparams.Count; ++i) {
var tp = tparams[i];
if (!tp.ResolveConstraints (base_context)) {
error = true;
return false;
}
}
if (IsPartialPart) {
PartialContainer.UpdateTypeParameterConstraints (this);
}
return true;
}
TypeSpec CheckRecursiveDefinition (TypeDefinition tc)
{
if (InTransit != null)
return spec;
InTransit = tc;
if (base_type != null) {
var ptc = base_type.MemberDefinition as TypeDefinition;
if (ptc != null && ptc.CheckRecursiveDefinition (this) != null)
return base_type;
}
if (iface_exprs != null) {
foreach (var iface in iface_exprs) {
// the interface might not have been resolved, prevents a crash, see #442144
if (iface == null)
continue;
var ptc = iface.MemberDefinition as Interface;
if (ptc != null && ptc.CheckRecursiveDefinition (this) != null)
return iface;
}
}
if (!IsTopLevel && Parent.PartialContainer.CheckRecursiveDefinition (this) != null)
return spec;
InTransit = null;
return null;
}
/// <summary>
/// Populates our TypeBuilder with fields and methods
/// </summary>
public sealed override bool Define ()
{
if (members_defined)
return members_defined_ok;
members_defined_ok = DoDefineMembers ();
members_defined = true;
base.Define ();
return members_defined_ok;
}
protected virtual bool DoDefineMembers ()
{
Debug.Assert (!IsPartialPart);
if (iface_exprs != null) {
foreach (var iface_type in iface_exprs) {
if (iface_type == null)
continue;
// Ensure the base is always setup
var compiled_iface = iface_type.MemberDefinition as Interface;
if (compiled_iface != null)
compiled_iface.Define ();
if (Kind == MemberKind.Interface)
MemberCache.AddInterface (iface_type);
ObsoleteAttribute oa = iface_type.GetAttributeObsolete ();
if (oa != null && !IsObsolete)
AttributeTester.Report_ObsoleteMessage (oa, iface_type.GetSignatureForError (), Location, Report);
if (iface_type.Arity > 0) {
// TODO: passing `this' is wrong, should be base type iface instead
TypeManager.CheckTypeVariance (iface_type, Variance.Covariant, this);
if (((InflatedTypeSpec) iface_type).HasDynamicArgument () && !IsCompilerGenerated) {
Report.Error (1966, Location,
"`{0}': cannot implement a dynamic interface `{1}'",
GetSignatureForError (), iface_type.GetSignatureForError ());
return false;
}
}
if (iface_type.IsGenericOrParentIsGeneric) {
if (spec.Interfaces != null) {
foreach (var prev_iface in iface_exprs) {
if (prev_iface == iface_type)
break;
if (!TypeSpecComparer.Unify.IsEqual (iface_type, prev_iface))
continue;
Report.Error (695, Location,
"`{0}' cannot implement both `{1}' and `{2}' because they may unify for some type parameter substitutions",
GetSignatureForError (), prev_iface.GetSignatureForError (), iface_type.GetSignatureForError ());
}
}
}
}
}
if (base_type != null) {
//
// Run checks skipped during DefineType (e.g FullNamedExpression::ResolveAsType)
//
if (base_type_expr != null) {
ObsoleteAttribute obsolete_attr = base_type.GetAttributeObsolete ();
if (obsolete_attr != null && !IsObsolete)
AttributeTester.Report_ObsoleteMessage (obsolete_attr, base_type.GetSignatureForError (), base_type_expr.Location, Report);
if (IsGenericOrParentIsGeneric && base_type.IsAttribute) {
Report.Error (698, base_type_expr.Location,
"A generic type cannot derive from `{0}' because it is an attribute class",
base_type.GetSignatureForError ());
}
}
if (base_type.Interfaces != null) {
foreach (var iface in base_type.Interfaces)
spec.AddInterface (iface);
}
var baseContainer = base_type.MemberDefinition as ClassOrStruct;
if (baseContainer != null) {
baseContainer.Define ();
//
// It can trigger define of this type (for generic types only)
//
if (HasMembersDefined)
return true;
}
}
if (Kind == MemberKind.Struct || Kind == MemberKind.Class) {
pending = PendingImplementation.GetPendingImplementations (this);
}
var count = members.Count;
for (int i = 0; i < count; ++i) {
var mc = members[i] as InterfaceMemberBase;
if (mc == null || !mc.IsExplicitImpl)
continue;
try {
mc.Define ();
} catch (Exception e) {
throw new InternalErrorException (mc, e);
}
}
for (int i = 0; i < count; ++i) {
var mc = members[i] as InterfaceMemberBase;
if (mc != null && mc.IsExplicitImpl)
continue;
if (members[i] is TypeContainer)
continue;
try {
members[i].Define ();
} catch (Exception e) {
throw new InternalErrorException (members[i], e);
}
}
if (HasOperators) {
CheckPairedOperators ();
}
if (requires_delayed_unmanagedtype_check) {
requires_delayed_unmanagedtype_check = false;
foreach (var member in members) {
var f = member as Field;
if (f != null && f.MemberType != null && f.MemberType.IsPointer)
TypeManager.VerifyUnmanaged (Module, f.MemberType, f.Location);
}
}
ComputeIndexerName();
if (HasEquals && !HasGetHashCode) {
Report.Warning (659, 3, Location,
"`{0}' overrides Object.Equals(object) but does not override Object.GetHashCode()", GetSignatureForError ());
}
if (Kind == MemberKind.Interface && iface_exprs != null) {
MemberCache.RemoveHiddenMembers (spec);
}
return true;
}
void ComputeIndexerName ()
{
var indexers = MemberCache.FindMembers (spec, MemberCache.IndexerNameAlias, true);
if (indexers == null)
return;
string class_indexer_name = null;
has_normal_indexers = true;
//
// Check normal indexers for consistent name, explicit interface implementation
// indexers are ignored
//
foreach (var indexer in indexers) {
if (class_indexer_name == null) {
indexer_name = class_indexer_name = indexer.Name;
continue;
}
if (indexer.Name != class_indexer_name)
Report.Error (668, ((Indexer)indexer.MemberDefinition).Location,
"Two indexers have different names; the IndexerName attribute must be used with the same name on every indexer within a type");
}
}
void EmitIndexerName ()
{
if (!has_normal_indexers)
return;
var ctor = Module.PredefinedMembers.DefaultMemberAttributeCtor.Get ();
if (ctor == null)
return;
var encoder = new AttributeEncoder ();
encoder.Encode (GetAttributeDefaultMember ());
encoder.EncodeEmptyNamedArguments ();
TypeBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), encoder.ToArray ());
}
public override void VerifyMembers ()
{
//
// Check for internal or private fields that were never assigned
//
if (!IsCompilerGenerated && Compiler.Settings.WarningLevel >= 3 && this == PartialContainer) {
bool is_type_exposed = Kind == MemberKind.Struct || IsExposedFromAssembly ();
foreach (var member in members) {
if (member is Event) {
//
// An event can be assigned from same class only, so we can report
// this warning for all accessibility modes
//
if (!member.IsUsed)
Report.Warning (67, 3, member.Location, "The event `{0}' is never used", member.GetSignatureForError ());
continue;
}
if ((member.ModFlags & Modifiers.AccessibilityMask) != Modifiers.PRIVATE) {
if (is_type_exposed)
continue;
member.SetIsUsed ();
}
var f = member as Field;
if (f == null)
continue;
if (!member.IsUsed) {
if ((member.caching_flags & Flags.IsAssigned) == 0) {
Report.Warning (169, 3, member.Location, "The private field `{0}' is never used", member.GetSignatureForError ());
} else {
Report.Warning (414, 3, member.Location, "The private field `{0}' is assigned but its value is never used",
member.GetSignatureForError ());
}
continue;
}
if ((f.caching_flags & Flags.IsAssigned) != 0)
continue;
//
// Only report 649 on level 4
//
if (Compiler.Settings.WarningLevel < 4)
continue;
//
// Don't be pendatic over serializable attributes
//
if (f.OptAttributes != null || PartialContainer.HasStructLayout)
continue;
Constant c = New.Constantify (f.MemberType, f.Location);
string value;
if (c != null) {
value = c.GetValueAsLiteral ();
} else if (TypeSpec.IsReferenceType (f.MemberType)) {
value = "null";
} else {
// Ignore this warning for struct value fields (they are always initialized)
if (f.MemberType.IsStruct)
continue;
value = null;
}
if (value != null)
value = " `" + value + "'";
Report.Warning (649, 4, f.Location, "Field `{0}' is never assigned to, and will always have its default value{1}",
f.GetSignatureForError (), value);
}
}
base.VerifyMembers ();
}
public override void Emit ()
{
if (OptAttributes != null)
OptAttributes.Emit ();
if (!IsTopLevel) {
MemberSpec candidate;
bool overrides = false;
var conflict_symbol = MemberCache.FindBaseMember (this, out candidate, ref overrides);
if (conflict_symbol == null && candidate == null) {
if ((ModFlags & Modifiers.NEW) != 0)
Report.Warning (109, 4, Location, "The member `{0}' does not hide an inherited member. The new keyword is not required",
GetSignatureForError ());
} else {
if ((ModFlags & Modifiers.NEW) == 0) {
if (candidate == null)
candidate = conflict_symbol;
Report.SymbolRelatedToPreviousError (candidate);
Report.Warning (108, 2, Location, "`{0}' hides inherited member `{1}'. Use the new keyword if hiding was intended",
GetSignatureForError (), candidate.GetSignatureForError ());
}
}
}
// Run constraints check on all possible generic types
if ((ModFlags & Modifiers.COMPILER_GENERATED) == 0) {
if (base_type != null && base_type_expr != null) {
ConstraintChecker.Check (this, base_type, base_type_expr.Location);
}
if (iface_exprs != null) {
foreach (var iface_type in iface_exprs) {
if (iface_type == null)
continue;
ConstraintChecker.Check (this, iface_type, Location); // TODO: Location is wrong
}
}
}
if (all_tp_builders != null) {
int current_starts_index = CurrentTypeParametersStartIndex;
for (int i = 0; i < all_tp_builders.Length; i++) {
if (i < current_starts_index) {
all_type_parameters[i].EmitConstraints (all_tp_builders [i]);
} else {
var tp = CurrentTypeParameters [i - current_starts_index];
tp.CheckGenericConstraints (!IsObsolete);
tp.Emit ();
}
}
}
if ((ModFlags & Modifiers.COMPILER_GENERATED) != 0 && !Parent.IsCompilerGenerated)
Module.PredefinedAttributes.CompilerGenerated.EmitAttribute (TypeBuilder);
#if STATIC
if ((TypeBuilder.Attributes & TypeAttributes.StringFormatMask) == 0 && Module.HasDefaultCharSet)
TypeBuilder.__SetAttributes (TypeBuilder.Attributes | Module.DefaultCharSetType);
#endif
base.Emit ();
for (int i = 0; i < members.Count; i++)
members[i].Emit ();
EmitIndexerName ();
CheckAttributeClsCompliance ();
if (pending != null)
pending.VerifyPendingMethods ();
}
void CheckAttributeClsCompliance ()
{
if (!spec.IsAttribute || !IsExposedFromAssembly () || !Compiler.Settings.VerifyClsCompliance || !IsClsComplianceRequired ())
return;
foreach (var m in members) {
var c = m as Constructor;
if (c == null)
continue;
if (c.HasCompliantArgs)
return;
}
Report.Warning (3015, 1, Location, "`{0}' has no accessible constructors which use only CLS-compliant types", GetSignatureForError ());
}
public sealed override void EmitContainer ()
{
if ((caching_flags & Flags.CloseTypeCreated) != 0)
return;
Emit ();
}
public override void CloseContainer ()
{
if ((caching_flags & Flags.CloseTypeCreated) != 0)
return;
// Close base type container first to avoid TypeLoadException
if (spec.BaseType != null) {
var btype = spec.BaseType.MemberDefinition as TypeContainer;
if (btype != null) {
btype.CloseContainer ();
if ((caching_flags & Flags.CloseTypeCreated) != 0)
return;
}
}
try {
caching_flags |= Flags.CloseTypeCreated;
TypeBuilder.CreateType ();
} catch (TypeLoadException) {
//
// This is fine, the code still created the type
//
} catch (Exception e) {
throw new InternalErrorException (this, e);
}
base.CloseContainer ();
containers = null;
initialized_fields = null;
initialized_static_fields = null;
type_bases = null;
OptAttributes = null;
}
//
// Performs the validation on a Method's modifiers (properties have
// the same properties).
//
// TODO: Why is it not done at parse stage, move to Modifiers::Check
//
public bool MethodModifiersValid (MemberCore mc)
{
const Modifiers vao = (Modifiers.VIRTUAL | Modifiers.ABSTRACT | Modifiers.OVERRIDE);
const Modifiers nv = (Modifiers.NEW | Modifiers.VIRTUAL);
bool ok = true;
var flags = mc.ModFlags;
//
// At most one of static, virtual or override
//
if ((flags & Modifiers.STATIC) != 0){
if ((flags & vao) != 0){
Report.Error (112, mc.Location, "A static member `{0}' cannot be marked as override, virtual or abstract",
mc.GetSignatureForError ());
ok = false;
}
}
if ((flags & Modifiers.OVERRIDE) != 0 && (flags & nv) != 0){
Report.Error (113, mc.Location, "A member `{0}' marked as override cannot be marked as new or virtual",
mc.GetSignatureForError ());
ok = false;
}
//
// If the declaration includes the abstract modifier, then the
// declaration does not include static, virtual or extern
//
if ((flags & Modifiers.ABSTRACT) != 0){
if ((flags & Modifiers.EXTERN) != 0){
Report.Error (
180, mc.Location, "`{0}' cannot be both extern and abstract", mc.GetSignatureForError ());
ok = false;
}
if ((flags & Modifiers.SEALED) != 0) {
Report.Error (502, mc.Location, "`{0}' cannot be both abstract and sealed", mc.GetSignatureForError ());
ok = false;
}
if ((flags & Modifiers.VIRTUAL) != 0){
Report.Error (503, mc.Location, "The abstract method `{0}' cannot be marked virtual", mc.GetSignatureForError ());
ok = false;
}
if ((ModFlags & Modifiers.ABSTRACT) == 0){
Report.SymbolRelatedToPreviousError (this);
Report.Error (513, mc.Location, "`{0}' is abstract but it is declared in the non-abstract class `{1}'",
mc.GetSignatureForError (), GetSignatureForError ());
ok = false;
}
}
if ((flags & Modifiers.PRIVATE) != 0){
if ((flags & vao) != 0){
Report.Error (621, mc.Location, "`{0}': virtual or abstract members cannot be private", mc.GetSignatureForError ());
ok = false;
}
}
if ((flags & Modifiers.SEALED) != 0){
if ((flags & Modifiers.OVERRIDE) == 0){
Report.Error (238, mc.Location, "`{0}' cannot be sealed because it is not an override", mc.GetSignatureForError ());
ok = false;
}
}
return ok;
}
protected override bool VerifyClsCompliance ()
{
if (!base.VerifyClsCompliance ())
return false;
// Check all container names for user classes
if (Kind != MemberKind.Delegate)
MemberCache.VerifyClsCompliance (Definition, Report);
if (BaseType != null && !BaseType.IsCLSCompliant ()) {
Report.Warning (3009, 1, Location, "`{0}': base type `{1}' is not CLS-compliant",
GetSignatureForError (), BaseType.GetSignatureForError ());
}
return true;
}
/// <summary>
/// Performs checks for an explicit interface implementation. First it
/// checks whether the `interface_type' is a base inteface implementation.
/// Then it checks whether `name' exists in the interface type.
/// </summary>
public bool VerifyImplements (InterfaceMemberBase mb)
{
var ifaces = spec.Interfaces;
if (ifaces != null) {
foreach (TypeSpec t in ifaces){
if (t == mb.InterfaceType)
return true;
}
}
Report.SymbolRelatedToPreviousError (mb.InterfaceType);
Report.Error (540, mb.Location, "`{0}': containing type does not implement interface `{1}'",
mb.GetSignatureForError (), TypeManager.CSharpName (mb.InterfaceType));
return false;
}
//
// Used for visiblity checks to tests whether this definition shares
// base type baseType, it does member-definition search
//
public bool IsBaseTypeDefinition (TypeSpec baseType)
{
// RootContext check
if (TypeBuilder == null)
return false;
var type = spec;
do {
if (type.MemberDefinition == baseType.MemberDefinition)
return true;
type = type.BaseType;
} while (type != null);
return false;
}
public override bool IsClsComplianceRequired ()
{
if (IsPartialPart)
return PartialContainer.IsClsComplianceRequired ();
return base.IsClsComplianceRequired ();
}
bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
{
return Module.DeclaringAssembly == assembly;
}
public virtual bool IsUnmanagedType ()
{
return false;
}
public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
{
throw new NotSupportedException ("Not supported for compiled definition " + GetSignatureForError ());
}
//
// Public function used to locate types.
//
// Set 'ignore_cs0104' to true if you want to ignore cs0104 errors.
//
// Returns: Type or null if they type can not be found.
//
public override FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
{
FullNamedExpression e;
if (arity == 0 && Cache.TryGetValue (name, out e) && mode != LookupMode.IgnoreAccessibility)
return e;
e = null;
if (arity == 0) {
var tp = CurrentTypeParameters;
if (tp != null) {
TypeParameter tparam = tp.Find (name);
if (tparam != null)
e = new TypeParameterExpr (tparam, Location.Null);
}
}
if (e == null) {
TypeSpec t = LookupNestedTypeInHierarchy (name, arity);
if (t != null && (t.IsAccessible (this) || mode == LookupMode.IgnoreAccessibility))
e = new TypeExpression (t, Location.Null);
else {
e = Parent.LookupNamespaceOrType (name, arity, mode, loc);
}
}
// TODO MemberCache: How to cache arity stuff ?
if (arity == 0 && mode == LookupMode.Normal)
Cache[name] = e;
return e;
}
TypeSpec LookupNestedTypeInHierarchy (string name, int arity)
{
// Has any nested type
// Does not work, because base type can have
//if (PartialContainer.Types == null)
// return null;
var container = PartialContainer.CurrentType;
return MemberCache.FindNestedType (container, name, arity);
}
public void Mark_HasEquals ()
{
cached_method |= CachedMethods.Equals;
}
public void Mark_HasGetHashCode ()
{
cached_method |= CachedMethods.GetHashCode;
}
/// <summary>
/// Method container contains Equals method
/// </summary>
public bool HasEquals {
get {
return (cached_method & CachedMethods.Equals) != 0;
}
}
/// <summary>
/// Method container contains GetHashCode method
/// </summary>
public bool HasGetHashCode {
get {
return (cached_method & CachedMethods.GetHashCode) != 0;
}
}
public bool HasStaticFieldInitializer {
get {
return (cached_method & CachedMethods.HasStaticFieldInitializer) != 0;
}
set {
if (value)
cached_method |= CachedMethods.HasStaticFieldInitializer;
else
cached_method &= ~CachedMethods.HasStaticFieldInitializer;
}
}
public override string DocCommentHeader {
get { return "T:"; }
}
}
public abstract class ClassOrStruct : TypeDefinition
{
SecurityType declarative_security;
public ClassOrStruct (TypeContainer parent, MemberName name, Attributes attrs, MemberKind kind)
: base (parent, name, attrs, kind)
{
}
protected override TypeAttributes TypeAttr {
get {
return has_static_constructor ? base.TypeAttr : base.TypeAttr | TypeAttributes.BeforeFieldInit;
}
}
public override void AddNameToContainer (MemberCore symbol, string name)
{
if (!(symbol is Constructor) && symbol.MemberName.Name == MemberName.Name) {
if (symbol is TypeParameter) {
Report.Error (694, symbol.Location,
"Type parameter `{0}' has same name as containing type, or method",
symbol.GetSignatureForError ());
return;
}
InterfaceMemberBase imb = symbol as InterfaceMemberBase;
if (imb == null || !imb.IsExplicitImpl) {
Report.SymbolRelatedToPreviousError (this);
Report.Error (542, symbol.Location, "`{0}': member names cannot be the same as their enclosing type",
symbol.GetSignatureForError ());
return;
}
}
base.AddNameToContainer (symbol, name);
}
public override void VerifyMembers ()
{
base.VerifyMembers ();
if (containers != null) {
foreach (var t in containers)
t.VerifyMembers ();
}
}
public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
{
if (a.IsValidSecurityAttribute ()) {
a.ExtractSecurityPermissionSet (ctor, ref declarative_security);
return;
}
if (a.Type == pa.StructLayout) {
PartialContainer.HasStructLayout = true;
if (a.IsExplicitLayoutKind ())
PartialContainer.HasExplicitLayout = true;
}
if (a.Type == pa.Dynamic) {
a.Error_MisusedDynamicAttribute ();
return;
}
base.ApplyAttributeBuilder (a, ctor, cdata, pa);
}
/// <summary>
/// Defines the default constructors
/// </summary>
protected Constructor DefineDefaultConstructor (bool is_static)
{
// The default instance constructor is public
// If the class is abstract, the default constructor is protected
// The default static constructor is private
Modifiers mods;
if (is_static) {
mods = Modifiers.STATIC | Modifiers.PRIVATE;
} else {
mods = ((ModFlags & Modifiers.ABSTRACT) != 0) ? Modifiers.PROTECTED : Modifiers.PUBLIC;
}
var c = new Constructor (this, MemberName.Name, mods, null, ParametersCompiled.EmptyReadOnlyParameters, Location);
c.Initializer = new GeneratedBaseInitializer (Location);
AddConstructor (c, true);
c.Block = new ToplevelBlock (Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location) {
IsCompilerGenerated = true
};
return c;
}
protected override bool DoDefineMembers ()
{
CheckProtectedModifier ();
base.DoDefineMembers ();
return true;
}
public override void Emit ()
{
if (!has_static_constructor && HasStaticFieldInitializer) {
var c = DefineDefaultConstructor (true);
c.Define ();
}
base.Emit ();
if (declarative_security != null) {
foreach (var de in declarative_security) {
#if STATIC
TypeBuilder.__AddDeclarativeSecurity (de);
#else
TypeBuilder.AddDeclarativeSecurity (de.Key, de.Value);
#endif
}
}
}
}
// TODO: should be sealed
public class Class : ClassOrStruct {
const Modifiers AllowedModifiers =
Modifiers.NEW |
Modifiers.PUBLIC |
Modifiers.PROTECTED |
Modifiers.INTERNAL |
Modifiers.PRIVATE |
Modifiers.ABSTRACT |
Modifiers.SEALED |
Modifiers.STATIC |
Modifiers.UNSAFE;
public const TypeAttributes StaticClassAttribute = TypeAttributes.Abstract | TypeAttributes.Sealed;
public Class (TypeContainer parent, MemberName name, Modifiers mod, Attributes attrs)
: base (parent, name, attrs, MemberKind.Class)
{
var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
this.ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod, accmods, Location, Report);
spec = new TypeSpec (Kind, null, this, null, ModFlags);
}
public override void Accept (StructuralVisitor visitor)
{
visitor.Visit (this);
}
public override void AddBasesForPart (List<FullNamedExpression> bases)
{
var pmn = MemberName;
if (pmn.Name == "Object" && !pmn.IsGeneric && Parent.MemberName.Name == "System" && Parent.MemberName.Left == null)
Report.Error (537, Location,
"The class System.Object cannot have a base class or implement an interface.");
base.AddBasesForPart (bases);
}
public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
{
if (a.Type == pa.AttributeUsage) {
if (!BaseType.IsAttribute && spec.BuiltinType != BuiltinTypeSpec.Type.Attribute) {
Report.Error (641, a.Location, "Attribute `{0}' is only valid on classes derived from System.Attribute", a.GetSignatureForError ());
}
}
if (a.Type == pa.Conditional && !BaseType.IsAttribute) {
Report.Error (1689, a.Location, "Attribute `System.Diagnostics.ConditionalAttribute' is only valid on methods or attribute classes");
return;
}
if (a.Type == pa.ComImport && !attributes.Contains (pa.Guid)) {
a.Error_MissingGuidAttribute ();
return;
}
if (a.Type == pa.Extension) {
a.Error_MisusedExtensionAttribute ();
return;
}
if (a.Type.IsConditionallyExcluded (this, Location))
return;
base.ApplyAttributeBuilder (a, ctor, cdata, pa);
}
public override AttributeTargets AttributeTargets {
get {
return AttributeTargets.Class;
}
}
protected override bool DoDefineMembers ()
{
if ((ModFlags & Modifiers.ABSTRACT) == Modifiers.ABSTRACT && (ModFlags & (Modifiers.SEALED | Modifiers.STATIC)) != 0) {
Report.Error (418, Location, "`{0}': an abstract class cannot be sealed or static", GetSignatureForError ());
}
if ((ModFlags & (Modifiers.SEALED | Modifiers.STATIC)) == (Modifiers.SEALED | Modifiers.STATIC)) {
Report.Error (441, Location, "`{0}': a class cannot be both static and sealed", GetSignatureForError ());
}
if (IsStatic) {
foreach (var m in Members) {
if (m is Operator) {
Report.Error (715, m.Location, "`{0}': Static classes cannot contain user-defined operators", m.GetSignatureForError ());
continue;
}
if (m is Destructor) {
Report.Error (711, m.Location, "`{0}': Static classes cannot contain destructor", GetSignatureForError ());
continue;
}
if (m is Indexer) {
Report.Error (720, m.Location, "`{0}': cannot declare indexers in a static class", m.GetSignatureForError ());
continue;
}
if ((m.ModFlags & Modifiers.STATIC) != 0 || m is TypeContainer)
continue;
if (m is Constructor) {
Report.Error (710, m.Location, "`{0}': Static classes cannot have instance constructors", GetSignatureForError ());
continue;
}
Report.Error (708, m.Location, "`{0}': cannot declare instance members in a static class", m.GetSignatureForError ());
}
} else {
if (!PartialContainer.HasInstanceConstructor)
DefineDefaultConstructor (false);
}
return base.DoDefineMembers ();
}
public override void Emit ()
{
base.Emit ();
if ((ModFlags & Modifiers.METHOD_EXTENSION) != 0)
Module.PredefinedAttributes.Extension.EmitAttribute (TypeBuilder);
if (base_type != null && base_type.HasDynamicElement) {
Module.PredefinedAttributes.Dynamic.EmitAttribute (TypeBuilder, base_type, Location);
}
}
protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class)
{
var ifaces = base.ResolveBaseTypes (out base_class);
if (base_class == null) {
if (spec.BuiltinType != BuiltinTypeSpec.Type.Object)
base_type = Compiler.BuiltinTypes.Object;
} else {
if (base_type.IsGenericParameter){
Report.Error (689, base_class.Location, "`{0}': Cannot derive from type parameter `{1}'",
GetSignatureForError (), base_type.GetSignatureForError ());
} else if (base_type.IsStatic) {
Report.SymbolRelatedToPreviousError (base_type);
Report.Error (709, Location, "`{0}': Cannot derive from static class `{1}'",
GetSignatureForError (), base_type.GetSignatureForError ());
} else if (base_type.IsSealed) {
Report.SymbolRelatedToPreviousError (base_type);
Report.Error (509, Location, "`{0}': cannot derive from sealed type `{1}'",
GetSignatureForError (), base_type.GetSignatureForError ());
} else if (PartialContainer.IsStatic && base_type.BuiltinType != BuiltinTypeSpec.Type.Object) {
Report.Error (713, Location, "Static class `{0}' cannot derive from type `{1}'. Static classes must derive from object",
GetSignatureForError (), base_type.GetSignatureForError ());
}
switch (base_type.BuiltinType) {
case BuiltinTypeSpec.Type.Enum:
case BuiltinTypeSpec.Type.ValueType:
case BuiltinTypeSpec.Type.MulticastDelegate:
case BuiltinTypeSpec.Type.Delegate:
case BuiltinTypeSpec.Type.Array:
if (!(spec is BuiltinTypeSpec)) {
Report.Error (644, Location, "`{0}' cannot derive from special class `{1}'",
GetSignatureForError (), base_type.GetSignatureForError ());
base_type = Compiler.BuiltinTypes.Object;
}
break;
}
if (!IsAccessibleAs (base_type)) {
Report.SymbolRelatedToPreviousError (base_type);
Report.Error (60, Location, "Inconsistent accessibility: base class `{0}' is less accessible than class `{1}'",
base_type.GetSignatureForError (), GetSignatureForError ());
}
}
if (PartialContainer.IsStatic && ifaces != null) {
foreach (var t in ifaces)
Report.SymbolRelatedToPreviousError (t);
Report.Error (714, Location, "Static class `{0}' cannot implement interfaces", GetSignatureForError ());
}
return ifaces;
}
/// Search for at least one defined condition in ConditionalAttribute of attribute class
/// Valid only for attribute classes.
public override string[] ConditionalConditions ()
{
if ((caching_flags & (Flags.Excluded_Undetected | Flags.Excluded)) == 0)
return null;
caching_flags &= ~Flags.Excluded_Undetected;
if (OptAttributes == null)
return null;
Attribute[] attrs = OptAttributes.SearchMulti (Module.PredefinedAttributes.Conditional);
if (attrs == null)
return null;
string[] conditions = new string[attrs.Length];
for (int i = 0; i < conditions.Length; ++i)
conditions[i] = attrs[i].GetConditionalAttributeValue ();
caching_flags |= Flags.Excluded;
return conditions;
}
//
// FIXME: How do we deal with the user specifying a different
// layout?
//
protected override TypeAttributes TypeAttr {
get {
TypeAttributes ta = base.TypeAttr | TypeAttributes.AutoLayout | TypeAttributes.Class;
if (IsStatic)
ta |= StaticClassAttribute;
return ta;
}
}
}
public sealed class Struct : ClassOrStruct {
bool is_unmanaged, has_unmanaged_check_done;
bool InTransit;
// <summary>
// Modifiers allowed in a struct declaration
// </summary>
const Modifiers AllowedModifiers =
Modifiers.NEW |
Modifiers.PUBLIC |
Modifiers.PROTECTED |
Modifiers.INTERNAL |
Modifiers.UNSAFE |
Modifiers.PRIVATE;
public Struct (TypeContainer parent, MemberName name, Modifiers mod, Attributes attrs)
: base (parent, name, attrs, MemberKind.Struct)
{
var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
this.ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod, accmods, Location, Report) | Modifiers.SEALED ;
spec = new TypeSpec (Kind, null, this, null, ModFlags);
}
public override AttributeTargets AttributeTargets {
get {
return AttributeTargets.Struct;
}
}
public override void Accept (StructuralVisitor visitor)
{
visitor.Visit (this);
}
public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
{
base.ApplyAttributeBuilder (a, ctor, cdata, pa);
//
// When struct constains fixed fixed and struct layout has explicitly
// set CharSet, its value has to be propagated to compiler generated
// fixed types
//
if (a.Type == pa.StructLayout) {
var value = a.GetNamedValue ("CharSet");
if (value == null)
return;
for (int i = 0; i < Members.Count; ++i) {
FixedField ff = Members [i] as FixedField;
if (ff == null)
continue;
ff.CharSet = (CharSet) System.Enum.Parse (typeof (CharSet), value.GetValue ().ToString ());
}
}
}
bool CheckStructCycles ()
{
if (InTransit)
return false;
InTransit = true;
foreach (var member in Members) {
var field = member as Field;
if (field == null)
continue;
TypeSpec ftype = field.Spec.MemberType;
if (!ftype.IsStruct)
continue;
if (ftype is BuiltinTypeSpec)
continue;
foreach (var targ in ftype.TypeArguments) {
if (!CheckFieldTypeCycle (targ)) {
Report.Error (523, field.Location,
"Struct member `{0}' of type `{1}' causes a cycle in the struct layout",
field.GetSignatureForError (), ftype.GetSignatureForError ());
break;
}
}
//
// Static fields of exactly same type are allowed
//
if (field.IsStatic && ftype == CurrentType)
continue;
if (!CheckFieldTypeCycle (ftype)) {
Report.Error (523, field.Location,
"Struct member `{0}' of type `{1}' causes a cycle in the struct layout",
field.GetSignatureForError (), ftype.GetSignatureForError ());
break;
}
}
InTransit = false;
return true;
}
static bool CheckFieldTypeCycle (TypeSpec ts)
{
var fts = ts.MemberDefinition as Struct;
if (fts == null)
return true;
return fts.CheckStructCycles ();
}
public override void Emit ()
{
CheckStructCycles ();
base.Emit ();
}
public override bool IsUnmanagedType ()
{
if (has_unmanaged_check_done)
return is_unmanaged;
if (requires_delayed_unmanagedtype_check)
return true;
var parent_def = Parent.PartialContainer;
if (parent_def != null && parent_def.IsGenericOrParentIsGeneric) {
has_unmanaged_check_done = true;
return false;
}
if (first_nonstatic_field != null) {
requires_delayed_unmanagedtype_check = true;
foreach (var member in Members) {
var f = member as Field;
if (f == null)
continue;
if (f.IsStatic)
continue;
// It can happen when recursive unmanaged types are defined
// struct S { S* s; }
TypeSpec mt = f.MemberType;
if (mt == null) {
return true;
}
if (mt.IsUnmanaged)
continue;
has_unmanaged_check_done = true;
return false;
}
has_unmanaged_check_done = true;
}
is_unmanaged = true;
return true;
}
protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class)
{
var ifaces = base.ResolveBaseTypes (out base_class);
base_type = Compiler.BuiltinTypes.ValueType;
return ifaces;
}
protected override TypeAttributes TypeAttr {
get {
const
TypeAttributes DefaultTypeAttributes =
TypeAttributes.SequentialLayout |
TypeAttributes.Sealed ;
return base.TypeAttr | DefaultTypeAttributes;
}
}
public override void RegisterFieldForInitialization (MemberCore field, FieldInitializer expression)
{
if ((field.ModFlags & Modifiers.STATIC) == 0) {
Report.Error (573, field.Location, "`{0}': Structs cannot have instance field initializers",
field.GetSignatureForError ());
return;
}
base.RegisterFieldForInitialization (field, expression);
}
}
/// <summary>
/// Interfaces
/// </summary>
public sealed class Interface : TypeDefinition {
/// <summary>
/// Modifiers allowed in a class declaration
/// </summary>
const Modifiers AllowedModifiers =
Modifiers.NEW |
Modifiers.PUBLIC |
Modifiers.PROTECTED |
Modifiers.INTERNAL |
Modifiers.UNSAFE |
Modifiers.PRIVATE;
public Interface (TypeContainer parent, MemberName name, Modifiers mod, Attributes attrs)
: base (parent, name, attrs, MemberKind.Interface)
{
var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
this.ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod, accmods, name.Location, Report);
spec = new TypeSpec (Kind, null, this, null, ModFlags);
}
#region Properties
public override AttributeTargets AttributeTargets {
get {
return AttributeTargets.Interface;
}
}
protected override TypeAttributes TypeAttr {
get {
const TypeAttributes DefaultTypeAttributes =
TypeAttributes.AutoLayout |
TypeAttributes.Abstract |
TypeAttributes.Interface;
return base.TypeAttr | DefaultTypeAttributes;
}
}
#endregion
public override void Accept (StructuralVisitor visitor)
{
visitor.Visit (this);
}
public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
{
if (a.Type == pa.ComImport && !attributes.Contains (pa.Guid)) {
a.Error_MissingGuidAttribute ();
return;
}
base.ApplyAttributeBuilder (a, ctor, cdata, pa);
}
protected override bool VerifyClsCompliance ()
{
if (!base.VerifyClsCompliance ())
return false;
if (iface_exprs != null) {
foreach (var iface in iface_exprs) {
if (iface.IsCLSCompliant ())
continue;
Report.SymbolRelatedToPreviousError (iface);
Report.Warning (3027, 1, Location, "`{0}' is not CLS-compliant because base interface `{1}' is not CLS-compliant",
GetSignatureForError (), TypeManager.CSharpName (iface));
}
}
return true;
}
}
public abstract class InterfaceMemberBase : MemberBase
{
//
// Common modifiers allowed in a class declaration
//
protected const Modifiers AllowedModifiersClass =
Modifiers.NEW |
Modifiers.PUBLIC |
Modifiers.PROTECTED |
Modifiers.INTERNAL |
Modifiers.PRIVATE |
Modifiers.STATIC |
Modifiers.VIRTUAL |
Modifiers.SEALED |
Modifiers.OVERRIDE |
Modifiers.ABSTRACT |
Modifiers.UNSAFE |
Modifiers.EXTERN;
//
// Common modifiers allowed in a struct declaration
//
protected const Modifiers AllowedModifiersStruct =
Modifiers.NEW |
Modifiers.PUBLIC |
Modifiers.PROTECTED |
Modifiers.INTERNAL |
Modifiers.PRIVATE |
Modifiers.STATIC |
Modifiers.OVERRIDE |
Modifiers.UNSAFE |
Modifiers.EXTERN;
//
// Common modifiers allowed in a interface declaration
//
protected const Modifiers AllowedModifiersInterface =
Modifiers.NEW |
Modifiers.UNSAFE;
//
// Whether this is an interface member.
//
public bool IsInterface;
//
// If true, this is an explicit interface implementation
//
public readonly bool IsExplicitImpl;
protected bool is_external_implementation;
//
// The interface type we are explicitly implementing
//
public TypeSpec InterfaceType;
//
// The method we're overriding if this is an override method.
//
protected MethodSpec base_method;
readonly Modifiers explicit_mod_flags;
public MethodAttributes flags;
public InterfaceMemberBase (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, MemberName name, Attributes attrs)
: base (parent, type, mod, allowed_mod, Modifiers.PRIVATE, name, attrs)
{
IsInterface = parent.Kind == MemberKind.Interface;
IsExplicitImpl = (MemberName.ExplicitInterface != null);
explicit_mod_flags = mod;
}
public abstract Variance ExpectedMemberTypeVariance { get; }
protected override bool CheckBase ()
{
if (!base.CheckBase ())
return false;
if ((caching_flags & Flags.MethodOverloadsExist) != 0)
CheckForDuplications ();
if (IsExplicitImpl)
return true;
// For System.Object only
if (Parent.BaseType == null)
return true;
MemberSpec candidate;
bool overrides = false;
var base_member = FindBaseMember (out candidate, ref overrides);
if ((ModFlags & Modifiers.OVERRIDE) != 0) {
if (base_member == null) {
if (candidate == null) {
if (this is Method && ((Method)this).ParameterInfo.IsEmpty && MemberName.Name == Destructor.MetadataName && MemberName.Arity == 0) {
Report.Error (249, Location, "Do not override `{0}'. Use destructor syntax instead",
"object.Finalize()");
} else {
Report.Error (115, Location, "`{0}' is marked as an override but no suitable {1} found to override",
GetSignatureForError (), SimpleName.GetMemberType (this));
}
} else {
Report.SymbolRelatedToPreviousError (candidate);
if (this is Event)
Report.Error (72, Location, "`{0}': cannot override because `{1}' is not an event",
GetSignatureForError (), TypeManager.GetFullNameSignature (candidate));
else if (this is PropertyBase)
Report.Error (544, Location, "`{0}': cannot override because `{1}' is not a property",
GetSignatureForError (), TypeManager.GetFullNameSignature (candidate));
else
Report.Error (505, Location, "`{0}': cannot override because `{1}' is not a method",
GetSignatureForError (), TypeManager.GetFullNameSignature (candidate));
}
return false;
}
//
// Handles ambiguous overrides
//
if (candidate != null) {
Report.SymbolRelatedToPreviousError (candidate);
Report.SymbolRelatedToPreviousError (base_member);
// Get member definition for error reporting
var m1 = MemberCache.GetMember (base_member.DeclaringType.GetDefinition (), base_member);
var m2 = MemberCache.GetMember (candidate.DeclaringType.GetDefinition (), candidate);
Report.Error (462, Location,
"`{0}' cannot override inherited members `{1}' and `{2}' because they have the same signature when used in type `{3}'",
GetSignatureForError (), m1.GetSignatureForError (), m2.GetSignatureForError (), Parent.GetSignatureForError ());
}
if (!CheckOverrideAgainstBase (base_member))
return false;
ObsoleteAttribute oa = base_member.GetAttributeObsolete ();
if (oa != null) {
if (OptAttributes == null || !OptAttributes.Contains (Module.PredefinedAttributes.Obsolete)) {
Report.SymbolRelatedToPreviousError (base_member);
Report.Warning (672, 1, Location, "Member `{0}' overrides obsolete member `{1}'. Add the Obsolete attribute to `{0}'",
GetSignatureForError (), base_member.GetSignatureForError ());
}
} else {
if (OptAttributes != null && OptAttributes.Contains (Module.PredefinedAttributes.Obsolete)) {
Report.SymbolRelatedToPreviousError (base_member);
Report.Warning (809, 1, Location, "Obsolete member `{0}' overrides non-obsolete member `{1}'",
GetSignatureForError (), base_member.GetSignatureForError ());
}
}
base_method = base_member as MethodSpec;
return true;
}
if (base_member == null && candidate != null && (!(candidate is IParametersMember) || !(this is IParametersMember)))
base_member = candidate;
if (base_member == null) {
if ((ModFlags & Modifiers.NEW) != 0) {
if (base_member == null) {
Report.Warning (109, 4, Location, "The member `{0}' does not hide an inherited member. The new keyword is not required",
GetSignatureForError ());
}
}
} else {
if ((ModFlags & Modifiers.NEW) == 0) {
ModFlags |= Modifiers.NEW;
if (!IsCompilerGenerated) {
Report.SymbolRelatedToPreviousError (base_member);
if (!IsInterface && (base_member.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
Report.Warning (114, 2, Location, "`{0}' hides inherited member `{1}'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword",
GetSignatureForError (), base_member.GetSignatureForError ());
} else {
Report.Warning (108, 2, Location, "`{0}' hides inherited member `{1}'. Use the new keyword if hiding was intended",
GetSignatureForError (), base_member.GetSignatureForError ());
}
}
}
if (!IsInterface && base_member.IsAbstract && !overrides) {
Report.SymbolRelatedToPreviousError (base_member);
Report.Error (533, Location, "`{0}' hides inherited abstract member `{1}'",
GetSignatureForError (), base_member.GetSignatureForError ());
}
}
return true;
}
protected virtual bool CheckForDuplications ()
{
return Parent.MemberCache.CheckExistingMembersOverloads (this, ParametersCompiled.EmptyReadOnlyParameters);
}
//
// Performs various checks on the MethodInfo `mb' regarding the modifier flags
// that have been defined.
//
protected virtual bool CheckOverrideAgainstBase (MemberSpec base_member)
{
bool ok = true;
if ((base_member.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) == 0) {
Report.SymbolRelatedToPreviousError (base_member);
Report.Error (506, Location,
"`{0}': cannot override inherited member `{1}' because it is not marked virtual, abstract or override",
GetSignatureForError (), TypeManager.CSharpSignature (base_member));
ok = false;
}
// Now we check that the overriden method is not final
if ((base_member.Modifiers & Modifiers.SEALED) != 0) {
Report.SymbolRelatedToPreviousError (base_member);
Report.Error (239, Location, "`{0}': cannot override inherited member `{1}' because it is sealed",
GetSignatureForError (), TypeManager.CSharpSignature (base_member));
ok = false;
}
var base_member_type = ((IInterfaceMemberSpec) base_member).MemberType;
if (!TypeSpecComparer.Override.IsEqual (MemberType, base_member_type)) {
Report.SymbolRelatedToPreviousError (base_member);
if (this is PropertyBasedMember) {
Report.Error (1715, Location, "`{0}': type must be `{1}' to match overridden member `{2}'",
GetSignatureForError (), TypeManager.CSharpName (base_member_type), TypeManager.CSharpSignature (base_member));
} else {
Report.Error (508, Location, "`{0}': return type must be `{1}' to match overridden member `{2}'",
GetSignatureForError (), TypeManager.CSharpName (base_member_type), TypeManager.CSharpSignature (base_member));
}
ok = false;
}
return ok;
}
protected static bool CheckAccessModifiers (MemberCore this_member, MemberSpec base_member)
{
var thisp = this_member.ModFlags & Modifiers.AccessibilityMask;
var base_classp = base_member.Modifiers & Modifiers.AccessibilityMask;
if ((base_classp & (Modifiers.PROTECTED | Modifiers.INTERNAL)) == (Modifiers.PROTECTED | Modifiers.INTERNAL)) {
//
// It must be at least "protected"
//
if ((thisp & Modifiers.PROTECTED) == 0) {
return false;
}
//
// when overriding protected internal, the method can be declared
// protected internal only within the same assembly or assembly
// which has InternalsVisibleTo
//
if ((thisp & Modifiers.INTERNAL) != 0) {
return base_member.DeclaringType.MemberDefinition.IsInternalAsPublic (this_member.Module.DeclaringAssembly);
}
//
// protected overriding protected internal inside same assembly
// requires internal modifier as well
//
if (base_member.DeclaringType.MemberDefinition.IsInternalAsPublic (this_member.Module.DeclaringAssembly)) {
return false;
}
return true;
}
return thisp == base_classp;
}
public override bool Define ()
{
if (IsInterface) {
ModFlags = Modifiers.PUBLIC | Modifiers.ABSTRACT |
Modifiers.VIRTUAL | (ModFlags & (Modifiers.UNSAFE | Modifiers.NEW));
flags = MethodAttributes.Public |
MethodAttributes.Abstract |
MethodAttributes.HideBySig |
MethodAttributes.NewSlot |
MethodAttributes.Virtual;
} else {
Parent.PartialContainer.MethodModifiersValid (this);
flags = ModifiersExtensions.MethodAttr (ModFlags);
}
if (IsExplicitImpl) {
InterfaceType = MemberName.ExplicitInterface.ResolveAsType (Parent);
if (InterfaceType == null)
return false;
if ((ModFlags & Modifiers.PARTIAL) != 0) {
Report.Error (754, Location, "A partial method `{0}' cannot explicitly implement an interface",
GetSignatureForError ());
}
if (!InterfaceType.IsInterface) {
Report.SymbolRelatedToPreviousError (InterfaceType);
Report.Error (538, Location, "The type `{0}' in explicit interface declaration is not an interface",
TypeManager.CSharpName (InterfaceType));
} else {
Parent.PartialContainer.VerifyImplements (this);
}
ModifiersExtensions.Check (Modifiers.AllowedExplicitImplFlags, explicit_mod_flags, 0, Location, Report);
}
return base.Define ();
}
protected bool DefineParameters (ParametersCompiled parameters)
{
if (!parameters.Resolve (this))
return false;
bool error = false;
for (int i = 0; i < parameters.Count; ++i) {
Parameter p = parameters [i];
if (p.HasDefaultValue && (IsExplicitImpl || this is Operator || (this is Indexer && parameters.Count == 1)))
p.Warning_UselessOptionalParameter (Report);
if (p.CheckAccessibility (this))
continue;
TypeSpec t = parameters.Types [i];
Report.SymbolRelatedToPreviousError (t);
if (this is Indexer)
Report.Error (55, Location,
"Inconsistent accessibility: parameter type `{0}' is less accessible than indexer `{1}'",
TypeManager.CSharpName (t), GetSignatureForError ());
else if (this is Operator)
Report.Error (57, Location,
"Inconsistent accessibility: parameter type `{0}' is less accessible than operator `{1}'",
TypeManager.CSharpName (t), GetSignatureForError ());
else
Report.Error (51, Location,
"Inconsistent accessibility: parameter type `{0}' is less accessible than method `{1}'",
TypeManager.CSharpName (t), GetSignatureForError ());
error = true;
}
return !error;
}
protected override void DoMemberTypeDependentChecks ()
{
base.DoMemberTypeDependentChecks ();
TypeManager.CheckTypeVariance (MemberType, ExpectedMemberTypeVariance, this);
}
public override void Emit()
{
// for extern static method must be specified either DllImport attribute or MethodImplAttribute.
// We are more strict than csc and report this as an error because SRE does not allow emit that
if ((ModFlags & Modifiers.EXTERN) != 0 && !is_external_implementation) {
if (this is Constructor) {
Report.Warning (824, 1, Location,
"Constructor `{0}' is marked `external' but has no external implementation specified", GetSignatureForError ());
} else {
Report.Warning (626, 1, Location,
"`{0}' is marked as an external but has no DllImport attribute. Consider adding a DllImport attribute to specify the external implementation",
GetSignatureForError ());
}
}
base.Emit ();
}
public override bool EnableOverloadChecks (MemberCore overload)
{
//
// Two members can differ in their explicit interface
// type parameter only
//
InterfaceMemberBase imb = overload as InterfaceMemberBase;
if (imb != null && imb.IsExplicitImpl) {
if (IsExplicitImpl) {
caching_flags |= Flags.MethodOverloadsExist;
}
return true;
}
return IsExplicitImpl;
}
protected void Error_CannotChangeAccessModifiers (MemberCore member, MemberSpec base_member)
{
var base_modifiers = base_member.Modifiers;
// Remove internal modifier from types which are not internally accessible
if ((base_modifiers & Modifiers.AccessibilityMask) == (Modifiers.PROTECTED | Modifiers.INTERNAL) &&
!base_member.DeclaringType.MemberDefinition.IsInternalAsPublic (member.Module.DeclaringAssembly))
base_modifiers = Modifiers.PROTECTED;
Report.SymbolRelatedToPreviousError (base_member);
Report.Error (507, member.Location,
"`{0}': cannot change access modifiers when overriding `{1}' inherited member `{2}'",
member.GetSignatureForError (),
ModifiersExtensions.AccessibilityName (base_modifiers),
base_member.GetSignatureForError ());
}
protected void Error_StaticReturnType ()
{
Report.Error (722, Location,
"`{0}': static types cannot be used as return types",
MemberType.GetSignatureForError ());
}
/// <summary>
/// Gets base method and its return type
/// </summary>
protected virtual MemberSpec FindBaseMember (out MemberSpec bestCandidate, ref bool overrides)
{
return MemberCache.FindBaseMember (this, out bestCandidate, ref overrides);
}
//
// The "short" name of this property / indexer / event. This is the
// name without the explicit interface.
//
public string ShortName {
get { return MemberName.Name; }
}
//
// Returns full metadata method name
//
public string GetFullName (MemberName name)
{
return GetFullName (name.Name);
}
public string GetFullName (string name)
{
if (!IsExplicitImpl)
return name;
//
// When dealing with explicit members a full interface type
// name is added to member name to avoid possible name conflicts
//
// We use CSharpName which gets us full name with benefit of
// replacing predefined names which saves some space and name
// is still unique
//
return TypeManager.CSharpName (InterfaceType) + "." + name;
}
public override string GetSignatureForDocumentation ()
{
if (IsExplicitImpl)
return Parent.GetSignatureForDocumentation () + "." + InterfaceType.GetExplicitNameSignatureForDocumentation () + "#" + ShortName;
return Parent.GetSignatureForDocumentation () + "." + ShortName;
}
public override bool IsUsed
{
get { return IsExplicitImpl || base.IsUsed; }
}
}
public abstract class MemberBase : MemberCore
{
protected FullNamedExpression type_expr;
protected TypeSpec member_type;
public new TypeDefinition Parent;
protected MemberBase (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, Modifiers def_mod, MemberName name, Attributes attrs)
: base (parent, name, attrs)
{
this.Parent = parent;
this.type_expr = type;
ModFlags = ModifiersExtensions.Check (allowed_mod, mod, def_mod, Location, Report);
}
#region Properties
public TypeSpec MemberType {
get {
return member_type;
}
}
public FullNamedExpression TypeExpression {
get {
return type_expr;
}
}
#endregion
//
// Main member define entry
//
public override bool Define ()
{
DoMemberTypeIndependentChecks ();
//
// Returns false only when type resolution failed
//
if (!ResolveMemberType ())
return false;
DoMemberTypeDependentChecks ();
return true;
}
//
// Any type_name independent checks
//
protected virtual void DoMemberTypeIndependentChecks ()
{
if ((Parent.ModFlags & Modifiers.SEALED) != 0 &&
(ModFlags & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
Report.Error (549, Location, "New virtual member `{0}' is declared in a sealed class `{1}'",
GetSignatureForError (), Parent.GetSignatureForError ());
}
}
//
// Any type_name dependent checks
//
protected virtual void DoMemberTypeDependentChecks ()
{
// verify accessibility
if (!IsAccessibleAs (MemberType)) {
Report.SymbolRelatedToPreviousError (MemberType);
if (this is Property)
Report.Error (53, Location,
"Inconsistent accessibility: property type `" +
TypeManager.CSharpName (MemberType) + "' is less " +
"accessible than property `" + GetSignatureForError () + "'");
else if (this is Indexer)
Report.Error (54, Location,
"Inconsistent accessibility: indexer return type `" +
TypeManager.CSharpName (MemberType) + "' is less " +
"accessible than indexer `" + GetSignatureForError () + "'");
else if (this is MethodCore) {
if (this is Operator)
Report.Error (56, Location,
"Inconsistent accessibility: return type `" +
TypeManager.CSharpName (MemberType) + "' is less " +
"accessible than operator `" + GetSignatureForError () + "'");
else
Report.Error (50, Location,
"Inconsistent accessibility: return type `" +
TypeManager.CSharpName (MemberType) + "' is less " +
"accessible than method `" + GetSignatureForError () + "'");
} else {
Report.Error (52, Location,
"Inconsistent accessibility: field type `" +
TypeManager.CSharpName (MemberType) + "' is less " +
"accessible than field `" + GetSignatureForError () + "'");
}
}
}
protected void IsTypePermitted ()
{
if (MemberType.IsSpecialRuntimeType) {
if (Parent is StateMachine) {
Report.Error (4012, Location,
"Parameters or local variables of type `{0}' cannot be declared in async methods or iterators",
MemberType.GetSignatureForError ());
} else if (Parent is HoistedStoreyClass) {
Report.Error (4013, Location,
"Local variables of type `{0}' cannot be used inside anonymous methods, lambda expressions or query expressions",
MemberType.GetSignatureForError ());
} else {
Report.Error (610, Location,
"Field or property cannot be of type `{0}'", MemberType.GetSignatureForError ());
}
}
}
protected virtual bool CheckBase ()
{
CheckProtectedModifier ();
return true;
}
public override string GetSignatureForDocumentation ()
{
return Parent.GetSignatureForDocumentation () + "." + MemberName.Basename;
}
protected virtual bool ResolveMemberType ()
{
if (member_type != null)
throw new InternalErrorException ("Multi-resolve");
member_type = type_expr.ResolveAsType (this);
return member_type != null;
}
}
}