// 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;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace ICSharpCode.SharpDevelop.Dom
{
///
/// Provides static methods that fill a list of completion results with entries
/// reachable from a certain calling class/member or entries that introduced
/// by a certain Using statement.
///
public class CtrlSpaceResolveHelper
{
static void AddTypeParametersForCtrlSpace(List result, IEnumerable typeParameters)
{
foreach (ITypeParameter p in typeParameters) {
DefaultClass c = DefaultTypeParameter.GetDummyClassForTypeParameter(p);
if (p.Method != null) {
c.Documentation = "Type parameter of " + p.Method.Name;
} else {
c.Documentation = "Type parameter of " + p.Class.Name;
}
result.Add(c);
}
}
public static void AddContentsFromCalling(List result, IClass callingClass, IMember callingMember)
{
IMethodOrProperty methodOrProperty = callingMember as IMethodOrProperty;
if (methodOrProperty != null) {
foreach (IParameter p in methodOrProperty.Parameters) {
result.Add(new DefaultField.ParameterField(p.ReturnType, p.Name, methodOrProperty.Region, callingClass));
}
if (callingMember is IMethod) {
AddTypeParametersForCtrlSpace(result, ((IMethod)callingMember).TypeParameters);
}
}
bool inStatic = false;
if (callingMember != null)
inStatic = callingMember.IsStatic;
if (callingClass != null) {
AddTypeParametersForCtrlSpace(result, callingClass.TypeParameters);
List members = new List();
IReturnType t = callingClass.DefaultReturnType;
var language = callingClass.ProjectContent.Language;
foreach (IMember m in MemberLookupHelper.GetAccessibleMembers(t, callingClass, language, true)) {
if ((!inStatic || m.IsStatic) && language.ShowMember(m, m.IsStatic))
result.Add(m);
}
members.Clear();
IClass c = callingClass.DeclaringType;
while (c != null) {
t = c.DefaultReturnType;
foreach (IMember m in MemberLookupHelper.GetAccessibleMembers(t, c, language, true)) {
if (language.ShowMember(m, true))
result.Add(m);
}
c = c.DeclaringType;
}
}
}
///
/// Adds contents of all assemblies referenced by 's project.
/// Also adds contents of .
///
public static void AddReferencedProjectsContents(List result, ICompilationUnit cu, IClass callingClass)
{
IProjectContent projectContent = cu.ProjectContent;
projectContent.AddNamespaceContents(result, "", projectContent.Language, true);
var allContents = projectContent.GetAllContents();
result.Capacity = result.Count + allContents.Count;
foreach (var entry in allContents.Where(e => !(e is NamespaceEntry))) {
result.Add(entry);
}
AddUsing(result, projectContent.DefaultImports, projectContent);
AddContentsFromCallingClass(result, projectContent, callingClass);
}
///
/// Adds contents of all namespaces that this imports to the list.
/// Also adds contents of .
///
public static void AddImportedNamespaceContents(List result, ICompilationUnit cu, IClass callingClass)
{
IProjectContent projectContent = cu.ProjectContent;
projectContent.AddNamespaceContents(result, "", projectContent.Language, true);
IUsingScope scope = (callingClass != null) ? callingClass.UsingScope : cu.UsingScope;
while (scope != null) {
foreach (IUsing u in scope.Usings)
AddUsing(result, u, projectContent);
scope = scope.Parent;
}
AddUsing(result, projectContent.DefaultImports, projectContent);
AddContentsFromCallingClass(result, projectContent, callingClass);
}
static void AddContentsFromCallingClass(List result, IProjectContent projectContent, IClass callingClass)
{
if (callingClass == null) {
return;
}
// use HashSet so that Contains lookups are possible in O(1).
HashSet existingResults = new HashSet(result);
string[] namespaceParts = callingClass.Namespace.Split('.');
for (int i = 1; i <= namespaceParts.Length; i++) {
foreach (ICompletionEntry member in projectContent.GetNamespaceContents(string.Join(".", namespaceParts, 0, i))) {
if (!existingResults.Contains(member))
result.Add(member);
}
}
IClass currentClass = callingClass;
do {
foreach (IClass innerClass in currentClass.GetCompoundClass().GetAccessibleTypes(currentClass)) {
if (!existingResults.Contains(innerClass))
result.Add(innerClass);
}
currentClass = currentClass.DeclaringType;
} while (currentClass != null);
}
public static void AddUsing(List result, IUsing u, IProjectContent projectContent)
{
if (u == null) {
return;
}
bool importNamespaces = projectContent.Language.ImportNamespaces;
bool importClasses = projectContent.Language.CanImportClasses;
foreach (string name in u.Usings) {
if (importClasses) {
IClass c = projectContent.GetClass(name, 0);
if (c != null) {
ArrayList members = new ArrayList();
IReturnType t = c.DefaultReturnType;
members.AddRange(t.GetMethods());
members.AddRange(t.GetFields());
members.AddRange(t.GetEvents());
members.AddRange(t.GetProperties());
foreach (IMember m in members) {
if (m.IsStatic && m.IsPublic) {
result.Add(m);
}
}
continue;
}
}
if (importNamespaces) {
string newName = null;
if (projectContent.DefaultImports != null) {
newName = projectContent.DefaultImports.SearchNamespace(name);
}
projectContent.AddNamespaceContents(result, newName ?? name, projectContent.Language, true);
} else {
foreach (ICompletionEntry o in projectContent.GetNamespaceContents(name)) {
if (!(o is NamespaceEntry))
result.Add(o);
}
}
}
if (u.HasAliases) {
foreach (string alias in u.Aliases.Keys) {
result.Add(new AliasEntry(alias));
}
}
}
public class AliasEntry : ICompletionEntry
{
public string Name { get; private set; }
public AliasEntry(string name)
{
if (name == null)
throw new ArgumentNullException("name");
this.Name = name;
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
public override bool Equals(object obj)
{
AliasEntry e = obj as AliasEntry;
return e != null && e.Name == this.Name;
}
public override string ToString()
{
return Name;
}
}
public static ResolveResult GetResultFromDeclarationLine(IClass callingClass, IMethodOrProperty callingMember, int caretLine, int caretColumn, ExpressionResult expressionResult)
{
string expression = expressionResult.Expression;
if (expression == null) return null;
if (callingClass == null) return null;
int pos = expression.IndexOf('(');
if (pos >= 0) {
expression = expression.Substring(0, pos);
}
expression = expression.Trim();
// if (!callingClass.BodyRegion.IsInside(caretLine, caretColumn)
// && callingClass.ProjectContent.Language.NameComparer.Equals(expression, callingClass.Name))
// {
// return new TypeResolveResult(callingClass, callingMember, callingClass);
// }
if (expressionResult.Context != ExpressionContext.Type) {
if (callingMember != null
&& !callingMember.BodyRegion.IsInside(caretLine, caretColumn)
&& (callingClass.ProjectContent.Language.NameComparer.Equals(expression, callingMember.Name) ||
// For constructor definition, the expression is the constructor name (e.g. "MyClass") but the name of the member is "#ctor"
(callingMember.Name == "#ctor" && callingClass.ProjectContent.Language.NameComparer.Equals(expression, callingClass.Name))
)
)
{
return new MemberResolveResult(callingClass, callingMember, callingMember);
}
}
return null;
}
public static IList FindAllExtensions(LanguageProperties language, IClass callingClass, bool searchInAllNamespaces = false)
{
if (language == null)
throw new ArgumentNullException("language");
if (callingClass == null)
throw new ArgumentNullException("callingClass");
HashSet res = new HashSet();
bool supportsExtensionMethods = language.SupportsExtensionMethods;
bool supportsExtensionProperties = language.SupportsExtensionProperties;
if (supportsExtensionMethods || supportsExtensionProperties) {
List list = new List();
IMethod dummyMethod = new DefaultMethod("dummy", callingClass.ProjectContent.SystemTypes.Void,
ModifierEnum.Static, DomRegion.Empty, DomRegion.Empty, callingClass);
CtrlSpaceResolveHelper.AddContentsFromCalling(list, callingClass, dummyMethod);
if (searchInAllNamespaces) {
// search extension methods in all referenced projects, no matter the using section
CtrlSpaceResolveHelper.AddReferencedProjectsContents(list, callingClass.CompilationUnit, callingClass);
} else {
CtrlSpaceResolveHelper.AddImportedNamespaceContents(list, callingClass.CompilationUnit, callingClass);
}
bool searchExtensionsInClasses = language.SearchExtensionsInClasses;
foreach (object o in list) {
IMethodOrProperty mp = o as IMethodOrProperty;
if (mp != null && mp.IsExtensionMethod &&
(supportsExtensionMethods && o is IMethod || supportsExtensionProperties && o is IProperty))
{
res.Add(mp);
} else if (searchExtensionsInClasses && o is IClass) {
IClass c = o as IClass;
if (c.HasExtensionMethods) {
if (supportsExtensionProperties) {
foreach (IProperty p in c.Properties) {
if (p.IsExtensionMethod)
res.Add(p);
}
}
if (supportsExtensionMethods) {
foreach (IMethod m in c.Methods) {
if (m.IsExtensionMethod)
res.Add(m);
}
}
}
}
}
}
return res.ToList();
} // FindAllExtensions
} // CtrlSpaceResolveHelper class
}