diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.NodeLocator.cs b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.NodeLocator.cs index 5b89bb25cb1d4f46357244f0932a91df76a9efd2..246f96ac0f4bc42a8f7111350ebd6b4987f0cb7d 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.NodeLocator.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.NodeLocator.cs @@ -37,6 +37,8 @@ protected override EnvDTE.vsCMPart DefaultPart { switch (node.Kind()) { + case SyntaxKind.ArrowExpressionClause: + return GetStartPoint(text, (ArrowExpressionClauseSyntax)node, part); case SyntaxKind.Attribute: return GetStartPoint(text, (AttributeSyntax)node, part); case SyntaxKind.AttributeArgument: @@ -83,6 +85,8 @@ protected override EnvDTE.vsCMPart DefaultPart { switch (node.Kind()) { + case SyntaxKind.ArrowExpressionClause: + return GetEndPoint(text, (ArrowExpressionClauseSyntax)node, part); case SyntaxKind.Attribute: return GetEndPoint(text, (AttributeSyntax)node, part); case SyntaxKind.AttributeArgument: @@ -211,6 +215,27 @@ private VirtualTreePoint GetBodyEndPoint(SourceText text, SyntaxToken closeBrace : new VirtualTreePoint(closeBrace.SyntaxTree, text, closeBrace.SpanStart); } + private VirtualTreePoint GetStartPoint(SourceText text, ArrowExpressionClauseSyntax node, EnvDTE.vsCMPart part) + { + int startPosition; + + switch (part) + { + case EnvDTE.vsCMPart.vsCMPartWhole: + startPosition = node.SpanStart; + break; + + case EnvDTE.vsCMPart.vsCMPartBody: + startPosition = node.Expression.SpanStart; + break; + + default: + throw Exceptions.ThrowENotImpl(); + } + + return new VirtualTreePoint(node.SyntaxTree, text, startPosition); + } + private VirtualTreePoint GetStartPoint(SourceText text, AttributeSyntax node, EnvDTE.vsCMPart part) { int startPosition; @@ -759,6 +784,24 @@ private VirtualTreePoint GetStartPoint(SourceText text, ParameterSyntax node, En return new VirtualTreePoint(node.SyntaxTree, text, startPosition); } + private VirtualTreePoint GetEndPoint(SourceText text, ArrowExpressionClauseSyntax node, EnvDTE.vsCMPart part) + { + int endPosition; + + switch (part) + { + case EnvDTE.vsCMPart.vsCMPartWhole: + case EnvDTE.vsCMPart.vsCMPartBody: + endPosition = node.Span.End; + break; + + default: + throw Exceptions.ThrowENotImpl(); + } + + return new VirtualTreePoint(node.SyntaxTree, text, endPosition); + } + private VirtualTreePoint GetEndPoint(SourceText text, AttributeSyntax node, EnvDTE.vsCMPart part) { int endPosition; diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs index 0a1e8be8536b5cfcae9d540b0c26b4672b855e34..9d0f89499872e20215281344011a864d9021ebd5 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs @@ -1477,6 +1477,15 @@ public override IEnumerable GetParameterNodes(SyntaxNode parentNode) return SpecializedCollections.EmptyEnumerable(); } + public override bool IsExpressionBodiedProperty(SyntaxNode node) + => (node as PropertyDeclarationSyntax)?.ExpressionBody != null; + + public override bool TryGetAutoPropertyExpressionBody(SyntaxNode parentNode, out SyntaxNode accessorNode) + { + accessorNode = (parentNode as PropertyDeclarationSyntax)?.ExpressionBody; + return accessorNode != null; + } + public override bool IsAccessorNode(SyntaxNode node) { switch (node.Kind()) diff --git a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs index ac28f811839518809c3dd53a7934ac8d9834d113..644f4eb09c911d64aeffa4cf2dae77f9fa68ebb1 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs @@ -663,10 +663,12 @@ protected bool TryGetElementFromSource(CodeModelState state, Project project, IT return false; } + public abstract bool IsExpressionBodiedProperty(SyntaxNode node); public abstract bool IsAccessorNode(SyntaxNode node); public abstract MethodKind GetAccessorKind(SyntaxNode node); public abstract bool TryGetAccessorNode(SyntaxNode parentNode, MethodKind kind, out SyntaxNode accessorNode); + public abstract bool TryGetAutoPropertyExpressionBody(SyntaxNode parentNode, out SyntaxNode accessorNode); public abstract bool TryGetParameterNode(SyntaxNode parentNode, string name, out SyntaxNode parameterNode); public abstract bool TryGetImportNode(SyntaxNode parentNode, string dottedName, out SyntaxNode importNode); public abstract bool TryGetOptionNode(SyntaxNode parentNode, string name, int ordinal, out SyntaxNode optionNode); diff --git a/src/VisualStudio/Core/Impl/CodeModel/ICodeModelService.cs b/src/VisualStudio/Core/Impl/CodeModel/ICodeModelService.cs index 326e9db92ca73ace481613e34a3cb0f04a1daf1f..fb12912a8996e04602bef2c3f3c32e5849480ad2 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/ICodeModelService.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/ICodeModelService.cs @@ -146,10 +146,12 @@ internal interface ICodeModelService : ICodeModelNavigationPointService SyntaxNode SetAccess(SyntaxNode node, EnvDTE.vsCMAccess access); EnvDTE.vsCMElement GetElementKind(SyntaxNode node); + bool IsExpressionBodiedProperty(SyntaxNode node); bool IsAccessorNode(SyntaxNode node); MethodKind GetAccessorKind(SyntaxNode node); bool TryGetAccessorNode(SyntaxNode parentNode, MethodKind kind, out SyntaxNode accessorNode); + bool TryGetAutoPropertyExpressionBody(SyntaxNode parentNode, out SyntaxNode expressionBody); bool TryGetParameterNode(SyntaxNode parentNode, string name, out SyntaxNode parameterNode); bool TryGetImportNode(SyntaxNode parentNode, string dottedName, out SyntaxNode importNode); bool TryGetOptionNode(SyntaxNode parentNode, string name, int ordinal, out SyntaxNode optionNode); diff --git a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeAccessorFunction.cs b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeAccessorFunction.cs index 58b6a11d2dfc6c541a361ed7ba22a6d18bb2a40a..b5a15740f36995fc49842cf0ee86599ef8152413 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeAccessorFunction.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeAccessorFunction.cs @@ -35,15 +35,10 @@ private CodeAccessorFunction(CodeModelState state, AbstractCodeMember parent, Me _kind = kind; } - private AbstractCodeMember ParentMember - { - get { return _parentHandle.Value; } - } + private AbstractCodeMember ParentMember => _parentHandle.Value; private bool IsPropertyAccessor() - { - return _kind == MethodKind.PropertyGet || _kind == MethodKind.PropertySet; - } + => _kind == MethodKind.PropertyGet || _kind == MethodKind.PropertySet; internal override bool TryLookupNode(out SyntaxNode node) { @@ -55,52 +50,29 @@ internal override bool TryLookupNode(out SyntaxNode node) return false; } - if (!CodeModelService.TryGetAccessorNode(parentNode, _kind, out var accessorNode)) - { - return false; - } - - node = accessorNode; - return node != null; + return CodeModelService.TryGetAutoPropertyExpressionBody(parentNode, out node) || + CodeModelService.TryGetAccessorNode(parentNode, _kind, out node); } public override EnvDTE.vsCMElement Kind - { - get { return EnvDTE.vsCMElement.vsCMElementFunction; } - } + => EnvDTE.vsCMElement.vsCMElementFunction; - public override object Parent - { - get { return _parentHandle.Value; } - } + public override object Parent => _parentHandle.Value; public override EnvDTE.CodeElements Children - { - get { return EmptyCollection.Create(this.State, this); } - } + => EmptyCollection.Create(this.State, this); protected override string GetName() - { - return this.ParentMember.Name; - } + => this.ParentMember.Name; protected override void SetName(string value) - { - this.ParentMember.Name = value; - } + => this.ParentMember.Name = value; protected override string GetFullName() - { - return this.ParentMember.FullName; - } + => this.ParentMember.FullName; public EnvDTE.CodeElements Attributes - { - get - { - return AttributeCollection.Create(this.State, this); - } - } + => AttributeCollection.Create(this.State, this); public EnvDTE.vsCMAccess Access { @@ -211,10 +183,7 @@ public EnvDTE80.vsCMOverrideKind OverrideKind } } - public bool IsOverloaded - { - get { return false; } - } + public bool IsOverloaded => false; public bool IsShared { @@ -271,12 +240,7 @@ public bool MustImplement } public EnvDTE.CodeElements Overloads - { - get - { - throw Exceptions.ThrowEFail(); - } - } + => throw Exceptions.ThrowEFail(); public EnvDTE.CodeElements Parameters { @@ -327,4 +291,4 @@ public void RemoveParameter(object element) throw Exceptions.ThrowEFail(); } } -} +} \ No newline at end of file diff --git a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeProperty.cs b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeProperty.cs index 8c23c1e3c5927f6aad55fe8d74b5f0fd49f57eab..2c4386f41384c83cba092fe9d5b1d9627838464f 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeProperty.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/CodeProperty.cs @@ -144,15 +144,17 @@ public override EnvDTE.CodeElements Children } private bool HasAccessorNode(MethodKind methodKind) - { - return CodeModelService.TryGetAccessorNode(LookupNode(), methodKind, out var accessorNode); - } + => CodeModelService.TryGetAccessorNode(LookupNode(), methodKind, out var accessorNode); + + private bool IsExpressionBodiedProperty() + => CodeModelService.IsExpressionBodiedProperty(LookupNode()); public EnvDTE.CodeFunction Getter { get { - if (!HasAccessorNode(MethodKind.PropertyGet)) + if (!HasAccessorNode(MethodKind.PropertyGet) && + !IsExpressionBodiedProperty()) { return null; } diff --git a/src/VisualStudio/Core/Test/CodeModel/CSharp/CodePropertyTests.vb b/src/VisualStudio/Core/Test/CodeModel/CSharp/CodePropertyTests.vb index fda08b2180ac8e153a5ed1e0cc3a4e29371d5850..ec14e661209887edcfad987a9605bcde2bea0d27 100644 --- a/src/VisualStudio/Core/Test/CodeModel/CSharp/CodePropertyTests.vb +++ b/src/VisualStudio/Core/Test/CodeModel/CSharp/CodePropertyTests.vb @@ -54,6 +54,68 @@ class C TextPoint(line:=3, lineOffset:=5, absoluteOffset:=15, lineLength:=16))) End Function + + Public Async Function TestAutoPropGetStartPoint1() As Task + Dim code = + +class C +{ + public int $$P => 0; +} + + + Await TestElement( + code, + Sub(prop) + Dim getter = prop.Getter + Dim textPointGetter = Function(part As EnvDTE.vsCMPart) + Return getter.GetStartPoint(part) + End Function + + Part(EnvDTE.vsCMPart.vsCMPartAttributes, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartBody, TextPoint(line:=3, lineOffset:=21, absoluteOffset:=31, lineLength:=22))(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartHeader, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartName, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartNavigate, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartWhole, TextPoint(line:=3, lineOffset:=18, absoluteOffset:=28, lineLength:=22))(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartWholeWithAttributes, ThrowsNotImplementedException)(textPointGetter) + End Sub) + End Function + + + Public Async Function TestAutoPropGetEndPoint1() As Task + Dim code = + +class C +{ + public int $$P => 0; +} + + + Await TestElement( + code, + Sub(prop) + Dim getter = prop.Getter + Dim textPointGetter = Function(part As EnvDTE.vsCMPart) + Return getter.GetEndPoint(part) + End Function + + Part(EnvDTE.vsCMPart.vsCMPartAttributes, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartBody, TextPoint(line:=3, lineOffset:=22, absoluteOffset:=32, lineLength:=22))(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartHeader, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartName, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartNavigate, ThrowsNotImplementedException)(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartWhole, TextPoint(line:=3, lineOffset:=22, absoluteOffset:=32, lineLength:=22))(textPointGetter) + Part(EnvDTE.vsCMPart.vsCMPartWholeWithAttributes, ThrowsNotImplementedException)(textPointGetter) + End Sub) + End Function + Public Async Function TestGetStartPoint_Attribute() As Task Dim code = diff --git a/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.vb b/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.vb index c4f65cd08c31501fa0b638fc63a7e5cc4a296691..0fbac75572c87c52f40c6970ba44796349f86860 100644 --- a/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.vb +++ b/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.vb @@ -1048,6 +1048,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel Return GetExternalSymbolFullName(symbol) End Function + Public Overrides Function IsExpressionBodiedProperty(node As SyntaxNode) As Boolean + Return False + End Function + + Public Overrides Function TryGetAutoPropertyExpressionBody(parentNode As SyntaxNode, ByRef accessorNode As SyntaxNode) As Boolean + Return False + End Function + Public Overrides Function IsAccessorNode(node As SyntaxNode) As Boolean Select Case node.Kind Case SyntaxKind.GetAccessorBlock,