Browse Source

Add code completion support for extension methods in Boo.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@664 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 20 years ago
parent
commit
67ddfc9230
  1. 6
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/BooLanguageProperties.cs
  2. 3
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ConvertVisitor.cs
  3. 24
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs
  4. 4
      src/Main/Base/Project/Src/Dom/IMethod.cs
  5. 10
      src/Main/Base/Project/Src/Dom/Implementations/DefaultClass.cs
  6. 12
      src/Main/Base/Project/Src/Dom/Implementations/DefaultMethod.cs
  7. 12
      src/Main/Base/Project/Src/Dom/Implementations/DefaultProperty.cs
  8. 46
      src/Main/Base/Project/Src/Dom/LanguageProperties.cs
  9. 11
      src/Main/Base/Project/Src/Dom/ReflectionLayer/DomPersistence.cs
  10. 70
      src/Main/Base/Project/Src/Dom/ResolveResult.cs
  11. 17
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/MethodInsightDataProvider.cs

6
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/BooLanguageProperties.cs

@ -16,7 +16,11 @@ namespace Grunwald.BooBinding @@ -16,7 +16,11 @@ namespace Grunwald.BooBinding
public BooLanguageProperties() : base(StringComparer.InvariantCulture, BooCodeGenerator.Instance) {}
public override bool SupportsExtensionMethods {
get {
return true;
}
}
public override bool ImportNamespaces {
get {

3
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ConvertVisitor.cs

@ -366,6 +366,9 @@ namespace Grunwald.BooBinding.CodeCompletion @@ -366,6 +366,9 @@ namespace Grunwald.BooBinding.CodeCompletion
{
//LoggingService.Debug("Method: " + node.FullName);
DefaultMethod method = new DefaultMethod(node.Name, null, GetModifier(node), GetRegion(node), GetClientRegion(node), OuterClass);
if ((node.ImplementationFlags & AST.MethodImplementationFlags.Extension) == AST.MethodImplementationFlags.Extension) {
method.IsExtensionMethod = true;
}
ConvertAttributes(node, method);
ConvertTemplates(node, method);
// return type must be assign AFTER ConvertTemplates

24
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs

@ -277,6 +277,19 @@ namespace Grunwald.BooBinding.CodeCompletion @@ -277,6 +277,19 @@ namespace Grunwald.BooBinding.CodeCompletion
return true;
}
}
if (callingClass != null) {
ArrayList list = new ArrayList();
ResolveResult.AddExtensions(callingClass.ProjectContent.Language, list, callingClass, type);
foreach (IMethodOrProperty mp in list) {
if (IsSameName(mp.Name, memberName)) {
if (mp is IMethod)
MakeMethodResult(type, memberName);
else
MakeResult(mp);
return true;
}
}
}
return false;
}
#endregion
@ -377,6 +390,17 @@ namespace Grunwald.BooBinding.CodeCompletion @@ -377,6 +390,17 @@ namespace Grunwald.BooBinding.CodeCompletion
methods.Add(m);
}
}
if (methods.Count == 0) {
ArrayList list = new ArrayList();
ResolveResult.AddExtensions(callingClass.ProjectContent.Language, list, callingClass, containingType);
foreach (IMethodOrProperty mp in list) {
if (IsSameName(mp.Name, methodName) && mp is IMethod) {
IMethod m = (IMethod)mp.Clone();
m.Parameters.RemoveAt(0);
methods.Add(m);
}
}
}
ResolveInvocation(methods, arguments);
}

4
src/Main/Base/Project/Src/Dom/IMethod.cs

@ -20,6 +20,10 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -20,6 +20,10 @@ namespace ICSharpCode.SharpDevelop.Dom
IList<IParameter> Parameters {
get;
}
bool IsExtensionMethod {
get;
}
}
public interface IMethod : IMethodOrProperty

10
src/Main/Base/Project/Src/Dom/Implementations/DefaultClass.cs

