// 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. #nullable enable using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.LanguageServices; namespace Microsoft.CodeAnalysis.ReplaceMethodWithProperty { internal abstract class AbstractReplaceMethodWithPropertyService where TMethodDeclarationSyntax : SyntaxNode { #pragma warning disable CA1822 // Mark members as static - implements interface method for sub-types. public async Task GetMethodDeclarationAsync(CodeRefactoringContext context) #pragma warning restore CA1822 // Mark members as static => await context.TryGetRelevantNodeAsync().ConfigureAwait(false); protected static string? GetWarning(GetAndSetMethods getAndSetMethods) { if (OverridesMetadataSymbol(getAndSetMethods.GetMethod) || OverridesMetadataSymbol(getAndSetMethods.SetMethod)) { return FeaturesResources.Warning_Method_overrides_symbol_from_metadata; } return null; } private static bool OverridesMetadataSymbol(IMethodSymbol method) { for (var current = method; current != null; current = current.OverriddenMethod) { if (current.Locations.Any(loc => loc.IsInMetadata)) { return true; } } return false; } protected static TPropertyDeclaration SetLeadingTrivia( ISyntaxFacts syntaxFacts, GetAndSetMethods getAndSetMethods, TPropertyDeclaration property) where TPropertyDeclaration : SyntaxNode { var getMethodDeclaration = getAndSetMethods.GetMethodDeclaration; var setMethodDeclaration = getAndSetMethods.SetMethodDeclaration; var finalLeadingTrivia = getAndSetMethods.GetMethodDeclaration.GetLeadingTrivia().ToList(); //If there is a comment on the same line as the method it is contained in trailing trivia for the parameter list //If it's there we need to add it to the final comments //this is to fix issue 42699, https://github.com/dotnet/roslyn/issues/42699 AddParamListTriviaIfNeeded(syntaxFacts, getMethodDeclaration, finalLeadingTrivia); if (setMethodDeclaration == null) { return property.WithLeadingTrivia(finalLeadingTrivia); } finalLeadingTrivia.AddRange( setMethodDeclaration.GetLeadingTrivia() .SkipWhile(t => syntaxFacts.IsEndOfLineTrivia(t)) .Where(t => !t.IsDirective)); //If there is a comment on the same line as the method it is contained in trailing trivia for the parameter list //If it's there we need to add it to the final comments AddParamListTriviaIfNeeded(syntaxFacts, setMethodDeclaration, finalLeadingTrivia); return property.WithLeadingTrivia(finalLeadingTrivia); } //If there is a comment on the same line as the method it is contained in trailing trivia for the parameter list //If it's there we need to add it to the final comments private static void AddParamListTriviaIfNeeded(ISyntaxFacts syntaxFacts, SyntaxNode methodDeclaration, List finalLeadingTrivia) { var paramList = syntaxFacts.GetParameterList(methodDeclaration); var trailingTrivia = paramList.GetTrailingTrivia(); if (trailingTrivia .Any(t => syntaxFacts.IsRegularComment(t))) { // we have a meaningful comment on the parameter list so add it to the trivia list finalLeadingTrivia.AddRange(trailingTrivia); } } } }