// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.TypeSystem
{
	/// 
	/// This interface represents a resolved type in the type system.
	/// 
	/// 
	/// 
	/// A type is potentially
	/// - a type definition (, i.e. a class, struct, interface, delegate, or built-in primitive type)
	/// - a parameterized type (, e.g. List<int>)
	/// - a type parameter (, e.g. T)
	/// - an array ()
	/// - a pointer ()
	/// - a managed reference ()
	/// - one of the special types (, ,
	///      , )
	/// 
	/// The  property can be used to switch on the kind of a type.
	/// 
	/// 
	/// IType uses the null object pattern:  serves as the null object.
	/// Methods or properties returning IType never return null unless documented otherwise.
	/// 
	/// 
	/// Types should be compared for equality using the  method.
	/// Identical types do not necessarily use the same object reference.
	/// 
	/// 
	public interface IType : INamedElement, IEquatable
	{
		/// 
		/// Gets the type kind.
		/// 
		TypeKind Kind { get; }
		
		/// 
		/// Gets whether the type is a reference type or value type.
		/// 
		/// 
		/// true, if the type is a reference type.
		/// false, if the type is a value type.
		/// null, if the type is not known (e.g. unconstrained generic type parameter or type not found)
		/// 
		bool? IsReferenceType { get; }
		
		/// 
		/// Gets the underlying type definition.
		/// Can return null for types which do not have a type definition (for example arrays, pointers, type parameters).
		/// 
		ITypeDefinition GetDefinition();
		
		/// 
		/// Gets the parent type, if this is a nested type.
		/// Returns null for top-level types.
		/// 
		IType DeclaringType { get; }
		
		/// 
		/// Gets the number of type parameters.
		/// 
		int TypeParameterCount { get; }
		/// 
		/// Gets the type parameters.
		/// Returns an empty list if this type is not generic.
		/// 
		IReadOnlyList TypeParameters { get; }
		/// 
		/// Gets the type arguments passed to this type.
		/// If this type is a generic type definition that is not parameterized, this property returns the type parameters,
		/// as if the type was parameterized with its own type arguments (class C<T> { C<T> field; }).
		/// 
		IReadOnlyList TypeArguments { get; }
		/// 
		/// Calls ITypeVisitor.Visit for this type.
		/// 
		/// The return value of the ITypeVisitor.Visit call
		IType AcceptVisitor(TypeVisitor visitor);
		
		/// 
		/// Calls ITypeVisitor.Visit for all children of this type, and reconstructs this type with the children based
		/// on the return values of the visit calls.
		/// 
		/// A copy of this type, with all children replaced by the return value of the corresponding visitor call.
		/// If the visitor returned the original types for all children (or if there are no children), returns this.
		/// 
		IType VisitChildren(TypeVisitor visitor);
		
		/// 
		/// Gets the direct base types.
		/// 
		/// Returns the direct base types including interfaces
		IEnumerable DirectBaseTypes { get; }
		
		/// 
		/// Gets a type visitor that performs the substitution of class type parameters with the type arguments
		/// of this parameterized type.
		/// Returns TypeParameterSubstitution.Identity if the type is not parametrized.
		/// 
		TypeParameterSubstitution GetSubstitution();
		
		/// 
		/// Gets a type visitor that performs the substitution of class type parameters with the type arguments
		/// of this parameterized type,
		/// and also substitutes method type parameters with the specified method type arguments.
		/// Returns TypeParameterSubstitution.Identity if the type is not parametrized.
		/// 
		TypeParameterSubstitution GetSubstitution(IReadOnlyList methodTypeArguments);
		
		/// 
		/// Gets inner classes (including inherited inner classes).
		/// 
		/// The filter used to select which types to return.
		/// The filter is tested on the original type definitions (before parameterization).
		/// Specified additional options for the GetMembers() operation.
		/// 
		/// 
		/// If the nested type is generic, this method will return a parameterized type,
		/// where the additional type parameters are set to .
		/// 
		/// 
		/// Type parameters belonging to the outer class will have the value copied from the outer type
		/// if it is a parameterized type. Otherwise, those existing type parameters will be self-parameterized,
		/// and thus 'leaked' to the caller in the same way the GetMembers() method does not specialize members
		/// from an  and 'leaks' type parameters in member signatures.
		/// 
		/// 
		/// 
		/// 
		/// class Base<T> {
		/// 	class Nested<X> {}
		/// }
		/// class Derived<A, B> : Base<B> {}
		/// 
		/// Derived[string,int].GetNestedTypes() = { Base`1+Nested`1[int, unbound] }
		/// Derived.GetNestedTypes() = { Base`1+Nested`1[`1, unbound] }
		/// Base[`1].GetNestedTypes() = { Base`1+Nested`1[`1, unbound] }
		/// Base.GetNestedTypes() = { Base`1+Nested`1[`0, unbound] }
		/// 
		/// 
		IEnumerable GetNestedTypes(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None);
		
		// Note that we cannot 'leak' the additional type parameter as we leak the normal type parameters, because
		// the index might collide. For example,
		//   class Base { class Nested {} }
		//   class Derived : Base { }
		// 
		// Derived.GetNestedTypes() = Base+Nested
		// Derived.GetNestedTypes() = Base+Nested<`1, >
		//  Here `1 refers to B, and there's no way to return X as it would collide with B.
		
		/// 
		/// Gets inner classes (including inherited inner classes)
		/// that have typeArguments.Count additional type parameters.
		/// 
		/// The type arguments passed to the inner class
		/// The filter used to select which types to return.
		/// The filter is tested on the original type definitions (before parameterization).
		/// Specified additional options for the GetMembers() operation.
		/// 
		/// Type parameters belonging to the outer class will have the value copied from the outer type
		/// if it is a parameterized type. Otherwise, those existing type parameters will be self-parameterized,
		/// and thus 'leaked' to the caller in the same way the GetMembers() method does not specialize members
		/// from an  and 'leaks' type parameters in member signatures.
		/// 
		IEnumerable GetNestedTypes(IReadOnlyList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None);
		
		/// 
		/// Gets all instance constructors for this type.
		/// 
		/// The filter used to select which constructors to return.
		/// The filter is tested on the original method definitions (before specialization).
		/// Specified additional options for the GetMembers() operation.
		/// 
		/// The result does not include static constructors.
		/// Constructors in base classes are not returned by default, as GetMemberOptions.IgnoreInheritedMembers is the default value.
		/// 
		/// For methods on parameterized types, type substitution will be performed on the method signature,
		/// and the appropriate  will be returned.
		/// 
		/// 
		IEnumerable GetConstructors(Predicate filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers);
		
		/// 
		/// Gets all methods that can be called on this type.
		/// 
		/// The filter used to select which methods to return.
		/// The filter is tested on the original method definitions (before specialization).
		/// Specified additional options for the GetMembers() operation.
		/// 
		/// 
		/// The result does not include constructors or accessors.
		/// 
		/// 
		/// For methods on parameterized types, type substitution will be performed on the method signature,
		/// and the appropriate  will be returned.
		/// 
		/// 
		/// If the method being returned is generic, and this type is a parameterized type where the type
		/// arguments involve another method's type parameters, the resulting specialized signature
		/// will be ambiguous as to which method a type parameter belongs to.
		/// For example, "List[[``0]].GetMethods()" will return "ConvertAll(Converter`2[[``0, ``0]])".
		/// 
		/// If possible, use the other GetMethods() overload to supply type arguments to the method,
		/// so that both class and method type parameter can be substituted at the same time, so that
		/// the ambiguity can be avoided.
		/// 
		/// 
		IEnumerable GetMethods(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None);
		
		/// 
		/// Gets all generic methods that can be called on this type with the specified type arguments.
		/// 
		/// The type arguments used for the method call.
		/// The filter used to select which methods to return.
		/// The filter is tested on the original method definitions (before specialization).
		/// Specified additional options for the GetMembers() operation.
		/// 
		/// The result does not include constructors or accessors.
		/// 
		/// Type substitution will be performed on the method signature, creating a 
		/// with the specified type arguments.
		/// 
		/// 
		/// When the list of type arguments is empty, this method acts like the GetMethods() overload without
		/// the type arguments parameter - that is, it also returns generic methods,
		/// and the other overload's remarks about ambiguous signatures apply here as well.
		/// 
		/// 
		IEnumerable GetMethods(IReadOnlyList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None);
		
		/// 
		/// Gets all properties that can be called on this type.
		/// 
		/// The filter used to select which properties to return.
		/// The filter is tested on the original property definitions (before specialization).
		/// Specified additional options for the GetMembers() operation.
		/// 
		/// For properties on parameterized types, type substitution will be performed on the property signature,
		/// and the appropriate  will be returned.
		/// 
		IEnumerable GetProperties(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None);
		
		/// 
		/// Gets all fields that can be accessed on this type.
		/// 
		/// The filter used to select which constructors to return.
		/// The filter is tested on the original field definitions (before specialization).
		/// Specified additional options for the GetMembers() operation.
		/// 
		/// For fields on parameterized types, type substitution will be performed on the field's return type,
		/// and the appropriate  will be returned.
		/// 
		IEnumerable GetFields(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None);
		
		/// 
		/// Gets all events that can be accessed on this type.
		/// 
		/// The filter used to select which events to return.
		/// The filter is tested on the original event definitions (before specialization).
		/// Specified additional options for the GetMembers() operation.
		/// 
		/// For fields on parameterized types, type substitution will be performed on the event's return type,
		/// and the appropriate  will be returned.
		/// 
		IEnumerable GetEvents(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None);
		
		/// 
		/// Gets all members that can be called on this type.
		/// 
		/// The filter used to select which members to return.
		/// The filter is tested on the original member definitions (before specialization).
		/// Specified additional options for the GetMembers() operation.
		/// 
		/// 
		/// The resulting list is the union of GetFields(), GetProperties(), GetMethods() and GetEvents().
		/// It does not include constructors.
		/// For parameterized types, type substitution will be performed.
		/// 
		/// 
		/// For generic methods, the remarks about ambiguous signatures from the
		///  method apply here as well.
		/// 
		/// 
		IEnumerable GetMembers(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None);
		
		/// 
		/// Gets all accessors belonging to properties or events on this type.
		/// 
		/// The filter used to select which members to return.
		/// The filter is tested on the original member definitions (before specialization).
		/// Specified additional options for the GetMembers() operation.
		/// 
		/// Accessors are not returned by GetMembers() or GetMethods().
		/// 
		IEnumerable GetAccessors(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None);
	}
	
	[Flags]
	public enum GetMemberOptions
	{
		/// 
		/// No options specified - this is the default.
		/// Members will be specialized, and inherited members will be included.
		/// 
		None = 0x00,
		/// 
		/// Do not specialize the returned members - directly return the definitions.
		/// 
		ReturnMemberDefinitions = 0x01,
		/// 
		/// Do not list inherited members - only list members defined directly on this type.
		/// 
		IgnoreInheritedMembers = 0x02
	}
}