@ -44,15 +44,21 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -44,15 +44,21 @@ namespace ICSharpCode.SharpDevelop.Dom
flags |= hasPublicOrInternalStaticMembersFlag;
}
}
foreach (IMember m in this.Properties) {
foreach (IProperty m in this.Properties) {
if (m.IsStatic && (m.IsPublic || m.IsInternal)) {
flags |= hasPublicOrInternalStaticMembersFlag;
}
if (m.IsExtensionMethod) {
flags |= hasExtensionMethodsFlag;
}
}
foreach (IMember m in this.Methods) {
foreach (IMethod m in this.Methods) {
if (m.IsStatic && (m.IsPublic || m.IsInternal)) {
flags |= hasPublicOrInternalStaticMembersFlag;
}
if (m.IsExtensionMethod) {
flags |= hasExtensionMethodsFlag;
}
}
foreach (IMember m in this.Events) {
if (m.IsStatic && (m.IsPublic || m.IsInternal)) {

12
src/Main/Base/Project/Src/Dom/Implementations/DefaultMethod.cs

@ -56,12 +56,24 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -56,12 +56,24 @@ namespace ICSharpCode.SharpDevelop.Dom
IList<IParameter> parameters = null;
IList<ITypeParameter> typeParameters = null;
bool isExtensionMethod;
public bool IsExtensionMethod {
get {
return isExtensionMethod;
}
set {
isExtensionMethod = value;
}
}
public override IMember Clone()
{
DefaultMethod p = new DefaultMethod(Name, ReturnType, Modifiers, Region, BodyRegion, DeclaringType);
p.parameters = DefaultParameter.Clone(this.Parameters);
p.typeParameters = this.typeParameters;
p.documentationTag = DocumentationTag;
p.isExtensionMethod = this.isExtensionMethod;
return p;
}

12
src/Main/Base/Project/Src/Dom/Implementations/DefaultProperty.cs

@ -20,9 +20,10 @@ namespace ICSharpCode.SharpDevelop.Dom { @@ -20,9 +20,10 @@ namespace ICSharpCode.SharpDevelop.Dom {
IList<IParameter> parameters = null;
internal byte accessFlags;
const byte indexerFlag = 1;
const byte getterFlag = 2;
const byte setterFlag = 4;
const byte indexerFlag = 0x01;
const byte getterFlag = 0x02;
const byte setterFlag = 0x04;
const byte extensionFlag = 0x08;
public bool IsIndexer {
get { return (accessFlags & indexerFlag) == indexerFlag; }
@ -39,6 +40,11 @@ namespace ICSharpCode.SharpDevelop.Dom { @@ -39,6 +40,11 @@ namespace ICSharpCode.SharpDevelop.Dom {
set { if (value) accessFlags |= setterFlag; else accessFlags &= 255-setterFlag; }
}
public bool IsExtensionMethod {
get { return (accessFlags & extensionFlag) == extensionFlag; }
set { if (value) accessFlags |= extensionFlag; else accessFlags &= 255-extensionFlag; }
}
public override string DocumentationTag {
get {
return "P:" + this.DotNetName;

46
src/Main/Base/Project/Src/Dom/LanguageProperties.cs

@ -12,7 +12,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -12,7 +12,7 @@ namespace ICSharpCode.SharpDevelop.Dom
{
public class LanguageProperties
{
public readonly static LanguageProperties CSharp = new LanguageProperties(StringComparer.InvariantCulture, CSharpCodeGenerator.Instance);
public readonly static LanguageProperties CSharp = new CSharpProperties();
public readonly static LanguageProperties VBNet = new VBNetProperties();
StringComparer nameComparer;
@ -37,6 +37,37 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -37,6 +37,37 @@ namespace ICSharpCode.SharpDevelop.Dom
}
}
/// <summary>
/// Gets if the language supports calling C# 3-style extension methods
/// (first parameter = instance parameter)
/// </summary>
public virtual bool SupportsExtensionMethods {
get {
return false;
}
}
/// <summary>
/// Gets if the language supports calling extension properties
/// (first parameter = instance parameter)
/// </summary>
public virtual bool SupportsExtensionProperties {
get {
return false;
}
}
/// <summary>
/// Gets if extension methods/properties are searched in imported classes (returns true) or if
/// only the extensions from the current class, imported classes and imported modules are used
/// (returns false). This property has no effect if the language doesn't support
/// </summary>
public virtual bool SearchExtensionsInClasses {
get {
return false;
}
}
/// <summary>
/// Gets if namespaces can be imported (i.e. Imports System, Dim a As Collections.ArrayList)
/// </summary>
@ -89,10 +120,17 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -89,10 +120,17 @@ namespace ICSharpCode.SharpDevelop.Dom
public override string ToString()
{
if (GetType() == typeof(LanguageProperties) && nameComparer == StringComparer.InvariantCulture)
return "[" + base.ToString() + "]";
}
private class CSharpProperties : LanguageProperties
{
public CSharpProperties() : base(StringComparer.InvariantCulture, CSharpCodeGenerator.Instance) {}
public override string ToString()
{
return "[LanguageProperties: C#]";
else
return "[" + base.ToString() + "]";
}
}
private class VBNetProperties : LanguageProperties

11
src/Main/Base/Project/Src/Dom/ReflectionLayer/DomPersistence.cs

@ -21,7 +21,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -21,7 +21,7 @@ namespace ICSharpCode.SharpDevelop.Dom
{
public const long FileMagic = 0x11635233ED2F428C;
public const long IndexFileMagic = 0x11635233ED2F427D;
public const short FileVersion = 5;
public const short FileVersion = 6;
#region Cache management
#if DEBUG
@ -747,6 +747,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -747,6 +747,7 @@ namespace ICSharpCode.SharpDevelop.Dom
WriteMember(m);
WriteTemplates(m.TypeParameters);
WriteType(m.ReturnType);
writer.Write(m.IsExtensionMethod);
WriteParameters(m.Parameters);
currentMethod = null;
}
@ -771,6 +772,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -771,6 +772,7 @@ namespace ICSharpCode.SharpDevelop.Dom
m.TypeParameters = DefaultTypeParameter.EmptyTypeParameterList;
}
m.ReturnType = ReadType();
m.IsExtensionMethod = reader.ReadBoolean();
ReadParameters(m);
currentMethod = null;
return m;
@ -781,7 +783,12 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -781,7 +783,12 @@ namespace ICSharpCode.SharpDevelop.Dom
void WriteProperty(IProperty p)
{
WriteMember(p);
writer.Write(((DefaultProperty)p).accessFlags);
DefaultProperty dp = p as DefaultProperty;
if (dp != null) {
writer.Write(dp.accessFlags);
} else {
writer.Write((byte)0);
}
WriteParameters(p.Parameters);
}

70
src/Main/Base/Project/Src/Dom/ResolveResult.cs

@ -102,9 +102,79 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -102,9 +102,79 @@ namespace ICSharpCode.SharpDevelop.Dom
if (language.ShowMember(p, showStatic) && p.IsAccessible(callingClass, isClassInInheritanceTree))
res.Add(p);
}
if (!showStatic && callingClass != null) {
AddExtensions(language, res, callingClass, resolvedType);
}
return res;
}
/// <summary>
/// Adds extension methods to <paramref name="res"/>.
/// </summary>
public static void AddExtensions(LanguageProperties language, ArrayList res, IClass callingClass, IReturnType resolvedType)
{
if (language == null)
throw new ArgumentNullException("language");
if (res == null)
throw new ArgumentNullException("res");
if (callingClass == null)
throw new ArgumentNullException("callingClass");
if (resolvedType == null)
throw new ArgumentNullException("resolvedType");
bool supportsExtensionMethods = language.SupportsExtensionMethods;
bool supportsExtensionProperties = language.SupportsExtensionProperties;
if (supportsExtensionMethods || supportsExtensionProperties) {
ArrayList list = new ArrayList();
IMethod dummyMethod = new DefaultMethod("dummy", ReflectionReturnType.Void, ModifierEnum.Static, DomRegion.Empty, DomRegion.Empty, callingClass);
NRefactoryResolver.NRefactoryResolver.AddContentsFromCalling(list, callingClass, dummyMethod);
bool searchExtensionsInClasses = language.SearchExtensionsInClasses;
foreach (object o in list) {
if (supportsExtensionMethods && o is IMethod || supportsExtensionProperties && o is IProperty) {
TryAddExtension(language, res, o as IMethodOrProperty, resolvedType);
} else if (searchExtensionsInClasses && o is IClass) {
IClass c = o as IClass;
if (c.HasExtensionMethods) {
if (supportsExtensionMethods) {
foreach (IProperty p in c.Properties) {
TryAddExtension(language, res, p, resolvedType);
}
}
if (supportsExtensionProperties) {
foreach (IMethod m in c.Methods) {
TryAddExtension(language, res, m, resolvedType);
}
}
}
}
}
}
}
static void TryAddExtension(LanguageProperties language, ArrayList res, IMethodOrProperty ext, IReturnType resolvedType)
{
// accept only extension methods
if (!ext.IsExtensionMethod)
return;
// don't add extension if method with that name already exists
// but allow overloading extension methods
foreach (IMember member in res) {
IMethodOrProperty p = member as IMethodOrProperty;
if (p != null && p.IsExtensionMethod)
continue;
if (language.NameComparer.Equals(member.Name, ext.Name)) {
return;
}
}
// now add the extension method if it fits the type
if (MemberLookupHelper.ConversionExists(resolvedType, ext.Parameters[0].ReturnType)) {
res.Add(ext);
}
}
public virtual FilePosition GetDefinitionPosition()
{
// this is only possible on some subclasses of ResolveResult

17
src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/MethodInsightDataProvider.cs

@ -134,8 +134,9 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -134,8 +134,9 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
}
ResolveResult results = ParserService.Resolve(expressionResult, caretLineNumber, caretColumn, fileName, document.TextContent);
TypeResolveResult trr = results as TypeResolveResult;
LanguageProperties language = ParserService.CurrentProjectContent.Language;
if (trr != null && !constructorInsight) {
if (ParserService.CurrentProjectContent.Language.AllowObjectConstructionOutsideContext)
if (language.AllowObjectConstructionOutsideContext)
constructorInsight = true;
}
if (constructorInsight) {
@ -155,17 +156,27 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -155,17 +156,27 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
MethodResolveResult result = results as MethodResolveResult;
if (result == null)
return;
IProjectContent p = ParserService.CurrentProjectContent;
bool classIsInInheritanceTree = false;
if (result.CallingClass != null)
classIsInInheritanceTree = result.CallingClass.IsTypeInInheritanceTree(result.ContainingType.GetUnderlyingClass());
foreach (IMethod method in result.ContainingType.GetMethods()) {
if (p.Language.NameComparer.Equals(method.Name, result.Name)) {
if (language.NameComparer.Equals(method.Name, result.Name)) {
if (method.IsAccessible(result.CallingClass, classIsInInheritanceTree)) {
methods.Add(method);
}
}
}
if (methods.Count == 0 && result.CallingClass != null && language.SupportsExtensionMethods) {
ArrayList list = new ArrayList();
ResolveResult.AddExtensions(language, list, result.CallingClass, result.ContainingType);
foreach (IMethodOrProperty mp in list) {
if (language.NameComparer.Equals(mp.Name, result.Name) && mp is IMethod) {
IMethod m = (IMethod)mp.Clone();
m.Parameters.RemoveAt(0);
methods.Add(m);
}
}
}
}
}

Loading…
Cancel
Save