public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node) { node = (MemberAccessExpressionSyntax)base.VisitMemberAccessExpression(node); var type = _context.GetNodeContainingClassType(node); if (type == _type && node.Name.ToString() == _memberName) { node = node .WithName(SyntaxFactory.IdentifierName(_newName)) .WithLeadingTrivia(node.GetLeadingTrivia()) .WithTrailingTrivia(node.GetTrailingTrivia()); node = node.CopyAnnotationsTo(node); } return(node); }
private static bool TryReduceMemberAccessExpression( MemberAccessExpressionSyntax memberAccess, SemanticModel semanticModel, out TypeSyntax replacementNode, out TextSpan issueSpan, OptionSet optionSet, CancellationToken cancellationToken) { replacementNode = null; issueSpan = default; if (memberAccess.Name == null || memberAccess.Expression == null) return false; // if this node is annotated as being a SpecialType, let's use this information. if (memberAccess.HasAnnotations(SpecialTypeAnnotation.Kind)) { replacementNode = SyntaxFactory.PredefinedType( SyntaxFactory.Token( memberAccess.GetLeadingTrivia(), GetPredefinedKeywordKind(SpecialTypeAnnotation.GetSpecialType(memberAccess.GetAnnotations(SpecialTypeAnnotation.Kind).First())), memberAccess.GetTrailingTrivia())); issueSpan = memberAccess.Span; return true; } // See https://github.com/dotnet/roslyn/issues/40974 // // To be very safe, we only support simplifying code that bound to a symbol without any // sort of problems. We could potentially relax this in the future. However, we would // need to be very careful about the implications of us offering to fixup 'broken' code // in a manner that might end up making things worse or confusing the user. var symbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, memberAccess); if (symbol == null) return false; if (memberAccess.Expression.IsKind(SyntaxKind.ThisExpression) && !SimplificationHelpers.ShouldSimplifyThisOrMeMemberAccessExpression(semanticModel, optionSet, symbol)) { return false; } // if this node is on the left side, we could simplify to aliases if (!memberAccess.IsRightSideOfDot()) { // Check if we need to replace this syntax with an alias identifier if (TryReplaceExpressionWithAlias( memberAccess, semanticModel, symbol, cancellationToken, out var aliasReplacement)) { // get the token text as it appears in source code to preserve e.g. unicode character escaping var text = aliasReplacement.Name; var syntaxRef = aliasReplacement.DeclaringSyntaxReferences.FirstOrDefault(); if (syntaxRef != null) { var declIdentifier = ((UsingDirectiveSyntax)syntaxRef.GetSyntax(cancellationToken)).Alias.Name.Identifier; text = declIdentifier.IsVerbatimIdentifier() ? declIdentifier.ToString().Substring(1) : declIdentifier.ToString(); } replacementNode = SyntaxFactory.IdentifierName( memberAccess.Name.Identifier.CopyAnnotationsTo(SyntaxFactory.Identifier( memberAccess.GetLeadingTrivia(), SyntaxKind.IdentifierToken, text, aliasReplacement.Name, memberAccess.GetTrailingTrivia()))); replacementNode = memberAccess.CopyAnnotationsTo(replacementNode); replacementNode = memberAccess.Name.CopyAnnotationsTo(replacementNode); issueSpan = memberAccess.Span; // In case the alias name is the same as the last name of the alias target, we only include // the left part of the name in the unnecessary span to Not confuse uses. if (memberAccess.Name.Identifier.ValueText == ((IdentifierNameSyntax)replacementNode).Identifier.ValueText) { issueSpan = memberAccess.Expression.Span; } return true; } // Check if the Expression can be replaced by Predefined Type keyword if (PreferPredefinedTypeKeywordInMemberAccess(memberAccess, optionSet, semanticModel)) { if (symbol != null && symbol.IsKind(SymbolKind.NamedType)) { var keywordKind = GetPredefinedKeywordKind(((INamedTypeSymbol)symbol).SpecialType); if (keywordKind != SyntaxKind.None) { replacementNode = CreatePredefinedTypeSyntax(memberAccess, keywordKind); replacementNode = replacementNode .WithAdditionalAnnotations<TypeSyntax>(new SyntaxAnnotation( nameof(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess))); issueSpan = memberAccess.Span; // we want to show the whole expression as unnecessary return true; } } } } // Try to eliminate cases without actually calling CanReplaceWithReducedName. For expressions of the form // 'this.Name' or 'base.Name', no additional check here is required. if (!memberAccess.Expression.IsKind(SyntaxKind.ThisExpression, SyntaxKind.BaseExpression)) { GetReplacementCandidates( semanticModel, memberAccess, symbol, out var speculativeSymbols, out var speculativeNamespacesAndTypes); if (!IsReplacementCandidate(symbol, speculativeSymbols, speculativeNamespacesAndTypes)) { return false; } } replacementNode = memberAccess.GetNameWithTriviaMoved(); issueSpan = memberAccess.Expression.Span; return CanReplaceWithReducedName( memberAccess, replacementNode, semanticModel, symbol, cancellationToken); }