From afd49c62a8827da29361dda950631c5195e84047 Mon Sep 17 00:00:00 2001 From: jmarolf Date: Thu, 13 Nov 2014 01:01:35 -0800 Subject: [PATCH] support GFU inside nameof for C# and VB ***NO_CI*** (changeset 1371266) --- .../ContextQuery/SyntaxTreeExtensions.cs | 2 +- .../Extensions/ExpressionSyntaxExtensions.cs | 507 +++++++++--------- .../Extensions/ISemanticModelExtensions.cs | 83 +-- .../CSharpSemanticFactsService.cs | 5 + .../ISemanticFactsService.cs | 1 + .../ContextQuery/SyntaxTreeExtensions.vb | 20 + .../VisualBasicSemanticFactsService.vb | 5 + 7 files changed, 329 insertions(+), 294 deletions(-) diff --git a/Src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs b/Src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs index a23e84b72bf..b0706e632f7 100644 --- a/Src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs +++ b/Src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs @@ -2075,7 +2075,7 @@ public static bool IsLabelContext(this SyntaxTree syntaxTree, int position, Canc return false; } - public static bool IsNameOfContext(this SyntaxTree syntaxTree, int position, SemanticModel semanticModelOpt, CancellationToken cancellationToken) + public static bool IsNameOfContext(this SyntaxTree syntaxTree, int position, SemanticModel semanticModelOpt = null, CancellationToken cancellationToken = default(CancellationToken)) { var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken); token = token.GetPreviousTokenIfTouchingWord(position); diff --git a/Src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs b/Src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs index bb266bccae7..be7bef1d2aa 100644 --- a/Src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs +++ b/Src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -369,11 +370,11 @@ public static bool IsWrittenTo(this ExpressionSyntax expression) { switch (expression.Parent.CSharpKind()) { - case SyntaxKind.PostIncrementExpression: - case SyntaxKind.PreIncrementExpression: - case SyntaxKind.PostDecrementExpression: - case SyntaxKind.PreDecrementExpression: - return true; + case SyntaxKind.PostIncrementExpression: + case SyntaxKind.PreIncrementExpression: + case SyntaxKind.PostDecrementExpression: + case SyntaxKind.PreDecrementExpression: + return true; } if (expression.IsLeftSideOfAnyAssignExpression()) @@ -393,20 +394,20 @@ public static bool IsNamedArgumentIdentifier(this ExpressionSyntax expression) public static bool IsInsideNameOf(this ExpressionSyntax expression) { - return false; // TODO: not sure what the desired semantics of this method are + return expression.SyntaxTree.IsNameOfContext(expression.SpanStart); } private static bool CanReplace(ISymbol symbol) { switch (symbol.Kind) { - case SymbolKind.Field: - case SymbolKind.Local: - case SymbolKind.Method: - case SymbolKind.Parameter: - case SymbolKind.Property: - case SymbolKind.RangeVariable: - return true; + case SymbolKind.Field: + case SymbolKind.Local: + case SymbolKind.Method: + case SymbolKind.Parameter: + case SymbolKind.Property: + case SymbolKind.RangeVariable: + return true; } return false; @@ -1361,33 +1362,33 @@ private static int GetNamespaceId(SyntaxList members, N SyntaxToken identifier; switch (name.CSharpKind()) { - case SyntaxKind.AliasQualifiedName: - var simpleName = ((AliasQualifiedNameSyntax)name).Name - .WithLeadingTrivia(name.GetLeadingTrivia()); + case SyntaxKind.AliasQualifiedName: + var simpleName = ((AliasQualifiedNameSyntax)name).Name + .WithLeadingTrivia(name.GetLeadingTrivia()); - simpleName = simpleName.ReplaceToken(simpleName.Identifier, - ((AliasQualifiedNameSyntax)name).Name.Identifier.CopyAnnotationsTo( - simpleName.Identifier.WithLeadingTrivia( - ((AliasQualifiedNameSyntax)name).Alias.Identifier.LeadingTrivia))); + simpleName = simpleName.ReplaceToken(simpleName.Identifier, + ((AliasQualifiedNameSyntax)name).Name.Identifier.CopyAnnotationsTo( + simpleName.Identifier.WithLeadingTrivia( + ((AliasQualifiedNameSyntax)name).Alias.Identifier.LeadingTrivia))); - replacementNode = simpleName; + replacementNode = simpleName; - issueSpan = ((AliasQualifiedNameSyntax)name).Alias.Span; + issueSpan = ((AliasQualifiedNameSyntax)name).Alias.Span; - break; + break; - case SyntaxKind.QualifiedName: - replacementNode = ((QualifiedNameSyntax)name).Right.WithLeadingTrivia(name.GetLeadingTrivia()); - issueSpan = ((QualifiedNameSyntax)name).Left.Span; + case SyntaxKind.QualifiedName: + replacementNode = ((QualifiedNameSyntax)name).Right.WithLeadingTrivia(name.GetLeadingTrivia()); + issueSpan = ((QualifiedNameSyntax)name).Left.Span; - break; + break; - case SyntaxKind.IdentifierName: - identifier = ((IdentifierNameSyntax)name).Identifier; + case SyntaxKind.IdentifierName: + identifier = ((IdentifierNameSyntax)name).Identifier; - // we can try to remove the Attribute suffix if this is the attribute name - TryReduceAttributeSuffix(name, identifier, semanticModel, out replacementNode, out issueSpan, cancellationToken); - break; + // we can try to remove the Attribute suffix if this is the attribute name + TryReduceAttributeSuffix(name, identifier, semanticModel, out replacementNode, out issueSpan, cancellationToken); + break; } } @@ -1481,18 +1482,18 @@ public static bool IsPartOfNamespaceDeclarationName(SyntaxNode node) { switch (parent.CSharpKind()) { - case SyntaxKind.IdentifierName: - case SyntaxKind.QualifiedName: - node = parent; - parent = parent.Parent; - break; + case SyntaxKind.IdentifierName: + case SyntaxKind.QualifiedName: + node = parent; + parent = parent.Parent; + break; - case SyntaxKind.NamespaceDeclaration: - var namespaceDeclaration = (NamespaceDeclarationSyntax)parent; - return object.Equals(namespaceDeclaration.Name, node); + case SyntaxKind.NamespaceDeclaration: + var namespaceDeclaration = (NamespaceDeclarationSyntax)parent; + return object.Equals(namespaceDeclaration.Name, node); - default: - return false; + default: + return false; } } @@ -1511,45 +1512,45 @@ public static bool IsPartOfNamespaceDeclarationName(SyntaxNode node) switch (expression.CSharpKind()) { - case SyntaxKind.SimpleMemberAccessExpression: - { - var memberAccess = (MemberAccessExpressionSyntax)expression; - ExpressionSyntax newLeft; - - if (IsMemberAccessADynamicInvocation(memberAccess, semanticModel)) - { - return false; - } - - if (TrySimplifyMemberAccessOrQualifiedName(memberAccess.Expression, memberAccess.Name, semanticModel, optionSet, out newLeft, out issueSpan)) - { - // replacement node might not be in it's simplest form, so add simplify annotation to it. - replacementNode = memberAccess.Update(newLeft, memberAccess.OperatorToken, memberAccess.Name) - .WithAdditionalAnnotations(Simplifier.Annotation); - - // Ensure that replacement doesn't change semantics. - return !ReplacementChangesSemantics(memberAccess, replacementNode, semanticModel); - } + case SyntaxKind.SimpleMemberAccessExpression: + { + var memberAccess = (MemberAccessExpressionSyntax)expression; + ExpressionSyntax newLeft; + if (IsMemberAccessADynamicInvocation(memberAccess, semanticModel)) + { return false; } - case SyntaxKind.QualifiedName: + if (TrySimplifyMemberAccessOrQualifiedName(memberAccess.Expression, memberAccess.Name, semanticModel, optionSet, out newLeft, out issueSpan)) { - var qualifiedName = (QualifiedNameSyntax)expression; - ExpressionSyntax newLeft; - if (TrySimplifyMemberAccessOrQualifiedName(qualifiedName.Left, qualifiedName.Right, semanticModel, optionSet, out newLeft, out issueSpan)) - { - // replacement node might not be in it's simplest form, so add simplify annotation to it. - replacementNode = qualifiedName.Update((NameSyntax)newLeft, qualifiedName.DotToken, qualifiedName.Right) - .WithAdditionalAnnotations(Simplifier.Annotation); + // replacement node might not be in it's simplest form, so add simplify annotation to it. + replacementNode = memberAccess.Update(newLeft, memberAccess.OperatorToken, memberAccess.Name) + .WithAdditionalAnnotations(Simplifier.Annotation); - // Ensure that replacement doesn't change semantics. - return !ReplacementChangesSemantics(qualifiedName, replacementNode, semanticModel); - } + // Ensure that replacement doesn't change semantics. + return !ReplacementChangesSemantics(memberAccess, replacementNode, semanticModel); + } - return false; + return false; + } + + case SyntaxKind.QualifiedName: + { + var qualifiedName = (QualifiedNameSyntax)expression; + ExpressionSyntax newLeft; + if (TrySimplifyMemberAccessOrQualifiedName(qualifiedName.Left, qualifiedName.Right, semanticModel, optionSet, out newLeft, out issueSpan)) + { + // replacement node might not be in it's simplest form, so add simplify annotation to it. + replacementNode = qualifiedName.Update((NameSyntax)newLeft, qualifiedName.DotToken, qualifiedName.Right) + .WithAdditionalAnnotations(Simplifier.Annotation); + + // Ensure that replacement doesn't change semantics. + return !ReplacementChangesSemantics(qualifiedName, replacementNode, semanticModel); } + + return false; + } } return false; @@ -2113,28 +2114,28 @@ private static SyntaxNode FindImmediatelyEnclosingLocalVariableDeclarationSpace( { switch (declSpace.CSharpKind()) { - // These are declaration-space-defining syntaxes, by the spec: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.IndexerDeclaration: - case SyntaxKind.OperatorDeclaration: - case SyntaxKind.ConstructorDeclaration: - case SyntaxKind.Block: - case SyntaxKind.ParenthesizedLambdaExpression: - case SyntaxKind.SimpleLambdaExpression: - case SyntaxKind.AnonymousMethodExpression: - case SyntaxKind.SwitchStatement: - case SyntaxKind.ForEachKeyword: - case SyntaxKind.ForStatement: - case SyntaxKind.UsingStatement: - - // SPEC VIOLATION: We also want to stop walking out if, say, we are in a field - // initializer. Technically according to the wording of the spec it should be - // legal to use a simple name inconsistently inside a field initializer because - // it does not define a local variable declaration space. In practice of course - // we want to check for that. (As the native compiler does as well.) - - case SyntaxKind.FieldDeclaration: - return declSpace; + // These are declaration-space-defining syntaxes, by the spec: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.IndexerDeclaration: + case SyntaxKind.OperatorDeclaration: + case SyntaxKind.ConstructorDeclaration: + case SyntaxKind.Block: + case SyntaxKind.ParenthesizedLambdaExpression: + case SyntaxKind.SimpleLambdaExpression: + case SyntaxKind.AnonymousMethodExpression: + case SyntaxKind.SwitchStatement: + case SyntaxKind.ForEachKeyword: + case SyntaxKind.ForStatement: + case SyntaxKind.UsingStatement: + + // SPEC VIOLATION: We also want to stop walking out if, say, we are in a field + // initializer. Technically according to the wording of the spec it should be + // legal to use a simple name inconsistently inside a field initializer because + // it does not define a local variable declaration space. In practice of course + // we want to check for that. (As the native compiler does as well.) + + case SyntaxKind.FieldDeclaration: + return declSpace; } } @@ -2150,40 +2151,40 @@ public static SyntaxKind GetPredefinedKeywordKind(SpecialType specialType) { switch (specialType) { - case SpecialType.System_Boolean: - return SyntaxKind.BoolKeyword; - case SpecialType.System_Byte: - return SyntaxKind.ByteKeyword; - case SpecialType.System_SByte: - return SyntaxKind.SByteKeyword; - case SpecialType.System_Int32: - return SyntaxKind.IntKeyword; - case SpecialType.System_UInt32: - return SyntaxKind.UIntKeyword; - case SpecialType.System_Int16: - return SyntaxKind.ShortKeyword; - case SpecialType.System_UInt16: - return SyntaxKind.UShortKeyword; - case SpecialType.System_Int64: - return SyntaxKind.LongKeyword; - case SpecialType.System_UInt64: - return SyntaxKind.ULongKeyword; - case SpecialType.System_Single: - return SyntaxKind.FloatKeyword; - case SpecialType.System_Double: - return SyntaxKind.DoubleKeyword; - case SpecialType.System_Decimal: - return SyntaxKind.DecimalKeyword; - case SpecialType.System_String: - return SyntaxKind.StringKeyword; - case SpecialType.System_Char: - return SyntaxKind.CharKeyword; - case SpecialType.System_Object: - return SyntaxKind.ObjectKeyword; - case SpecialType.System_Void: - return SyntaxKind.VoidKeyword; - default: - return SyntaxKind.None; + case SpecialType.System_Boolean: + return SyntaxKind.BoolKeyword; + case SpecialType.System_Byte: + return SyntaxKind.ByteKeyword; + case SpecialType.System_SByte: + return SyntaxKind.SByteKeyword; + case SpecialType.System_Int32: + return SyntaxKind.IntKeyword; + case SpecialType.System_UInt32: + return SyntaxKind.UIntKeyword; + case SpecialType.System_Int16: + return SyntaxKind.ShortKeyword; + case SpecialType.System_UInt16: + return SyntaxKind.UShortKeyword; + case SpecialType.System_Int64: + return SyntaxKind.LongKeyword; + case SpecialType.System_UInt64: + return SyntaxKind.ULongKeyword; + case SpecialType.System_Single: + return SyntaxKind.FloatKeyword; + case SpecialType.System_Double: + return SyntaxKind.DoubleKeyword; + case SpecialType.System_Decimal: + return SyntaxKind.DecimalKeyword; + case SpecialType.System_String: + return SyntaxKind.StringKeyword; + case SpecialType.System_Char: + return SyntaxKind.CharKeyword; + case SpecialType.System_Object: + return SyntaxKind.ObjectKeyword; + case SpecialType.System_Void: + return SyntaxKind.VoidKeyword; + default: + return SyntaxKind.None; } } @@ -2214,136 +2215,136 @@ public static OperatorPrecedence GetOperatorPrecedence(this ExpressionSyntax exp { switch (expression.CSharpKind()) { - case SyntaxKind.SimpleMemberAccessExpression: - case SyntaxKind.InvocationExpression: - case SyntaxKind.ElementAccessExpression: - case SyntaxKind.PostIncrementExpression: - case SyntaxKind.PostDecrementExpression: - case SyntaxKind.ObjectCreationExpression: - case SyntaxKind.TypeOfExpression: - case SyntaxKind.DefaultExpression: - case SyntaxKind.CheckedExpression: - case SyntaxKind.UncheckedExpression: - case SyntaxKind.AnonymousMethodExpression: - // From C# spec, 7.3.1: - // Primary: x.y f(x) a[x] x++ x-- new typeof default checked unchecked delegate - - return OperatorPrecedence.Primary; - - case SyntaxKind.UnaryPlusExpression: - case SyntaxKind.UnaryMinusExpression: - case SyntaxKind.LogicalNotExpression: - case SyntaxKind.BitwiseNotExpression: - case SyntaxKind.PreIncrementExpression: - case SyntaxKind.PreDecrementExpression: - case SyntaxKind.CastExpression: - // From C# spec, 7.3.1: - // Unary: + - ! ~ ++x --x (T)x - - return OperatorPrecedence.Unary; - - case SyntaxKind.MultiplyExpression: - case SyntaxKind.DivideExpression: - case SyntaxKind.ModuloExpression: - // From C# spec, 7.3.1: - // Multiplicative: * / % - - return OperatorPrecedence.Multiplicative; - - case SyntaxKind.AddExpression: - case SyntaxKind.SubtractExpression: - // From C# spec, 7.3.1: - // Additive: + - - - return OperatorPrecedence.Additive; - - case SyntaxKind.LeftShiftExpression: - case SyntaxKind.RightShiftExpression: - // From C# spec, 7.3.1: - // Shift: << >> - - return OperatorPrecedence.Shift; - - case SyntaxKind.LessThanExpression: - case SyntaxKind.GreaterThanExpression: - case SyntaxKind.LessThanOrEqualExpression: - case SyntaxKind.GreaterThanOrEqualExpression: - case SyntaxKind.IsExpression: - case SyntaxKind.AsExpression: - // From C# spec, 7.3.1: - // Relational and type testing: < > <= >= is as + case SyntaxKind.SimpleMemberAccessExpression: + case SyntaxKind.InvocationExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.PostIncrementExpression: + case SyntaxKind.PostDecrementExpression: + case SyntaxKind.ObjectCreationExpression: + case SyntaxKind.TypeOfExpression: + case SyntaxKind.DefaultExpression: + case SyntaxKind.CheckedExpression: + case SyntaxKind.UncheckedExpression: + case SyntaxKind.AnonymousMethodExpression: + // From C# spec, 7.3.1: + // Primary: x.y f(x) a[x] x++ x-- new typeof default checked unchecked delegate - return OperatorPrecedence.RelationalAndTypeTesting; + return OperatorPrecedence.Primary; - case SyntaxKind.EqualsExpression: - case SyntaxKind.NotEqualsExpression: - // From C# spec, 7.3.1: - // Equality: == != + case SyntaxKind.UnaryPlusExpression: + case SyntaxKind.UnaryMinusExpression: + case SyntaxKind.LogicalNotExpression: + case SyntaxKind.BitwiseNotExpression: + case SyntaxKind.PreIncrementExpression: + case SyntaxKind.PreDecrementExpression: + case SyntaxKind.CastExpression: + // From C# spec, 7.3.1: + // Unary: + - ! ~ ++x --x (T)x + + return OperatorPrecedence.Unary; + + case SyntaxKind.MultiplyExpression: + case SyntaxKind.DivideExpression: + case SyntaxKind.ModuloExpression: + // From C# spec, 7.3.1: + // Multiplicative: * / % + + return OperatorPrecedence.Multiplicative; + + case SyntaxKind.AddExpression: + case SyntaxKind.SubtractExpression: + // From C# spec, 7.3.1: + // Additive: + - + + return OperatorPrecedence.Additive; + + case SyntaxKind.LeftShiftExpression: + case SyntaxKind.RightShiftExpression: + // From C# spec, 7.3.1: + // Shift: << >> + + return OperatorPrecedence.Shift; + + case SyntaxKind.LessThanExpression: + case SyntaxKind.GreaterThanExpression: + case SyntaxKind.LessThanOrEqualExpression: + case SyntaxKind.GreaterThanOrEqualExpression: + case SyntaxKind.IsExpression: + case SyntaxKind.AsExpression: + // From C# spec, 7.3.1: + // Relational and type testing: < > <= >= is as + + return OperatorPrecedence.RelationalAndTypeTesting; + + case SyntaxKind.EqualsExpression: + case SyntaxKind.NotEqualsExpression: + // From C# spec, 7.3.1: + // Equality: == != + + return OperatorPrecedence.Equality; + + case SyntaxKind.BitwiseAndExpression: + // From C# spec, 7.3.1: + // Logical AND: & + + return OperatorPrecedence.LogicalAnd; + + case SyntaxKind.ExclusiveOrExpression: + // From C# spec, 7.3.1: + // Logical XOR: ^ + + return OperatorPrecedence.LogicalXor; + + case SyntaxKind.BitwiseOrExpression: + // From C# spec, 7.3.1: + // Logical OR: | + + return OperatorPrecedence.LogicalOr; + + case SyntaxKind.LogicalAndExpression: + // From C# spec, 7.3.1: + // Conditional AND: && + + return OperatorPrecedence.ConditionalAnd; + + case SyntaxKind.LogicalOrExpression: + // From C# spec, 7.3.1: + // Conditional AND: || + + return OperatorPrecedence.ConditionalOr; + + case SyntaxKind.CoalesceExpression: + // From C# spec, 7.3.1: + // Null coalescing: ?? + + return OperatorPrecedence.NullCoalescing; + + case SyntaxKind.ConditionalExpression: + // From C# spec, 7.3.1: + // Conditional: ?: - return OperatorPrecedence.Equality; + return OperatorPrecedence.Conditional; - case SyntaxKind.BitwiseAndExpression: - // From C# spec, 7.3.1: - // Logical AND: & + case SyntaxKind.SimpleAssignmentExpression: + case SyntaxKind.MultiplyAssignmentExpression: + case SyntaxKind.DivideAssignmentExpression: + case SyntaxKind.ModuloAssignmentExpression: + case SyntaxKind.AddAssignmentExpression: + case SyntaxKind.SubtractAssignmentExpression: + case SyntaxKind.LeftShiftAssignmentExpression: + case SyntaxKind.RightShiftAssignmentExpression: + case SyntaxKind.AndAssignmentExpression: + case SyntaxKind.ExclusiveOrAssignmentExpression: + case SyntaxKind.OrAssignmentExpression: + case SyntaxKind.SimpleLambdaExpression: + case SyntaxKind.ParenthesizedLambdaExpression: + // From C# spec, 7.3.1: + // Conditional: ?: - return OperatorPrecedence.LogicalAnd; + return OperatorPrecedence.AssignmentAndLambdaExpression; - case SyntaxKind.ExclusiveOrExpression: - // From C# spec, 7.3.1: - // Logical XOR: ^ - - return OperatorPrecedence.LogicalXor; - - case SyntaxKind.BitwiseOrExpression: - // From C# spec, 7.3.1: - // Logical OR: | - - return OperatorPrecedence.LogicalOr; - - case SyntaxKind.LogicalAndExpression: - // From C# spec, 7.3.1: - // Conditional AND: && - - return OperatorPrecedence.ConditionalAnd; - - case SyntaxKind.LogicalOrExpression: - // From C# spec, 7.3.1: - // Conditional AND: || - - return OperatorPrecedence.ConditionalOr; - - case SyntaxKind.CoalesceExpression: - // From C# spec, 7.3.1: - // Null coalescing: ?? - - return OperatorPrecedence.NullCoalescing; - - case SyntaxKind.ConditionalExpression: - // From C# spec, 7.3.1: - // Conditional: ?: - - return OperatorPrecedence.Conditional; - - case SyntaxKind.SimpleAssignmentExpression: - case SyntaxKind.MultiplyAssignmentExpression: - case SyntaxKind.DivideAssignmentExpression: - case SyntaxKind.ModuloAssignmentExpression: - case SyntaxKind.AddAssignmentExpression: - case SyntaxKind.SubtractAssignmentExpression: - case SyntaxKind.LeftShiftAssignmentExpression: - case SyntaxKind.RightShiftAssignmentExpression: - case SyntaxKind.AndAssignmentExpression: - case SyntaxKind.ExclusiveOrAssignmentExpression: - case SyntaxKind.OrAssignmentExpression: - case SyntaxKind.SimpleLambdaExpression: - case SyntaxKind.ParenthesizedLambdaExpression: - // From C# spec, 7.3.1: - // Conditional: ?: - - return OperatorPrecedence.AssignmentAndLambdaExpression; - - default: - return OperatorPrecedence.None; + default: + return OperatorPrecedence.None; } } } diff --git a/Src/Workspaces/CSharp/Portable/Extensions/ISemanticModelExtensions.cs b/Src/Workspaces/CSharp/Portable/Extensions/ISemanticModelExtensions.cs index 6a8cf6de405..327c6e344f5 100644 --- a/Src/Workspaces/CSharp/Portable/Extensions/ISemanticModelExtensions.cs +++ b/Src/Workspaces/CSharp/Portable/Extensions/ISemanticModelExtensions.cs @@ -60,42 +60,42 @@ private static void DecomposeName(ExpressionSyntax expression, out ExpressionSyn { switch (expression.CSharpKind()) { - case SyntaxKind.SimpleMemberAccessExpression: - case SyntaxKind.PointerMemberAccessExpression: - var max = (MemberAccessExpressionSyntax)expression; - qualifier = max.Expression; - name = max.Name.Identifier.ValueText; - arity = max.Name.Arity; - break; - case SyntaxKind.QualifiedName: - var qn = (QualifiedNameSyntax)expression; - qualifier = qn.Left; - name = qn.Right.Identifier.ValueText; - arity = qn.Arity; - break; - case SyntaxKind.AliasQualifiedName: - var aq = (AliasQualifiedNameSyntax)expression; - qualifier = aq.Alias; - name = aq.Name.Identifier.ValueText; - arity = aq.Name.Arity; - break; - case SyntaxKind.GenericName: - var gx = (GenericNameSyntax)expression; - qualifier = null; - name = gx.Identifier.ValueText; - arity = gx.Arity; - break; - case SyntaxKind.IdentifierName: - var nx = (IdentifierNameSyntax)expression; - qualifier = null; - name = nx.Identifier.ValueText; - arity = 0; - break; - default: - qualifier = null; - name = null; - arity = 0; - break; + case SyntaxKind.SimpleMemberAccessExpression: + case SyntaxKind.PointerMemberAccessExpression: + var max = (MemberAccessExpressionSyntax)expression; + qualifier = max.Expression; + name = max.Name.Identifier.ValueText; + arity = max.Name.Arity; + break; + case SyntaxKind.QualifiedName: + var qn = (QualifiedNameSyntax)expression; + qualifier = qn.Left; + name = qn.Right.Identifier.ValueText; + arity = qn.Arity; + break; + case SyntaxKind.AliasQualifiedName: + var aq = (AliasQualifiedNameSyntax)expression; + qualifier = aq.Alias; + name = aq.Name.Identifier.ValueText; + arity = aq.Name.Arity; + break; + case SyntaxKind.GenericName: + var gx = (GenericNameSyntax)expression; + qualifier = null; + name = gx.Identifier.ValueText; + arity = gx.Arity; + break; + case SyntaxKind.IdentifierName: + var nx = (IdentifierNameSyntax)expression; + qualifier = null; + name = nx.Identifier.ValueText; + arity = 0; + break; + default: + qualifier = null; + name = null; + arity = 0; + break; } } @@ -163,9 +163,9 @@ private static bool CanBindToken(SyntaxToken token) // Add more token kinds if necessary; switch (token.CSharpKind()) { - case SyntaxKind.CommaToken: - case SyntaxKind.DelegateKeyword: - return false; + case SyntaxKind.CommaToken: + case SyntaxKind.DelegateKeyword: + return false; } return true; @@ -315,7 +315,10 @@ public static ISet GetUsingNamespacesInScope(this SemanticMode TypeSyntax type, CancellationToken cancellationToken) { - type = GetOutermostType(type); + if (type != null) + { + type = GetOutermostType(type); + } // Interesting cases based on 3.5.4 Accessibility constraints in the language spec. // If any of the below hold, then we will override the default accessibility if the diff --git a/Src/Workspaces/CSharp/Portable/LanguageServices/CSharpSemanticFactsService.cs b/Src/Workspaces/CSharp/Portable/LanguageServices/CSharpSemanticFactsService.cs index 5bc918b65aa..3ad8ac67b65 100644 --- a/Src/Workspaces/CSharp/Portable/LanguageServices/CSharpSemanticFactsService.cs +++ b/Src/Workspaces/CSharp/Portable/LanguageServices/CSharpSemanticFactsService.cs @@ -262,5 +262,10 @@ public bool IsAssignableTo(ITypeSymbol fromSymbol, ITypeSymbol toSymbol, Compila toSymbol != null && ((CSharpCompilation)compilation).ClassifyConversion(fromSymbol, toSymbol).IsImplicit; } + + public bool IsNameOfContext(SemanticModel semanticModel, int position, CancellationToken cancellationToken) + { + return semanticModel.SyntaxTree.IsNameOfContext(position, semanticModel, cancellationToken); + } } } \ No newline at end of file diff --git a/Src/Workspaces/Core/Portable/LanguageServices/SemanticsFactsService/ISemanticFactsService.cs b/Src/Workspaces/Core/Portable/LanguageServices/SemanticsFactsService/ISemanticFactsService.cs index b7d02fea8ee..9a12b9a89ca 100644 --- a/Src/Workspaces/Core/Portable/LanguageServices/SemanticsFactsService/ISemanticFactsService.cs +++ b/Src/Workspaces/Core/Portable/LanguageServices/SemanticsFactsService/ISemanticFactsService.cs @@ -48,6 +48,7 @@ internal interface ISemanticFactsService : ILanguageService bool IsGlobalStatementContext(SemanticModel semanticModel, int position, CancellationToken cancellationToken); bool IsLabelContext(SemanticModel semanticModel, int position, CancellationToken cancellationToken); bool IsAttributeNameContext(SemanticModel semanticModel, int position, CancellationToken cancellationToken); + bool IsNameOfContext(SemanticModel semanticModel, int position, CancellationToken cancellationToken); /// /// True if a write is performed to the given expression. Note: reads may also be performed diff --git a/Src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.vb b/Src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.vb index 91d20916099..7bcf61da017 100644 --- a/Src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.vb +++ b/Src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.vb @@ -447,6 +447,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Return token.IsChildToken(Of SimpleAsClauseSyntax)(Function(asClause) asClause.AsKeyword) End Function + + Public Function IsNameOfContext(syntaxTree As SyntaxTree, position As Integer, token As SyntaxToken, Optional cancellationToken As CancellationToken = Nothing) As Boolean + ' first do quick exit check + If syntaxTree.IsInPreprocessorDirectiveContext(position, cancellationToken) OrElse + syntaxTree.IsInInactiveRegion(position, cancellationToken) OrElse + syntaxTree.IsEntirelyWithinComment(position, cancellationToken) OrElse + syntaxTree.IsEntirelyWithinStringOrCharLiteral(position, cancellationToken) Then + + Return False + End If + + Contract.Requires(token = syntaxTree.GetTargetToken(position, cancellationToken)) + + If token.IsChildToken(Of NameOfExpressionSyntax)(Function(importAliasClause) importAliasClause.OpenParenToken) Then + Return True + End If + + Return False + End Function + Friend Function IsSingleLineStatementContext(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean Dim targetToken = syntaxTree.GetTargetToken(position, cancellationToken) diff --git a/Src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSemanticFactsService.vb b/Src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSemanticFactsService.vb index 642210ff790..364a765662a 100644 --- a/Src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSemanticFactsService.vb +++ b/Src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSemanticFactsService.vb @@ -245,5 +245,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public Function IsAssignableTo(fromSymbol As ITypeSymbol, toSymbol As ITypeSymbol, compilation As Compilation) As Boolean Implements ISemanticFactsService.IsAssignableTo Return fromSymbol IsNot Nothing AndAlso toSymbol IsNot Nothing AndAlso DirectCast(compilation, VisualBasicCompilation).ClassifyConversion(fromSymbol, toSymbol).IsWidening End Function + + Public Function IsNameOfContext(semanticModel As SemanticModel, position As Integer, cancellationToken As CancellationToken) As Boolean Implements ISemanticFactsService.IsNameOfContext + Dim token = semanticModel.SyntaxTree.GetTargetToken(position, cancellationToken) + Return semanticModel.SyntaxTree.IsNameOfContext(position, token, cancellationToken) + End Function End Class End Namespace \ No newline at end of file -- GitLab