Skip to content
This repository has been archived by the owner on Nov 16, 2023. It is now read-only.

Signature help bugfixes #132

Merged
merged 3 commits into from
Dec 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
using System.Threading.Tasks;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;

using Xamarin.CrossBrowser;

using Xamarin.Interactive.Compilation.Roslyn;
using Xamarin.Interactive.RoslynInternals;

namespace Xamarin.Interactive.CodeAnalysis.Monaco
{
Expand Down Expand Up @@ -98,15 +100,15 @@ async Task<SignatureHelp> ComputeSignatureHelpAsync (
var currentNode = syntaxToken.Parent;
do {
var creationExpression = currentNode as ObjectCreationExpressionSyntax;
if (creationExpression != null)
if (creationExpression != null && creationExpression.ArgumentList.Span.Contains (position))
return CreateMethodGroupSignatureHelp (
creationExpression,
creationExpression.ArgumentList,
position,
semanticModel);

var invocationExpression = currentNode as InvocationExpressionSyntax;
if (invocationExpression != null)
if (invocationExpression != null && invocationExpression.ArgumentList.Span.Contains (position))
return CreateMethodGroupSignatureHelp (
invocationExpression.Expression,
invocationExpression.ArgumentList,
Expand Down Expand Up @@ -138,9 +140,37 @@ static SignatureHelp CreateMethodGroupSignatureHelp (
var symbolInfo = semanticModel.GetSymbolInfo (expression);
var bestGuessMethod = symbolInfo.Symbol as IMethodSymbol;

// Include everything by default (global eval context)
var includeInstance = true;
var includeStatic = true;

ITypeSymbol throughType = null;

// When accessing method via some member, only show static methods in static context and vice versa for instance methods.
// This block based on https://github.com/dotnet/roslyn/blob/3b6536f4a616e5f3b8ede940c63663a828e68b5d/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider_MethodGroup.cs#L44-L50
if (expression is MemberAccessExpressionSyntax memberAccessExpression) {
var throughExpression = (memberAccessExpression).Expression;
if (!(throughExpression is BaseExpressionSyntax))
throughType = semanticModel.GetTypeInfo (throughExpression).Type;
var throughSymbolInfo = semanticModel.GetSymbolInfo (throughExpression);
var throughSymbol = throughSymbolInfo.Symbol ?? throughSymbolInfo.CandidateSymbols.FirstOrDefault ();

includeInstance = !throughExpression.IsKind (SyntaxKind.IdentifierName) ||
semanticModel.LookupSymbols (throughExpression.SpanStart, name: throughSymbol.Name).Any (s => !(s is INamedTypeSymbol)) ||
(!(throughSymbol is INamespaceOrTypeSymbol) && semanticModel.LookupSymbols (throughExpression.SpanStart, throughSymbol.ContainingType).Any (s => !(s is INamedTypeSymbol)));
includeStatic = throughSymbol is INamedTypeSymbol ||
(throughExpression.IsKind (SyntaxKind.IdentifierName) &&
semanticModel.LookupNamespacesAndTypes (throughExpression.SpanStart, name: throughSymbol.Name).Any (t => t.GetSymbolType () == throughType));
}

// TODO: Start taking CT in here? Most calls in this method have optional CT arg. Could make this async.
var within = semanticModel.GetEnclosingNamedTypeOrAssembly (position, CancellationToken.None);

var methods = semanticModel
.GetMemberGroup (expression)
.OfType<IMethodSymbol> ()
.Where (m => (m.IsStatic && includeStatic) || (!m.IsStatic && includeInstance))
.Where (m => m.IsAccessibleWithin (within, throughTypeOpt: throughType))
.ToArray ();

var signatures = new List<SignatureInformation> ();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// Author:
// Sandy Armstrong <sandy@xamarin.com>
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Reflection;
using System.Threading;

using Microsoft.CodeAnalysis;

namespace Xamarin.Interactive.RoslynInternals
{
static class InternalExtensions
{
static readonly Type symbolExtensionsType = typeof (Workspace).Assembly.GetType (
"Microsoft.CodeAnalysis.Shared.Extensions.ISymbolExtensions");
static readonly Type semanticModelExtensionsType = typeof (Workspace).Assembly.GetType (
"Microsoft.CodeAnalysis.Shared.Extensions.SemanticModelExtensions");

static readonly MethodInfo isAccessibleWithin = symbolExtensionsType.GetMethod (
"IsAccessibleWithin",
new [] {
typeof (ISymbol),
typeof (ISymbol),
typeof (ITypeSymbol)
});
static readonly MethodInfo getSymbolType = symbolExtensionsType.GetMethod (
"GetSymbolType",
new [] { typeof (ISymbol) });
static readonly MethodInfo getEnclosingNamedTypeOrAssembly = semanticModelExtensionsType.GetMethod (
"GetEnclosingNamedTypeOrAssembly",
new [] {
typeof (SemanticModel),
typeof (int),
typeof (CancellationToken)
});

public static bool IsAccessibleWithin (
this ISymbol symbol,
ISymbol within,
ITypeSymbol throughTypeOpt = null)
=> (bool)isAccessibleWithin.Invoke (
null,
new object [] { symbol, within, throughTypeOpt });

public static ITypeSymbol GetSymbolType (this ISymbol symbol)
=> (ITypeSymbol)getSymbolType.Invoke (null, new object [] { symbol });

public static ISymbol GetEnclosingNamedTypeOrAssembly (
this SemanticModel semanticModel,
int position,
CancellationToken cancellationToken)
=> (ISymbol)getEnclosingNamedTypeOrAssembly.Invoke (
null,
new object [] { semanticModel, position, cancellationToken });
}
}