Skip to content

Commit

Permalink
Merge pull request #1030 from akshita31/base_class_func
Browse files Browse the repository at this point in the history
Intellisense not showing methods from the Base class in Signature Help
  • Loading branch information
DustinCampbell authored Dec 8, 2017
2 parents 099a2c1 + fbc4c5f commit eae75dc
Show file tree
Hide file tree
Showing 5 changed files with 489 additions and 56 deletions.
1 change: 1 addition & 0 deletions build/Settings.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<PropertyGroup>
<LangVersion>7.1</LangVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Adapted from https://github.com/dotnet/roslyn/blob/master/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace OmniSharp.Roslyn.CSharp.Services.Signatures
{
//TO DO: Remove this class once a public API for Signature Help from Roslyn is available
internal static class CheckForStaticExtension
{
public static bool IsInStaticContext(this SyntaxNode node)
{
// this/base calls are always static.
if (node.FirstAncestorOrSelf<ConstructorInitializerSyntax>() != null)
{
return true;
}

var memberDeclaration = node.FirstAncestorOrSelf<MemberDeclarationSyntax>();
if (memberDeclaration == null)
{
return false;
}

switch (memberDeclaration.Kind())
{
case SyntaxKind.MethodDeclaration:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.EventDeclaration:
case SyntaxKind.IndexerDeclaration:
return GetModifiers(memberDeclaration).Any(SyntaxKind.StaticKeyword);

case SyntaxKind.PropertyDeclaration:
return GetModifiers(memberDeclaration).Any(SyntaxKind.StaticKeyword) ||
node.IsFoundUnder((PropertyDeclarationSyntax p) => p.Initializer);

case SyntaxKind.FieldDeclaration:
case SyntaxKind.EventFieldDeclaration:
// Inside a field one can only access static members of a type (unless it's top-level).
return !memberDeclaration.Parent.IsKind(SyntaxKind.CompilationUnit);

case SyntaxKind.DestructorDeclaration:
return false;
}

// Global statements are not a static context.
if (node.FirstAncestorOrSelf<GlobalStatementSyntax>() != null)
{
return false;
}

// any other location is considered static
return true;
}

public static SyntaxTokenList GetModifiers(SyntaxNode member)
{
if (member != null)
{
switch (member.Kind())
{
case SyntaxKind.EnumDeclaration:
return ((EnumDeclarationSyntax)member).Modifiers;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.StructDeclaration:
return ((TypeDeclarationSyntax)member).Modifiers;
case SyntaxKind.DelegateDeclaration:
return ((DelegateDeclarationSyntax)member).Modifiers;
case SyntaxKind.FieldDeclaration:
return ((FieldDeclarationSyntax)member).Modifiers;
case SyntaxKind.EventFieldDeclaration:
return ((EventFieldDeclarationSyntax)member).Modifiers;
case SyntaxKind.ConstructorDeclaration:
return ((ConstructorDeclarationSyntax)member).Modifiers;
case SyntaxKind.DestructorDeclaration:
return ((DestructorDeclarationSyntax)member).Modifiers;
case SyntaxKind.PropertyDeclaration:
return ((PropertyDeclarationSyntax)member).Modifiers;
case SyntaxKind.EventDeclaration:
return ((EventDeclarationSyntax)member).Modifiers;
case SyntaxKind.IndexerDeclaration:
return ((IndexerDeclarationSyntax)member).Modifiers;
case SyntaxKind.OperatorDeclaration:
return ((OperatorDeclarationSyntax)member).Modifiers;
case SyntaxKind.ConversionOperatorDeclaration:
return ((ConversionOperatorDeclarationSyntax)member).Modifiers;
case SyntaxKind.MethodDeclaration:
return ((MethodDeclarationSyntax)member).Modifiers;
case SyntaxKind.GetAccessorDeclaration:
case SyntaxKind.SetAccessorDeclaration:
case SyntaxKind.AddAccessorDeclaration:
case SyntaxKind.RemoveAccessorDeclaration:
return ((AccessorDeclarationSyntax)member).Modifiers;
}
}

return default;
}

public static bool IsFoundUnder<TParent>(this SyntaxNode node, Func<TParent, SyntaxNode> childGetter)
where TParent : SyntaxNode
{
var ancestor = node.GetAncestor<TParent>();
if (ancestor == null)
{
return false;
}

var child = childGetter(ancestor);

// See if node passes through child on the way up to ancestor.
return node.GetAncestorsOrThis<SyntaxNode>().Contains(child);
}

public static TNode GetAncestor<TNode>(this SyntaxNode node)
where TNode : SyntaxNode
{
var current = node.Parent;
while (current != null)
{
if (current is TNode tNode)
{
return tNode;
}

current = current.GetParent();
}

return null;
}

private static SyntaxNode GetParent(this SyntaxNode node)
{
return node is IStructuredTriviaSyntax trivia ? trivia.ParentTrivia.Token.Parent : node.Parent;
}

public static TNode FirstAncestorOrSelfUntil<TNode>(this SyntaxNode node, Func<SyntaxNode, bool> predicate)
where TNode : SyntaxNode
{
for (var current = node; current != null; current = current.GetParent())
{
if (current is TNode tnode)
{
return tnode;
}

if (predicate(current))
{
break;
}
}

return default;
}

public static TNode GetAncestorOrThis<TNode>(this SyntaxNode node)
where TNode : SyntaxNode
{
return node?.GetAncestorsOrThis<TNode>().FirstOrDefault();
}

public static IEnumerable<TNode> GetAncestorsOrThis<TNode>(this SyntaxNode node)
where TNode : SyntaxNode
{
var current = node;
while (current != null)
{
if (current is TNode tNode)
{
yield return tNode;
}

current = current.GetParent();
}
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,26 @@ internal class InvocationContext
public SyntaxNode Receiver { get; }
public IEnumerable<TypeInfo> ArgumentTypes { get; }
public IEnumerable<SyntaxToken> Separators { get; }
public bool IsInStaticContext { get; }

public InvocationContext(SemanticModel semModel, int position, SyntaxNode receiver, ArgumentListSyntax argList)
public InvocationContext(SemanticModel semModel, int position, SyntaxNode receiver, ArgumentListSyntax argList, bool isStatic)
{
SemanticModel = semModel;
Position = position;
Receiver = receiver;
ArgumentTypes = argList.Arguments.Select(argument => semModel.GetTypeInfo(argument.Expression));
Separators = argList.Arguments.GetSeparators();
IsInStaticContext = isStatic;
}

public InvocationContext(SemanticModel semModel, int position, SyntaxNode receiver, AttributeArgumentListSyntax argList)
public InvocationContext(SemanticModel semModel, int position, SyntaxNode receiver, AttributeArgumentListSyntax argList, bool isStatic)
{
SemanticModel = semModel;
Position = position;
Receiver = receiver;
ArgumentTypes = argList.Arguments.Select(argument => semModel.GetTypeInfo(argument.Expression));
Separators = argList.Arguments.GetSeparators();
IsInStaticContext = isStatic;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using OmniSharp.Mef;
Expand Down Expand Up @@ -59,7 +60,24 @@ public async Task<SignatureHelpResponse> Handle(SignatureHelpRequest request)
foreach (var invocation in invocations)
{
var types = invocation.ArgumentTypes;
foreach (var methodOverload in GetMethodOverloads(invocation.SemanticModel, invocation.Receiver))
ISymbol throughSymbol = null;
ISymbol throughType = null;
var methodGroup = invocation.SemanticModel.GetMemberGroup(invocation.Receiver).OfType<IMethodSymbol>();
if (invocation.Receiver is MemberAccessExpressionSyntax)
{
var throughExpression = ((MemberAccessExpressionSyntax)invocation.Receiver).Expression;
throughSymbol = invocation.SemanticModel.GetSpeculativeSymbolInfo(invocation.Position, throughExpression, SpeculativeBindingOption.BindAsExpression).Symbol;
throughType = invocation.SemanticModel.GetSpeculativeTypeInfo(invocation.Position, throughExpression, SpeculativeBindingOption.BindAsTypeOrNamespace).Type;
var includeInstance = throughSymbol != null && !(throughSymbol is ITypeSymbol);
var includeStatic = (throughSymbol is INamedTypeSymbol) || throughType != null;
methodGroup = methodGroup.Where(m => (m.IsStatic && includeStatic) || (!m.IsStatic && includeInstance));
}
else if (invocation.Receiver is SimpleNameSyntax && invocation.IsInStaticContext)
{
methodGroup = methodGroup.Where(m => m.IsStatic);
}

foreach (var methodOverload in methodGroup)
{
var signature = BuildSignature(methodOverload);
signaturesSet.Add(signature);
Expand Down Expand Up @@ -94,19 +112,19 @@ private async Task<InvocationContext> GetInvocation(Document document, Request r
if (node is InvocationExpressionSyntax invocation && invocation.ArgumentList.Span.Contains(position))
{
var semanticModel = await document.GetSemanticModelAsync();
return new InvocationContext(semanticModel, position, invocation.Expression, invocation.ArgumentList);
return new InvocationContext(semanticModel, position, invocation.Expression, invocation.ArgumentList, invocation.IsInStaticContext());
}

if (node is ObjectCreationExpressionSyntax objectCreation && objectCreation.ArgumentList.Span.Contains(position))
{
var semanticModel = await document.GetSemanticModelAsync();
return new InvocationContext(semanticModel, position, objectCreation, objectCreation.ArgumentList);
return new InvocationContext(semanticModel, position, objectCreation, objectCreation.ArgumentList, objectCreation.IsInStaticContext());
}

if (node is AttributeSyntax attributeSyntax && attributeSyntax.ArgumentList.Span.Contains(position))
{
var semanticModel = await document.GetSemanticModelAsync();
return new InvocationContext(semanticModel, position, attributeSyntax, attributeSyntax.ArgumentList);
return new InvocationContext(semanticModel, position, attributeSyntax, attributeSyntax.ArgumentList, attributeSyntax.IsInStaticContext());
}

node = node.Parent;
Expand All @@ -115,30 +133,9 @@ private async Task<InvocationContext> GetInvocation(Document document, Request r
return null;
}

private IEnumerable<IMethodSymbol> GetMethodOverloads(SemanticModel semanticModel, SyntaxNode node)
{
ISymbol symbol = null;
var symbolInfo = semanticModel.GetSymbolInfo(node);
if (symbolInfo.Symbol != null)
{
symbol = symbolInfo.Symbol;
}
else if (!symbolInfo.CandidateSymbols.IsEmpty)
{
symbol = symbolInfo.CandidateSymbols.First();
}

if (symbol == null || symbol.ContainingType == null)
{
return new IMethodSymbol[] { };
}

return symbol.ContainingType.GetMembers(symbol.Name).OfType<IMethodSymbol>();
}

private int InvocationScore(IMethodSymbol symbol, IEnumerable<TypeInfo> types)
{
var parameters = GetParameters(symbol);
var parameters = symbol.Parameters;
if (parameters.Count() < types.Count())
{
return int.MinValue;
Expand Down Expand Up @@ -172,7 +169,7 @@ private static SignatureHelpItem BuildSignature(IMethodSymbol symbol)
signature.Name = symbol.MethodKind == MethodKind.Constructor ? symbol.ContainingType.Name : symbol.Name;
signature.Label = symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);

signature.Parameters = GetParameters(symbol).Select(parameter =>
signature.Parameters = symbol.Parameters.Select(parameter =>
{
return new SignatureHelpParameter()
{
Expand All @@ -185,16 +182,5 @@ private static SignatureHelpItem BuildSignature(IMethodSymbol symbol)
return signature;
}

private static IEnumerable<IParameterSymbol> GetParameters(IMethodSymbol methodSymbol)
{
if (!methodSymbol.IsExtensionMethod)
{
return methodSymbol.Parameters;
}
else
{
return methodSymbol.Parameters.RemoveAt(0);
}
}
}
}
Loading

0 comments on commit eae75dc

Please sign in to comment.