File: Rename\CSharpRenameIssuesService.cs
Web Access
Project: src\src\Features\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Features.csproj (Microsoft.CodeAnalysis.CSharp.Features)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Composition;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Rename;
 
namespace Microsoft.CodeAnalysis.CSharp.Rename;
 
[ExportLanguageService(typeof(IRenameIssuesService), LanguageNames.CSharp), Shared]
internal sealed class CSharpRenameIssuesService : IRenameIssuesService
{
    [ImportingConstructor]
    [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
    public CSharpRenameIssuesService()
    {
    }
 
    public bool CheckLanguageSpecificIssues(
        SemanticModel semanticModel, ISymbol symbol, SyntaxToken triggerToken, [NotNullWhen(true)] out string? langError)
    {
        if (triggerToken.IsTypeNamedDynamic() &&
            symbol.Kind == SymbolKind.DynamicType)
        {
            langError = FeaturesResources.You_cannot_rename_this_element;
            return true;
        }
 
        if (IsTypeNamedVarInVariableOrFieldDeclaration(triggerToken))
        {
            // To check if var in this context is a real type, or the keyword, we need to 
            // speculatively bind the identifier "var". If it returns a symbol, it's a real type,
            // if not, it's the keyword.
            // see bugs 659683 (compiler API) and 659705 (rename/workspace api) for examples
            var symbolForVar = semanticModel.GetSpeculativeSymbolInfo(
                triggerToken.SpanStart,
                triggerToken.Parent!,
                SpeculativeBindingOption.BindAsTypeOrNamespace).Symbol;
 
            if (symbolForVar == null)
            {
                langError = FeaturesResources.You_cannot_rename_this_element;
                return true;
            }
        }
 
        langError = null;
        return false;
    }
 
    private static bool IsTypeNamedVarInVariableOrFieldDeclaration(SyntaxToken token)
    {
        var parent = token.Parent;
        if (parent.IsKind(SyntaxKind.IdentifierName))
        {
            TypeSyntax? declaredType = null;
            if (parent?.Parent is VariableDeclarationSyntax varDecl)
            {
                declaredType = varDecl.Type;
            }
            else if (parent?.Parent is FieldDeclarationSyntax fieldDecl)
            {
                declaredType = fieldDecl.Declaration.Type;
            }
 
            return declaredType == parent && token.Text == "var";
        }
 
        return false;
    }
}