// // 2002-2005 AlphaSierraPapa // GNU General Public License // // $Revision$ // using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using ICSharpCode.SharpDevelop.Project; using ICSharpCode.Core; namespace ICSharpCode.SharpDevelop.Dom { #region ResolveResult /// /// The base class of all resolve results. /// This class is used whenever an expression is not one of the special expressions /// (having their own ResolveResult class). /// The ResolveResult specified the location where Resolve was called (Class+Member) /// and the type of the resolved expression. /// public class ResolveResult { IClass callingClass; IMember callingMember; IReturnType resolvedType; public ResolveResult(IClass callingClass, IMember callingMember, IReturnType resolvedType) { // if (callingMember != null && callingMember.DeclaringType != callingClass) // throw new ArgumentException("callingMember.DeclaringType must be equal to callingClass"); this.callingClass = callingClass; this.callingMember = callingMember; this.resolvedType = resolvedType; } /// /// Gets the class that contained the expression used to get this ResolveResult. /// Can be null when the class is unknown. /// public IClass CallingClass { get { return callingClass; } } /// /// Gets the member (method or property in ) that contained the /// expression used to get this ResolveResult. /// Can be null when the expression was not inside a member or the member is unknown. /// public IMember CallingMember { get { return callingMember; } } /// /// Gets the type of the resolved expression. /// Can be null when the type cannot be represented by a IReturnType (e.g. when the /// expression was a namespace name). /// public IReturnType ResolvedType { get { return resolvedType; } set { resolvedType = value; } } public virtual ArrayList GetCompletionData(IProjectContent projectContent) { return GetCompletionData(projectContent.Language, false); } protected ArrayList GetCompletionData(LanguageProperties language, bool showStatic) { if (resolvedType == null) return null; ArrayList res = new ArrayList(); bool isClassInInheritanceTree = false; if (callingClass != null) isClassInInheritanceTree = callingClass.IsTypeInInheritanceTree(resolvedType.GetUnderlyingClass()); foreach (IMethod m in resolvedType.GetMethods()) { if (language.ShowMember(m, showStatic) && m.IsAccessible(callingClass, isClassInInheritanceTree)) res.Add(m); } foreach (IEvent e in resolvedType.GetEvents()) { if (language.ShowMember(e, showStatic) && e.IsAccessible(callingClass, isClassInInheritanceTree)) res.Add(e); } foreach (IField f in resolvedType.GetFields()) { if (language.ShowMember(f, showStatic) && f.IsAccessible(callingClass, isClassInInheritanceTree)) res.Add(f); } foreach (IProperty p in resolvedType.GetProperties()) { if (language.ShowMember(p, showStatic) && p.IsAccessible(callingClass, isClassInInheritanceTree)) res.Add(p); } return res; } public virtual FilePosition GetDefinitionPosition() { // this is only possible on some subclasses of ResolveResult return null; } } #endregion #region MixedResolveResult /// /// The MixedResolveResult is used when an expression can have multiple meanings, for example /// "Size" in a class deriving from "Control". /// public class MixedResolveResult : ResolveResult { ResolveResult primaryResult, secondaryResult; public ResolveResult PrimaryResult { get { return primaryResult; } } public TypeResolveResult TypeResult { get { if (primaryResult is TypeResolveResult) return (TypeResolveResult)primaryResult; if (secondaryResult is TypeResolveResult) return (TypeResolveResult)secondaryResult; return null; } } public MixedResolveResult(ResolveResult primaryResult, ResolveResult secondaryResult) : base(primaryResult.CallingClass, primaryResult.CallingMember, primaryResult.ResolvedType) { this.primaryResult = primaryResult; this.secondaryResult = secondaryResult; } public override FilePosition GetDefinitionPosition() { return primaryResult.GetDefinitionPosition(); } public override ArrayList GetCompletionData(IProjectContent projectContent) { ArrayList result = primaryResult.GetCompletionData(projectContent); ArrayList result2 = secondaryResult.GetCompletionData(projectContent); if (result == null) return result2; if (result2 == null) return result; foreach (object o in result2) { if (!result.Contains(o)) result.Add(o); } return result; } } #endregion #region LocalResolveResult /// /// The LocalResolveResult is used when an expression was a simple local variable /// or parameter. /// /// /// For fields in the current class, a MemberResolveResult is used, so "e" is not always /// a LocalResolveResult. /// public class LocalResolveResult : ResolveResult { IField field; bool isParameter; public LocalResolveResult(IMember callingMember, IField field) : base(callingMember.DeclaringType, callingMember, field.ReturnType) { if (callingMember == null) throw new ArgumentNullException("callingMember"); if (field == null) throw new ArgumentNullException("field"); this.field = field; this.isParameter = field.IsParameter; if (!isParameter && !field.IsLocalVariable) { throw new ArgumentException("the field must either be a local variable-field or a parameter-field"); } } /// /// Gets the field representing the local variable. /// public IField Field { get { return field; } } /// /// Gets if the variable is a parameter (true) or a local variable (false). /// public bool IsParameter { get { return isParameter; } } public override FilePosition GetDefinitionPosition() { ICompilationUnit cu = this.CallingClass.CompilationUnit; if (cu == null) { return null; } if (cu.FileName == null || cu.FileName.Length == 0) { return null; } DomRegion reg = field.Region; if (!reg.IsEmpty) { return new FilePosition(cu.FileName, new Point(reg.BeginLine, reg.BeginColumn)); } else { LoggingService.Warn("GetDefinitionPosition: field.Region is empty"); return new FilePosition(cu.FileName, Point.Empty); } } } #endregion #region NamespaceResolveResult /// /// The NamespaceResolveResult is used when an expression was the name of a namespace. /// is always null on a NamespaceReturnType. /// /// /// Example expressions: /// "System" /// "System.Windows.Forms" /// "using Win = System.Windows; Win.Forms" /// public class NamespaceResolveResult : ResolveResult { string name; public NamespaceResolveResult(IClass callingClass, IMember callingMember, string name) : base(callingClass, callingMember, null) { if (name == null) throw new ArgumentNullException("name"); this.name = name; } /// /// Gets the name of the namespace. /// public string Name { get { return name; } } public override ArrayList GetCompletionData(IProjectContent projectContent) { return projectContent.GetNamespaceContents(name); } } #endregion #region TypeResolveResult /// /// The TypeResolveResult is used when an expression was the name of a type. /// This resolve result makes code completion show the static members instead /// of the instance members. /// /// /// Example expressions: /// "System.EventArgs" /// "using System; EventArgs" /// public class TypeResolveResult : ResolveResult { IClass resolvedClass; public TypeResolveResult(IClass callingClass, IMember callingMember, IClass resolvedClass) : base(callingClass, callingMember, resolvedClass.DefaultReturnType) { this.resolvedClass = resolvedClass; } public TypeResolveResult(IClass callingClass, IMember callingMember, IReturnType resolvedType, IClass resolvedClass) : base(callingClass, callingMember, resolvedType) { this.resolvedClass = resolvedClass; } public TypeResolveResult(IClass callingClass, IMember callingMember, IReturnType resolvedType) : base(callingClass, callingMember, resolvedType) { this.resolvedClass = resolvedType.GetUnderlyingClass(); } /// /// Gets the class corresponding to the resolved type. /// This property can be null when the type has no class (for example a type parameter). /// public IClass ResolvedClass { get { return resolvedClass; } } public override ArrayList GetCompletionData(IProjectContent projectContent) { ArrayList ar = GetCompletionData(projectContent.Language, true); if (resolvedClass != null) { ar.AddRange(resolvedClass.InnerClasses); } return ar; } public override FilePosition GetDefinitionPosition() { if (resolvedClass == null) { return null; } ICompilationUnit cu = resolvedClass.CompilationUnit; if (cu == null || cu.FileName == null || cu.FileName.Length == 0) { return null; } DomRegion reg = resolvedClass.Region; if (!reg.IsEmpty) return new FilePosition(cu.FileName, new Point(reg.BeginLine, reg.BeginColumn)); else return new FilePosition(cu.FileName, Point.Empty); } } #endregion #region MemberResolveResult /// /// The TypeResolveResult is used when an expression was a member /// (field, property, event or method call). /// /// /// Example expressions: /// "(any expression).fieldName" /// "(any expression).eventName" /// "(any expression).propertyName" /// "(any expression).methodName(arguments)" (methods only when method parameters are part of expression) /// "using System; EventArgs.Empty" /// "fieldName" (when fieldName is a field in the current class) /// "new System.Windows.Forms.Button()" (constructors are also methods) /// "SomeMethod()" (when SomeMethod is a method in the current class) /// "System.Console.WriteLine(text)" /// public class MemberResolveResult : ResolveResult { IMember resolvedMember; public MemberResolveResult(IClass callingClass, IMember callingMember, IMember resolvedMember) : base(callingClass, callingMember, resolvedMember.ReturnType) { if (resolvedMember == null) throw new ArgumentNullException("resolvedMember"); this.resolvedMember = resolvedMember; } /// /// Gets the member that was resolved. /// public IMember ResolvedMember { get { return resolvedMember; } } public override FilePosition GetDefinitionPosition() { return GetDefinitionPosition(resolvedMember); } public static FilePosition GetDefinitionPosition(IMember resolvedMember) { IClass declaringType = resolvedMember.DeclaringType; if (declaringType == null) { return null; } ICompilationUnit cu = declaringType.CompilationUnit; if (cu == null) { return null; } if (cu.FileName == null || cu.FileName.Length == 0) { return null; } DomRegion reg = resolvedMember.Region; if (!reg.IsEmpty) return new FilePosition(cu.FileName, new Point(reg.BeginLine, reg.BeginColumn)); else return new FilePosition(cu.FileName, Point.Empty); } } #endregion #region MethodResolveResult /// /// The MethodResolveResult is used when an expression was the name of a method, /// but there were no parameters specified so the exact overload could not be found. /// is always null on a MethodReturnType. /// /// /// Example expressions: /// "System.Console.WriteLine" /// "a.Add" (where a is List<string>) /// "SomeMethod" (when SomeMethod is a method in the current class) /// public class MethodResolveResult : ResolveResult { string name; IReturnType containingType; public MethodResolveResult(IClass callingClass, IMember callingMember, IReturnType containingType, string name) : base(callingClass, callingMember, null) { if (containingType == null) throw new ArgumentNullException("containingType"); if (name == null) throw new ArgumentNullException("name"); this.containingType = containingType; this.name = name; } /// /// Gets the name of the method. /// public string Name { get { return name; } } /// /// Gets the class that contains the method. /// public IReturnType ContainingType { get { return containingType; } } public IMethod GetMethodIfSingleOverload() { List methods = containingType.GetMethods(); methods = methods.FindAll(delegate(IMethod m) { return m.Name == this.Name; }); if (methods.Count == 1) return methods[0]; else return null; } public override FilePosition GetDefinitionPosition() { IMethod m = GetMethodIfSingleOverload(); if (m != null) return MemberResolveResult.GetDefinitionPosition(m); else return base.GetDefinitionPosition(); } } #endregion }