mirror of https://github.com/icsharpcode/ILSpy.git
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.
486 lines
14 KiB
486 lines
14 KiB
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) |
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) |
|
|
|
using System; |
|
|
|
namespace ICSharpCode.SharpDevelop.Dom |
|
{ |
|
/// <summary> |
|
/// Class describing a context in which an expression can be. |
|
/// Serves as filter for code completion results, but the contexts exposed as static fields |
|
/// can also be used as a kind of enumeration for special behaviour in the resolver. |
|
/// </summary> |
|
public abstract class ExpressionContext |
|
{ |
|
#region Instance members |
|
public abstract bool ShowEntry(ICompletionEntry o); |
|
|
|
protected bool readOnly = true; |
|
object suggestedItem; |
|
|
|
/// <summary> |
|
/// Gets if the expression is in the context of an object creation. |
|
/// </summary> |
|
public virtual bool IsObjectCreation { |
|
get { |
|
return false; |
|
} |
|
set { |
|
if (value) |
|
throw new NotSupportedException(); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Gets/Sets the default item that should be included in a code completion popup |
|
/// in this context and selected as default value. |
|
/// </summary> |
|
/// <example> |
|
/// "List<TypeName> var = new *expr*();" has as suggested item the pseudo-class |
|
/// "List<TypeName>". |
|
/// </example> |
|
public object SuggestedItem { |
|
get { |
|
return suggestedItem; |
|
} |
|
set { |
|
if (readOnly) |
|
throw new NotSupportedException(); |
|
suggestedItem = value; |
|
} |
|
} |
|
|
|
public virtual bool IsTypeContext { |
|
get { return false; } |
|
} |
|
#endregion |
|
|
|
#region VB specific contexts (public static fields) * MOVE TO ANOTHER CLASS * |
|
/// <summary>The context expects a new parameter declaration</summary> |
|
/// <example>Function Test(*expr*, *expr*, ...)</example> |
|
public static readonly ExpressionContext Parameter = new DefaultExpressionContext("Parameter"); |
|
#endregion |
|
|
|
#region Default contexts (public static fields) |
|
/// <summary>Default/unknown context</summary> |
|
public readonly static ExpressionContext Default = new DefaultExpressionContext("Default"); |
|
|
|
/// <summary>The context expects the base type of an enum.</summary> |
|
/// <example>enum Name : *expr* {}</example> |
|
public readonly static ExpressionContext EnumBaseType = new EnumBaseTypeExpressionContext(); |
|
|
|
/// <summary>Context expects a non-sealed type or interface</summary> |
|
/// <example>class C : *expr* {}</example> |
|
public readonly static ExpressionContext InheritableType = new InheritableTypeExpressionContext(); |
|
|
|
/// <summary>Context expects a namespace name</summary> |
|
/// <example>using *expr*;</example> |
|
public readonly static ExpressionContext Namespace = new ImportableExpressionContext(false); |
|
|
|
/// <summary>Context expects an importable type (namespace or class with public static members)</summary> |
|
/// <example>Imports *expr*;</example> |
|
public readonly static ExpressionContext Importable = new ImportableExpressionContext(true); |
|
|
|
/// <summary>Context expects a type name</summary> |
|
/// <example>typeof(*expr*)</example> |
|
public readonly static ExpressionContext Type = new TypeExpressionContext(null, false, true); |
|
|
|
/// <summary>Context expects the name of a non-static, non-void type</summary> |
|
/// <example>is *expr*, *expr* variableName</example> |
|
public readonly static ExpressionContext NonStaticNonVoidType = new NonStaticTypeExpressionContext("NonStaticType", false); |
|
|
|
/// <summary>Context expects a non-abstract type that has accessible constructors</summary> |
|
/// <example>new *expr*();</example> |
|
/// <remarks>When using this context, a resolver should treat the expression as object creation, |
|
/// even when the keyword "new" is not part of the expression.</remarks> |
|
public readonly static ExpressionContext ObjectCreation = new TypeExpressionContext(null, true, true); |
|
|
|
/// <summary>Context expects a type deriving from System.Attribute.</summary> |
|
/// <example>[*expr*()]</example> |
|
/// <remarks>When using this context, a resolver should try resolving typenames with an |
|
/// appended "Attribute" suffix and treat "invocations" of the attribute type as |
|
/// object creation.</remarks> |
|
public readonly static ExpressionContext Attribute = new AttributeExpressionContext(); |
|
|
|
/// <summary>Context expects a type name which has special base type</summary> |
|
/// <param name="baseClass">The class the expression must derive from.</param> |
|
/// <param name="isObjectCreation">Specifies whether classes must be constructable.</param> |
|
/// <example>catch(*expr* ...), using(*expr* ...), throw new *expr*();</example> |
|
public static ExpressionContext TypeDerivingFrom(IReturnType baseType, bool isObjectCreation) |
|
{ |
|
return new TypeExpressionContext(baseType, isObjectCreation, false); |
|
} |
|
|
|
/// <summary>Context expects an interface</summary> |
|
/// <example>interface C : *expr* {}</example> |
|
/// <example>Implements *expr*</example> |
|
public readonly static ExpressionContext Interface = new ClassTypeExpressionContext(ClassType.Interface); |
|
|
|
/// <summary>Context expects a delegate</summary> |
|
/// <example>public event *expr*</example> |
|
public readonly static ExpressionContext DelegateType = new ClassTypeExpressionContext(ClassType.Delegate); |
|
|
|
/// <summary>The context expects a new identifier</summary> |
|
/// <example>class *expr* {}; string *expr*;</example> |
|
public readonly static ExpressionContext IdentifierExpected = new DefaultExpressionContext("IdentifierExpected"); |
|
|
|
/// <summary>The context is outside of any type declaration, expecting a global-level keyword.</summary> |
|
public readonly static ExpressionContext Global = new DefaultExpressionContext("Global"); |
|
|
|
/// <summary>The context is the body of a type declaration.</summary> |
|
public readonly static ExpressionContext TypeDeclaration = new ExpressionContext.NonStaticTypeExpressionContext("TypeDeclaration", true); |
|
|
|
/// <summary>The context is the body of a method.</summary> |
|
/// <example>void Main () { *expr* }</example> |
|
public readonly static ExpressionContext MethodBody = new ExpressionContext.DefaultExpressionContext("MethodBody"); |
|
#endregion |
|
|
|
#region DefaultExpressionContext |
|
internal sealed class DefaultExpressionContext : ExpressionContext |
|
{ |
|
string name; |
|
|
|
public DefaultExpressionContext(string name) |
|
{ |
|
this.name = name; |
|
} |
|
|
|
public override bool ShowEntry(ICompletionEntry o) |
|
{ |
|
return true; |
|
} |
|
|
|
public override string ToString() |
|
{ |
|
return "[" + GetType().Name + ": " + name + "]"; |
|
} |
|
} |
|
#endregion |
|
|
|
#region NamespaceExpressionContext |
|
sealed class ImportableExpressionContext : ExpressionContext |
|
{ |
|
bool allowImportClasses; |
|
|
|
public ImportableExpressionContext(bool allowImportClasses) |
|
{ |
|
this.allowImportClasses = allowImportClasses; |
|
} |
|
|
|
public override bool ShowEntry(ICompletionEntry o) |
|
{ |
|
if (!(o is IEntity)) |
|
return true; |
|
IClass c = o as IClass; |
|
if (allowImportClasses && c != null) { |
|
return c.HasPublicOrInternalStaticMembers; |
|
} |
|
return false; |
|
} |
|
|
|
public override string ToString() |
|
{ |
|
return "[" + GetType().Name + " AllowImportClasses=" + allowImportClasses.ToString() + "]"; |
|
} |
|
} |
|
#endregion |
|
|
|
#region TypeExpressionContext |
|
sealed class TypeExpressionContext : ExpressionContext |
|
{ |
|
IClass baseClass; |
|
bool isObjectCreation; |
|
|
|
public TypeExpressionContext(IReturnType baseType, bool isObjectCreation, bool readOnly) |
|
{ |
|
if (baseType != null) |
|
baseClass = baseType.GetUnderlyingClass(); |
|
this.isObjectCreation = isObjectCreation; |
|
this.readOnly = readOnly; |
|
} |
|
|
|
public override bool ShowEntry(ICompletionEntry o) |
|
{ |
|
if (!(o is IEntity)) |
|
return true; |
|
IClass c = o as IClass; |
|
if (c == null) |
|
return false; |
|
if (isObjectCreation) { |
|
if (c.IsAbstract || c.IsStatic) return false; |
|
if (c.ClassType == ClassType.Enum || c.ClassType == ClassType.Interface) |
|
return false; |
|
} |
|
if (baseClass == null) |
|
return true; |
|
return c.IsTypeInInheritanceTree(baseClass); |
|
} |
|
|
|
public override bool IsObjectCreation { |
|
get { |
|
return isObjectCreation; |
|
} |
|
set { |
|
if (readOnly && value != isObjectCreation) |
|
throw new NotSupportedException(); |
|
isObjectCreation = value; |
|
} |
|
} |
|
|
|
public override bool IsTypeContext { |
|
get { return true; } |
|
} |
|
|
|
public override string ToString() |
|
{ |
|
if (baseClass != null) |
|
return "[" + GetType().Name + ": " + baseClass.FullyQualifiedName |
|
+ " IsObjectCreation=" + IsObjectCreation + "]"; |
|
else |
|
return "[" + GetType().Name + " IsObjectCreation=" + IsObjectCreation + "]"; |
|
} |
|
|
|
public override bool Equals(object obj) |
|
{ |
|
TypeExpressionContext o = obj as TypeExpressionContext; |
|
return o != null && object.Equals(baseClass, o.baseClass) && IsObjectCreation == o.IsObjectCreation; |
|
} |
|
|
|
public override int GetHashCode() |
|
{ |
|
return ((baseClass != null) ? baseClass.GetHashCode() : 0) |
|
^ isObjectCreation.GetHashCode(); |
|
} |
|
} |
|
#endregion |
|
|
|
#region CombinedExpressionContext |
|
public static ExpressionContext operator | (ExpressionContext a, ExpressionContext b) |
|
{ |
|
return new CombinedExpressionContext(0, a, b); |
|
} |
|
|
|
public static ExpressionContext operator & (ExpressionContext a, ExpressionContext b) |
|
{ |
|
return new CombinedExpressionContext(1, a, b); |
|
} |
|
|
|
public static ExpressionContext operator ^ (ExpressionContext a, ExpressionContext b) |
|
{ |
|
return new CombinedExpressionContext(2, a, b); |
|
} |
|
|
|
sealed class CombinedExpressionContext : ExpressionContext |
|
{ |
|
byte opType; // 0 = or ; 1 = and ; 2 = xor |
|
ExpressionContext a; |
|
ExpressionContext b; |
|
|
|
public CombinedExpressionContext(byte opType, ExpressionContext a, ExpressionContext b) |
|
{ |
|
if (a == null) |
|
throw new ArgumentNullException("a"); |
|
if (b == null) |
|
throw new ArgumentNullException("a"); |
|
this.opType = opType; |
|
this.a = a; |
|
this.b = b; |
|
} |
|
|
|
public override bool ShowEntry(ICompletionEntry o) |
|
{ |
|
if (opType == 0) |
|
return a.ShowEntry(o) || b.ShowEntry(o); |
|
else if (opType == 1) |
|
return a.ShowEntry(o) && b.ShowEntry(o); |
|
else |
|
return a.ShowEntry(o) ^ b.ShowEntry(o); |
|
} |
|
|
|
public override string ToString() |
|
{ |
|
string op; |
|
if (opType == 0) |
|
op = " OR "; |
|
else if (opType == 1) |
|
op = " AND "; |
|
else |
|
op = " XOR "; |
|
return "[" + GetType().Name + ": " + a + op + b + "]"; |
|
} |
|
|
|
public override int GetHashCode() |
|
{ |
|
int hashCode = 0; |
|
unchecked { |
|
hashCode += opType.GetHashCode(); |
|
if (a != null) hashCode += a.GetHashCode() * 3; |
|
if (b != null) hashCode += b.GetHashCode() * 181247123; |
|
} |
|
return hashCode; |
|
} |
|
|
|
public override bool Equals(object obj) |
|
{ |
|
CombinedExpressionContext cec = obj as CombinedExpressionContext; |
|
return cec != null && this.opType == cec.opType && object.Equals(this.a, cec.a) && object.Equals(this.b, cec.b); |
|
} |
|
} |
|
#endregion |
|
|
|
#region EnumBaseTypeExpressionContext |
|
sealed class EnumBaseTypeExpressionContext : ExpressionContext |
|
{ |
|
public override bool ShowEntry(ICompletionEntry o) |
|
{ |
|
IClass c = o as IClass; |
|
if (c != null) { |
|
// use this hack to show dummy classes like "short" |
|
// (go from the dummy class to the real class) |
|
if (c.Methods.Count > 0) { |
|
c = c.Methods[0].DeclaringType; |
|
} |
|
switch (c.FullyQualifiedName) { |
|
case "System.Byte": |
|
case "System.SByte": |
|
case "System.Int16": |
|
case "System.UInt16": |
|
case "System.Int32": |
|
case "System.UInt32": |
|
case "System.Int64": |
|
case "System.UInt64": |
|
return true; |
|
default: |
|
return false; |
|
} |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
public override string ToString() |
|
{ |
|
return "[" + GetType().Name + "]"; |
|
} |
|
} |
|
#endregion |
|
|
|
#region AttributeExpressionContext |
|
sealed class AttributeExpressionContext : ExpressionContext |
|
{ |
|
public override bool ShowEntry(ICompletionEntry o) |
|
{ |
|
if (!(o is IEntity)) |
|
return true; |
|
IClass c = o as IClass; |
|
if (c != null && !c.IsAbstract) { |
|
return c.IsTypeInInheritanceTree(c.ProjectContent.SystemTypes.Attribute.GetUnderlyingClass()); |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
public override bool IsTypeContext { |
|
get { return true; } |
|
} |
|
|
|
public override string ToString() |
|
{ |
|
return "[" + GetType().Name + "]"; |
|
} |
|
} |
|
#endregion |
|
|
|
#region InheritableTypeExpressionContext |
|
sealed class InheritableTypeExpressionContext : ExpressionContext |
|
{ |
|
public override bool ShowEntry(ICompletionEntry o) |
|
{ |
|
if (!(o is IEntity)) return true; |
|
IClass c = o as IClass; |
|
if (c != null) { |
|
foreach (IClass innerClass in c.InnerClasses) { |
|
if (ShowEntry(innerClass)) return true; |
|
} |
|
if (c.ClassType == ClassType.Interface) return true; |
|
if (c.ClassType == ClassType.Class) { |
|
if (!c.IsSealed && !c.IsStatic) return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
public override string ToString() |
|
{ |
|
return "[" + GetType().Name + "]"; |
|
} |
|
} |
|
#endregion |
|
|
|
#region ClassTypeExpressionContext |
|
sealed class ClassTypeExpressionContext : ExpressionContext |
|
{ |
|
readonly ClassType expectedType; |
|
|
|
public ClassTypeExpressionContext(ClassType expectedType) |
|
{ |
|
this.expectedType = expectedType; |
|
} |
|
|
|
public override bool ShowEntry(ICompletionEntry o) |
|
{ |
|
if (!(o is IEntity)) return true; |
|
IClass c = o as IClass; |
|
if (c != null) { |
|
foreach (IClass innerClass in c.InnerClasses) { |
|
if (ShowEntry(innerClass)) return true; |
|
} |
|
if (c.ClassType == expectedType) return true; |
|
} |
|
return false; |
|
} |
|
|
|
public override string ToString() |
|
{ |
|
return "[" + GetType().Name + " expectedType=" + expectedType.ToString() + "]"; |
|
} |
|
} |
|
#endregion |
|
|
|
#region NonStaticTypeExpressionContext |
|
internal sealed class NonStaticTypeExpressionContext : ExpressionContext |
|
{ |
|
string name; |
|
bool allowVoid; |
|
|
|
public NonStaticTypeExpressionContext(string name, bool allowVoid) |
|
{ |
|
this.name = name; |
|
this.allowVoid = allowVoid; |
|
} |
|
|
|
public override bool ShowEntry(ICompletionEntry o) |
|
{ |
|
if (!(o is IEntity)) return true; |
|
IClass c = o as IClass; |
|
if (c != null) { |
|
if (!allowVoid) { |
|
if (c.FullyQualifiedName == "System.Void" || c.FullyQualifiedName == "void") return false; |
|
} |
|
|
|
foreach (IClass innerClass in c.InnerClasses) { |
|
if (ShowEntry(innerClass)) return true; |
|
} |
|
if (!c.IsStatic && c.ClassType != ClassType.Module) return true; |
|
} |
|
return false; |
|
} |
|
|
|
public override string ToString() |
|
{ |
|
return "[" + GetType().Name + " " + name + "]"; |
|
} |
|
} |
|
#endregion |
|
} |
|
}
|
|
|