提交 4157cc3e 编写于 作者: D Dustin Campbell

Merge pull request #4984 from DustinCampbell/issue-4339

Fix Visual Basic Workflow v1 projects when events are hooked up
......@@ -33,6 +33,7 @@ internal abstract partial class AbstractMethodXmlBuilder
private const string NameRefElementName = "NameRef";
private const string NewArrayElementName = "NewArray";
private const string NewClassElementName = "NewClass";
private const string NewDelegateElementName = "NewDelegate";
private const string NullElementName = "Null";
private const string NumberElementName = "Number";
private const string ParenthesesElementName = "Parentheses";
......@@ -42,7 +43,10 @@ internal abstract partial class AbstractMethodXmlBuilder
private const string TypeElementName = "Type";
private const string BinaryOperatorAttributeName = "binaryoperator";
private const string FullNameAttributeName = "fullname";
private const string ImplicitAttributeName = "implicit";
private const string LineAttributeName = "line";
private const string NameAttributeName = "name";
private const string RankAttributeName = "rank";
private const string TypeAttributeName = "type";
private const string VariableKindAttributeName = "variablekind";
......@@ -182,11 +186,41 @@ private AttributeInfo BinaryOperatorAttribute(BinaryOperatorKind kind)
return new AttributeInfo(BinaryOperatorAttributeName, GetBinaryOperatorKindText(kind));
}
private AttributeInfo FullNameAttribute(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return AttributeInfo.Empty;
}
return new AttributeInfo(FullNameAttributeName, name);
}
private AttributeInfo ImplicitAttribute(bool? @implicit)
{
if (@implicit == null)
{
return AttributeInfo.Empty;
}
return new AttributeInfo(ImplicitAttributeName, @implicit.Value ? "yes" : "no");
}
private AttributeInfo LineNumberAttribute(int lineNumber)
{
return new AttributeInfo(LineAttributeName, lineNumber.ToString());
}
private AttributeInfo NameAttribute(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return AttributeInfo.Empty;
}
return new AttributeInfo(NameAttributeName, name);
}
private AttributeInfo RankAttribute(int rank)
{
return new AttributeInfo(RankAttributeName, rank.ToString());
......@@ -307,9 +341,9 @@ protected IDisposable NameTag()
return Tag(NameElementName);
}
protected IDisposable NameRefTag(VariableKind kind)
protected IDisposable NameRefTag(VariableKind kind, string name = null, string fullName = null)
{
return Tag(NameRefElementName, VariableKindAttribute(kind));
return Tag(NameRefElementName, VariableKindAttribute(kind), NameAttribute(name), FullNameAttribute(fullName));
}
protected IDisposable NewArrayTag()
......@@ -322,6 +356,11 @@ protected IDisposable NewClassTag()
return Tag(NewClassElementName);
}
protected IDisposable NewDelegateTag(string name)
{
return Tag(NewDelegateElementName, NameAttribute(name));
}
protected void NullTag()
{
AppendLeafTag(NullElementName);
......@@ -352,9 +391,9 @@ protected void ThisReferenceTag()
AppendLeafTag(ThisReferenceElementName);
}
protected IDisposable TypeTag()
protected IDisposable TypeTag(bool? @implicit = null)
{
return Tag(TypeElementName);
return Tag(TypeElementName, ImplicitAttribute(@implicit));
}
protected void LineBreak()
......@@ -427,21 +466,25 @@ protected void GenerateName(string name)
}
}
protected void GenerateType(ITypeSymbol type)
protected void GenerateType(ITypeSymbol type, bool? @implicit = null, bool assemblyQualify = false)
{
if (type.TypeKind == TypeKind.Array)
{
var arrayType = (IArrayTypeSymbol)type;
using (var tag = ArrayTypeTag(arrayType.Rank))
{
GenerateType(arrayType.ElementType);
GenerateType(arrayType.ElementType, @implicit, assemblyQualify);
}
}
else
{
using (TypeTag())
using (TypeTag(@implicit))
{
EncodedText(GetTypeName(type));
var typeName = assemblyQualify
? GetTypeName(type) + ", " + type.ContainingAssembly.ToDisplayString()
: GetTypeName(type);
EncodedText(typeName);
}
}
}
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Roslyn.Test.Utilities
Imports Microsoft.VisualStudio.LanguageServices.UnitTests.CodeModel
Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.CodeModel.MethodXML
Partial Public Class MethodXMLTests
......
......@@ -300,6 +300,7 @@
<Compile Include="CodeModel\MethodXML\MethodXMLTests_VBInitializeComponent_TestContent.vb" />
<Compile Include="CodeModel\MethodXML\MethodXMLTests_VBInvocations.vb" />
<Compile Include="CodeModel\MethodXML\MethodXMLTests_VBLocalDeclarations.vb" />
<Compile Include="CodeModel\MethodXML\MethodXMLTests_VBStatements.vb" />
<Compile Include="CodeModel\Mocks\MockTextManagerAdapter.vb" />
<Compile Include="CodeModel\Mocks\MockTextPoint.vb" />
<Compile Include="CodeModel\VisualBasic\CodeAccessorFunctionTests.vb" />
......
......@@ -2,10 +2,8 @@
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Shared.Extensions
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.MethodXml
......@@ -13,6 +11,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel.MethodXm
Friend Class MethodXmlBuilder
Inherits AbstractMethodXmlBuilder
Private Shared ReadOnly s_fullNameFormat As New SymbolDisplayFormat(
typeQualificationStyle:=SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
memberOptions:=SymbolDisplayMemberOptions.None)
Private Sub New(symbol As IMethodSymbol, semanticModel As SemanticModel)
MyBase.New(symbol, semanticModel)
End Sub
......@@ -38,6 +40,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel.MethodXm
success = TryGenerateCall(DirectCast(statement, CallStatementSyntax))
Case SyntaxKind.ExpressionStatement
success = TryGenerateExpressionStatement(DirectCast(statement, ExpressionStatementSyntax))
Case SyntaxKind.AddHandlerStatement,
SyntaxKind.RemoveHandlerStatement
success = TryGenerateAddOrRemoveHandlerStatement(DirectCast(statement, AddRemoveHandlerStatementSyntax))
End Select
If Not success Then
......@@ -110,13 +115,54 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel.MethodXm
End Using
End Function
Private Function TryGenerateExpression(expression As ExpressionSyntax) As Boolean
Private Function TryGenerateAddOrRemoveHandlerStatement(addHandlerStatement As AddRemoveHandlerStatementSyntax) As Boolean
' AddHandler statements are represented as invocations of an event's add_* method.
' RemoveHandler statements are represented as invocations of an event's remove_* method.
Dim eventExpression = addHandlerStatement.EventExpression
Dim eventSymbol = TryCast(SemanticModel.GetSymbolInfo(eventExpression).Symbol, IEventSymbol)
Dim eventAccessor As IMethodSymbol
If addHandlerStatement.Kind() = SyntaxKind.AddHandlerStatement Then
eventAccessor = eventSymbol?.AddMethod
ElseIf addHandlerStatement.Kind() = SyntaxKind.RemoveHandlerStatement
eventAccessor = eventSymbol?.RemoveMethod
Else
eventAccessor = Nothing
End If
If eventAccessor Is Nothing Then
Return False
End If
Using ExpressionStatementTag(GetLineNumber(addHandlerStatement))
Using ExpressionTag()
Using MethodCallTag()
If Not TryGenerateExpression(eventExpression, eventAccessor, generateAttributes:=True) Then
Return False
End If
GenerateType(eventSymbol.ContainingType, implicit:=True, assemblyQualify:=True)
Using ArgumentTag()
If Not TryGenerateExpression(addHandlerStatement.DelegateExpression, generateAttributes:=True) Then
Return False
End If
End Using
Return True
End Using
End Using
End Using
End Function
Private Function TryGenerateExpression(expression As ExpressionSyntax, Optional symbolOpt As ISymbol = Nothing, Optional generateAttributes As Boolean = False) As Boolean
Using ExpressionTag()
Return TryGenerateExpressionSansTag(expression)
Return TryGenerateExpressionSansTag(expression, symbolOpt, generateAttributes)
End Using
End Function
Private Function TryGenerateExpressionSansTag(expression As ExpressionSyntax) As Boolean
Private Function TryGenerateExpressionSansTag(expression As ExpressionSyntax, Optional symbolOpt As ISymbol = Nothing, Optional generateAttributes As Boolean = False) As Boolean
Select Case expression.Kind
Case SyntaxKind.CharacterLiteralExpression,
SyntaxKind.UnaryMinusExpression,
......@@ -149,10 +195,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel.MethodXm
Return TryGenerateNewClass(DirectCast(expression, ObjectCreationExpressionSyntax))
Case SyntaxKind.SimpleMemberAccessExpression
Return TryGenerateNameRef(DirectCast(expression, MemberAccessExpressionSyntax))
Return TryGenerateNameRef(DirectCast(expression, MemberAccessExpressionSyntax), symbolOpt, generateAttributes)
Case SyntaxKind.IdentifierName
Return TryGenerateNameRef(DirectCast(expression, IdentifierNameSyntax))
Return TryGenerateNameRef(DirectCast(expression, IdentifierNameSyntax), symbolOpt, generateAttributes)
Case SyntaxKind.InvocationExpression
Return TryGenerateMethodCall(DirectCast(expression, InvocationExpressionSyntax))
......@@ -169,6 +215,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel.MethodXm
Case SyntaxKind.MeExpression
GenerateThisReference()
Return True
Case SyntaxKind.AddressOfExpression
Return TryGenerateAddressOfExpression(DirectCast(expression, UnaryExpressionSyntax))
End Select
Return False
......@@ -278,16 +327,36 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel.MethodXm
Return kind
End Function
Private Function TryGenerateNameRef(memberAccessExpression As MemberAccessExpressionSyntax) As Boolean
Dim symbol = SemanticModel.GetSymbolInfo(memberAccessExpression).Symbol
Private Shared Function GetFullNameText(symbol As ISymbol) As String
If symbol Is Nothing Then
Return Nothing
End If
If symbol.IsAccessor() Then
Return Nothing
End If
Return symbol.ContainingSymbol.ToDisplayString(s_fullNameFormat) & "." & symbol.Name
End Function
Private Function TryGenerateNameRef(
memberAccess As MemberAccessExpressionSyntax,
Optional symbolOpt As ISymbol = Nothing,
Optional generateAttributes As Boolean = False
) As Boolean
symbolOpt = If(symbolOpt, SemanticModel.GetSymbolInfo(memberAccess).Symbol)
' No null check for 'symbol' here. If 'symbol' unknown, we'll
' generate an "unknown" name ref.
' Note: There's no null check for 'symbolOpt' here. If 'symbolOpt' is Nothing, we'll generate an "unknown" name ref.
Dim varKind As VariableKind = GetVariableKind(symbolOpt)
Dim kind As VariableKind = GetVariableKind(symbol)
Dim name = If(symbolOpt IsNot Nothing, symbolOpt.Name, memberAccess.Name.Identifier.ValueText)
Dim nameAttribute = If(generateAttributes, name, Nothing)
Dim fullNameAttribute = If(generateAttributes, GetFullNameText(symbolOpt), Nothing)
Using NameRefTag(kind)
Dim leftHandSymbol = SemanticModel.GetSymbolInfo(memberAccessExpression.GetExpressionOfMemberAccessExpression()).Symbol
Using NameRefTag(varKind, nameAttribute, fullNameAttribute)
Dim leftHandSymbol = SemanticModel.GetSymbolInfo(memberAccess.GetExpressionOfMemberAccessExpression()).Symbol
If leftHandSymbol IsNot Nothing Then
If leftHandSymbol.Kind = SymbolKind.Alias Then
leftHandSymbol = DirectCast(leftHandSymbol, IAliasSymbol).Target
......@@ -296,10 +365,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel.MethodXm
' This can occur if a module member is referenced without the module name. In that case,
' we'll go ahead and try to use the module name name.
If leftHandSymbol.Kind = SymbolKind.Namespace AndAlso
symbol.ContainingType IsNot Nothing AndAlso
symbol.ContainingType.TypeKind = TypeKind.Module Then
symbolOpt?.ContainingType?.TypeKind = TypeKind.Module Then
leftHandSymbol = symbol.ContainingType
leftHandSymbol = symbolOpt.ContainingType
End If
End If
......@@ -311,50 +379,65 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel.MethodXm
GenerateType(DirectCast(leftHandSymbol, ITypeSymbol))
End Using
End Using
ElseIf Not TryGenerateExpression(memberAccessExpression.GetExpressionOfMemberAccessExpression()) Then
ElseIf Not TryGenerateExpression(memberAccess.GetExpressionOfMemberAccessExpression(), generateAttributes:=generateAttributes) Then
Return False
End If
GenerateName(memberAccessExpression.Name.Identifier.ValueText)
If Not generateAttributes Then
GenerateName(name)
End If
End Using
Return True
End Function
Private Function TryGenerateNameRef(identifierName As IdentifierNameSyntax) As Boolean
Dim symbol = SemanticModel.GetSymbolInfo(identifierName).Symbol
Private Function TryGenerateNameRef(
identifierName As IdentifierNameSyntax,
Optional symbolOpt As ISymbol = Nothing,
Optional generateAttributes As Boolean = False
) As Boolean
' No null check for 'symbol' here. If 'symbol' unknown, we'll
' generate an "unknown" name ref.
symbolOpt = If(symbolOpt, SemanticModel.GetSymbolInfo(identifierName).Symbol)
Dim varKind = GetVariableKind(symbol)
' Note: There's no null check for 'symbolOpt' here. If 'symbolOpt' is Nothing, we'll generate an "unknown" name ref.
Dim varKind = GetVariableKind(symbolOpt)
Using NameRefTag(varKind)
If symbol IsNot Nothing AndAlso varKind <> VariableKind.Local Then
' This is a little tricky -- if our method symbol's containing type inherits from
' or is the same as the identifier symbol's containing type, we'll go ahead and
' generate a <ThisReference />. Otherwise, because this is an identifier, we assume
' that it is a Shared member or an imported type (for example, a Module) and generate
' an <Expression><Literal><Type/></Literal></Expression>
If Me.Symbol.ContainingType.InheritsFromOrEquals(symbol.ContainingType) Then
Using ExpressionTag()
GenerateThisReference()
End Using
Else
Using ExpressionTag()
Using LiteralTag()
GenerateType(symbol.ContainingType)
End Using
End Using
End If
Dim name = If(symbolOpt IsNot Nothing, symbolOpt.Name, identifierName.Identifier.ValueText)
Dim nameAttribute = If(generateAttributes, name, Nothing)
Dim fullNameAttribute = If(generateAttributes, GetFullNameText(symbolOpt), Nothing)
Using NameRefTag(varKind, nameAttribute, fullNameAttribute)
If symbolOpt IsNot Nothing AndAlso varKind <> VariableKind.Local Then
GenerateLastNameRef(symbolOpt)
End If
GenerateName(identifierName.ToString())
If Not generateAttributes Then
GenerateName(name)
End If
End Using
Return True
End Function
Private Sub GenerateLastNameRef(symbol As ISymbol)
' This is a little tricky -- if our method symbol's containing type inherits from
' or is the same as the identifier symbol's containing type, we'll go ahead and
' generate a <ThisReference />. Otherwise, because this is an identifier, we assume
' that it is a Shared member or an imported type (for example, a Module) and generate
' an <Expression><Literal><Type/></Literal></Expression>
If Me.Symbol.ContainingType.InheritsFromOrEquals(symbol.ContainingType) Then
Using ExpressionTag()
GenerateThisReference()
End Using
Else
Using ExpressionTag()
Using LiteralTag()
GenerateType(symbol.ContainingType)
End Using
End Using
End If
End Sub
Private Function TryGenerateMethodCall(invocationExpression As InvocationExpressionSyntax) As Boolean
Using MethodCallTag()
If Not TryGenerateExpression(invocationExpression.Expression) Then
......@@ -558,8 +641,41 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel.MethodXm
Return True
End Function
Private Function TryGenerateAddressOfExpression(expression As UnaryExpressionSyntax) As Boolean
Debug.Assert(expression.Kind() = SyntaxKind.AddressOfExpression)
Dim delegateExpression = expression.Operand
Dim delegateSymbol = TryCast(SemanticModel.GetSymbolInfo(delegateExpression).Symbol, IMethodSymbol)
If delegateSymbol Is Nothing Then
Return False
End If
Dim eventType = SemanticModel.GetTypeInfo(expression).Type
If eventType Is Nothing Then
Return False
End If
Using NewDelegateTag(delegateSymbol.Name)
GenerateType(eventType, implicit:=True, assemblyQualify:=True)
If delegateExpression.Kind() = SyntaxKind.IdentifierName Then
GenerateLastNameRef(delegateSymbol)
ElseIf delegateExpression.Kind() = SyntaxKind.SimpleMemberAccessExpression
Dim memberAccess = DirectCast(delegateExpression, MemberAccessExpressionSyntax)
If Not TryGenerateExpression(memberAccess.GetExpressionOfMemberAccessExpression(), generateAttributes:=True) Then
Return False
End If
End If
GenerateType(delegateSymbol.ContainingType, implicit:=True, assemblyQualify:=True)
Return True
End Using
End Function
Public Shared Function Generate(methodBlock As MethodBlockBaseSyntax, semanticModel As SemanticModel) As String
Dim symbol = DirectCast(semanticModel.GetDeclaredSymbol(methodBlock), IMethodSymbol)
Dim symbol = semanticModel.GetDeclaredSymbol(methodBlock)
Dim builder = New MethodXmlBuilder(symbol, semanticModel)
builder.GenerateStatementBlock(methodBlock.Statements)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册