// 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;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp
{
///
/// A type reference in the C# AST.
///
public abstract class AstType : AstNode
{
#region Null
public new static readonly AstType Null = new NullAstType ();
sealed class NullAstType : AstType
{
public override bool IsNull {
get {
return true;
}
}
public override void AcceptVisitor (IAstVisitor visitor)
{
visitor.VisitNullNode(this);
}
public override T AcceptVisitor (IAstVisitor visitor)
{
return visitor.VisitNullNode(this);
}
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
return other == null || other.IsNull;
}
public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider)
{
return SpecialType.UnknownType;
}
}
#endregion
#region PatternPlaceholder
public static implicit operator AstType(PatternMatching.Pattern pattern)
{
return pattern != null ? new PatternPlaceholder(pattern) : null;
}
sealed class PatternPlaceholder : AstType, PatternMatching.INode
{
readonly PatternMatching.Pattern child;
public PatternPlaceholder(PatternMatching.Pattern child)
{
this.child = child;
}
public override NodeType NodeType {
get { return NodeType.Pattern; }
}
public override void AcceptVisitor (IAstVisitor visitor)
{
visitor.VisitPatternPlaceholder (this, child);
}
public override T AcceptVisitor (IAstVisitor visitor)
{
return visitor.VisitPatternPlaceholder (this, child);
}
public override S AcceptVisitor(IAstVisitor visitor, T data)
{
return visitor.VisitPatternPlaceholder (this, child, data);
}
public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider)
{
throw new NotSupportedException();
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
return child.DoMatch(other, match);
}
bool PatternMatching.INode.DoMatchCollection(Role role, PatternMatching.INode pos, PatternMatching.Match match, PatternMatching.BacktrackingInfo backtrackingInfo)
{
return child.DoMatchCollection(role, pos, match, backtrackingInfo);
}
}
#endregion
public override NodeType NodeType {
get { return NodeType.TypeReference; }
}
public new AstType Clone()
{
return (AstType)base.Clone();
}
///
/// Gets whether this type is a SimpleType "var".
///
public bool IsVar()
{
SimpleType st = this as SimpleType;
return st != null && st.Identifier == "var" && st.TypeArguments.Count == 0;
}
///
/// Create an ITypeReference for this AstType.
/// Uses the context (ancestors of this node) to determine the correct .
///
///
/// The resulting type reference will read the context information from the
/// :
/// For resolving type parameters, the CurrentTypeDefinition/CurrentMember is used.
/// For resolving simple names, the current namespace and usings from the CurrentUsingScope
/// (on CSharpTypeResolveContext only) is used.
///
public ITypeReference ToTypeReference(InterningProvider interningProvider = null)
{
return ToTypeReference(GetNameLookupMode(), interningProvider);
}
///
/// Create an ITypeReference for this AstType.
///
///
/// The resulting type reference will read the context information from the
/// :
/// For resolving type parameters, the CurrentTypeDefinition/CurrentMember is used.
/// For resolving simple names, the current namespace and usings from the CurrentUsingScope
/// (on CSharpTypeResolveContext only) is used.
///
public abstract ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null);
///
/// Gets the name lookup mode from the context (looking at the ancestors of this ).
///
public NameLookupMode GetNameLookupMode()
{
AstType outermostType = this;
while (outermostType.Parent is AstType)
outermostType = (AstType)outermostType.Parent;
if (outermostType.Parent is UsingDeclaration || outermostType.Parent is UsingAliasDeclaration) {
return NameLookupMode.TypeInUsingDeclaration;
} else if (outermostType.Role == Roles.BaseType) {
// Use BaseTypeReference for a type's base type, and for a constraint on a type.
// Do not use it for a constraint on a method.
if (outermostType.Parent is TypeDeclaration || (outermostType.Parent is Constraint && outermostType.Parent.Parent is TypeDeclaration))
return NameLookupMode.BaseTypeReference;
}
return NameLookupMode.Type;
}
///
/// Creates a pointer type from this type by nesting it in a .
/// If this type already is a pointer type, this method just increases the PointerRank of the existing pointer type.
///
public virtual AstType MakePointerType()
{
return new ComposedType { BaseType = this }.MakePointerType();
}
///
/// Creates an array type from this type by nesting it in a .
/// If this type already is an array type, the additional rank is prepended to the existing array specifier list.
/// Thus, new SimpleType("T").MakeArrayType(1).MakeArrayType(2) will result in "T[,][]".
///
public virtual AstType MakeArrayType(int rank = 1)
{
return new ComposedType { BaseType = this }.MakeArrayType(rank);
}
///
/// Creates a nullable type from this type by nesting it in a .
///
public AstType MakeNullableType()
{
return new ComposedType { BaseType = this, HasNullableSpecifier = true };
}
///
/// Builds an expression that can be used to access a static member on this type.
///
public MemberReferenceExpression Member(string memberName)
{
return new TypeReferenceExpression { Type = this }.Member(memberName);
}
///
/// Builds an expression that can be used to access a static member on this type.
///
public MemberType MemberType(string memberName, params AstType[] typeArguments)
{
var memberType = new MemberType(this, memberName);
memberType.TypeArguments.AddRange(typeArguments);
return memberType;
}
///
/// Builds an expression that can be used to access a static member on this type.
///
public MemberType MemberType(string memberName, IEnumerable typeArguments)
{
var memberType = new MemberType(this, memberName);
memberType.TypeArguments.AddRange(typeArguments);
return memberType;
}
///
/// Builds an invocation expression using this type as target.
///
public InvocationExpression Invoke(string methodName, IEnumerable arguments)
{
return new TypeReferenceExpression { Type = this }.Invoke(methodName, arguments);
}
///
/// Builds an invocation expression using this type as target.
///
public InvocationExpression Invoke(string methodName, params Expression[] arguments)
{
return new TypeReferenceExpression { Type = this }.Invoke(methodName, arguments);
}
///
/// Builds an invocation expression using this type as target.
///
public InvocationExpression Invoke(string methodName, IEnumerable typeArguments, IEnumerable arguments)
{
return new TypeReferenceExpression { Type = this }.Invoke(methodName, typeArguments, arguments);
}
///
/// Creates a simple AstType from a dotted name.
/// Does not support generics, arrays, etc. - just simple dotted names,
/// e.g. namespace names.
///
public static AstType Create(string dottedName)
{
string[] parts = dottedName.Split('.');
AstType type = new SimpleType(parts[0]);
for (int i = 1; i < parts.Length; i++) {
type = new MemberType(type, parts[i]);
}
return type;
}
}
}