diff --git a/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/MicrosoftMaintainabilityAnalyzersResources.resx b/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/MicrosoftMaintainabilityAnalyzersResources.resx
index ebbf3be1c6..8ea78c6468 100644
--- a/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/MicrosoftMaintainabilityAnalyzersResources.resx
+++ b/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/MicrosoftMaintainabilityAnalyzersResources.resx
@@ -192,4 +192,13 @@
{0} calls {1} but does not use the value the method returns. Because {1} is marked as a Pure method, it cannot have side effects. Use the result in a conditional statement, assign the result to a variable, or pass it as an argument to another method.
+
+ Using nameof helps keep your code valid when refactoring.
+
+
+ Use nameof in place of string literal '{0}'
+
+
+ Use nameof to express symbol names
+
\ No newline at end of file
diff --git a/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/UseNameofInPlaceOfString.Fixer.cs b/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/UseNameofInPlaceOfString.Fixer.cs
new file mode 100644
index 0000000000..a404df0eca
--- /dev/null
+++ b/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/UseNameofInPlaceOfString.Fixer.cs
@@ -0,0 +1,65 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Immutable;
+using System.Composition;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Editing;
+
+namespace Microsoft.CodeQuality.Analyzers.Maintainability
+{
+ ///
+ /// CA1507 Use nameof to express symbol names
+ ///
+ [ExportCodeFixProvider(LanguageNames.VisualBasic, LanguageNames.CSharp), Shared]
+ public class UseNameOfInPlaceOfStringFixer : CodeFixProvider
+ {
+ public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(UseNameofInPlaceOfStringAnalyzer.RuleId);
+
+ public sealed override FixAllProvider GetFixAllProvider()
+ {
+ // See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/FixAllProvider.md for more information on Fix All Providers'
+ return WellKnownFixAllProviders.BatchFixer;
+ }
+
+ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+ var diagnostics = context.Diagnostics;
+ var diagnosticSpan = context.Span;
+ // getInnerModeNodeForTie = true so we are replacing the string literal node and not the whole argument node
+ var nodeToReplace = root.FindNode(diagnosticSpan, getInnermostNodeForTie: true);
+
+ Debug.Assert(nodeToReplace != null);
+ var stringText = nodeToReplace.FindToken(diagnosticSpan.Start).ValueText;
+ context.RegisterCodeFix(CodeAction.Create(
+ MicrosoftMaintainabilityAnalyzersResources.UseNameOfInPlaceOfStringTitle,
+ c => ReplaceWithNameOf(context.Document, nodeToReplace, stringText, c),
+ equivalenceKey: nameof(UseNameOfInPlaceOfStringFixer)),
+ context.Diagnostics);
+ }
+
+ private async Task ReplaceWithNameOf(Document document, SyntaxNode nodeToReplace,
+ string stringText, CancellationToken cancellationToken)
+ {
+ var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
+ var generator = editor.Generator;
+
+ var trailingTrivia = nodeToReplace.GetTrailingTrivia();
+ var leadingTrivia = nodeToReplace.GetLeadingTrivia();
+ var nameOfExpression = generator.NameOfExpression(generator.IdentifierName(stringText))
+ .WithTrailingTrivia(trailingTrivia)
+ .WithLeadingTrivia(leadingTrivia);
+
+ var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
+ var newRoot = root.ReplaceNode(nodeToReplace, nameOfExpression);
+
+ return document.WithSyntaxRoot(newRoot);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/UseNameofInPlaceOfString.cs b/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/UseNameofInPlaceOfString.cs
new file mode 100644
index 0000000000..7bf536062b
--- /dev/null
+++ b/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/UseNameofInPlaceOfString.cs
@@ -0,0 +1,151 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using Analyzer.Utilities;
+using Analyzer.Utilities.Extensions;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Operations;
+
+namespace Microsoft.CodeQuality.Analyzers.Maintainability
+{
+ ///
+ /// CA1507 Use nameof to express symbol names
+ ///
+ [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+ public sealed class UseNameofInPlaceOfStringAnalyzer : DiagnosticAnalyzer
+ {
+ internal const string RuleId = "CA1507";
+ private const string ParamName = "paramName";
+ private const string PropertyName = "propertyName";
+ internal const string StringText = "StringText";
+
+ private static readonly LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(MicrosoftMaintainabilityAnalyzersResources.UseNameOfInPlaceOfStringTitle), MicrosoftMaintainabilityAnalyzersResources.ResourceManager, typeof(MicrosoftMaintainabilityAnalyzersResources));
+ private static readonly LocalizableString s_localizableMessage = new LocalizableResourceString(nameof(MicrosoftMaintainabilityAnalyzersResources.UseNameOfInPlaceOfStringMessage), MicrosoftMaintainabilityAnalyzersResources.ResourceManager, typeof(MicrosoftMaintainabilityAnalyzersResources));
+ private static readonly LocalizableString s_localizableDescription = new LocalizableResourceString(nameof(MicrosoftMaintainabilityAnalyzersResources.UseNameOfInPlaceOfStringDescription), MicrosoftMaintainabilityAnalyzersResources.ResourceManager, typeof(MicrosoftMaintainabilityAnalyzersResources));
+
+ internal static DiagnosticDescriptor RuleWithSuggestion = new DiagnosticDescriptor(RuleId,
+ s_localizableTitle,
+ s_localizableMessage,
+ DiagnosticCategory.Maintainability,
+ DiagnosticHelpers.DefaultDiagnosticSeverity,
+ isEnabledByDefault: true,
+ description: s_localizableDescription,
+ helpLinkUri: "https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeQuality.Analyzers/Microsoft.CodeQuality.Analyzers.md#maintainability",
+ customTags: WellKnownDiagnosticTags.Telemetry);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(RuleWithSuggestion);
+
+ public override void Initialize(AnalysisContext analysisContext)
+ {
+ analysisContext.EnableConcurrentExecution();
+ analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+
+ analysisContext.RegisterOperationAction(AnalyzeArgument, OperationKind.Argument);
+ }
+
+ private void AnalyzeArgument(OperationAnalysisContext context)
+ {
+ var argument = (IArgumentOperation)context.Operation;
+ if ((argument.Value.Kind != OperationKind.Literal
+ || argument.Value.Type.SpecialType != SpecialType.System_String))
+ {
+ return;
+ }
+
+ if (argument.Parameter == null)
+ {
+ return;
+ }
+
+ var stringText = (string)argument.Value.ConstantValue.Value;
+
+ var matchingParameter = argument.Parameter;
+
+ switch (matchingParameter.Name)
+ {
+ case ParamName:
+ var parametersInScope = GetParametersInScope(context);
+ if (HasAMatchInScope(stringText, parametersInScope))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(
+ RuleWithSuggestion, argument.Value.Syntax.GetLocation(), stringText ));
+ }
+ return;
+ case PropertyName:
+ var propertiesInScope = GetPropertiesInScope(context);
+ if (HasAMatchInScope(stringText, propertiesInScope))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(
+ RuleWithSuggestion, argument.Value.Syntax.GetLocation(), stringText));
+ }
+ return;
+ default:
+ return;
+ }
+ }
+
+ private IEnumerable GetPropertiesInScope(OperationAnalysisContext context)
+ {
+ var containingType = context.ContainingSymbol.ContainingType;
+ // look for all of the properties in the containing type and return the property names
+ if (containingType != null)
+ {
+ foreach (var property in containingType.GetMembers().OfType())
+ {
+ yield return property.Name;
+ }
+ }
+ }
+
+ internal IEnumerable GetParametersInScope(OperationAnalysisContext context)
+ {
+ // get the parameters for the containing method
+ foreach (var parameter in context.ContainingSymbol.GetParameters())
+ {
+ yield return parameter.Name;
+ }
+
+ // and loop through the ancestors to find parameters of anonymous functions and local functions
+ var parentOperation = context.Operation.Parent;
+ while (parentOperation != null)
+ {
+ if (parentOperation.Kind == OperationKind.AnonymousFunction)
+ {
+ var lambdaSymbol = ((IAnonymousFunctionOperation)parentOperation).Symbol;
+ if (lambdaSymbol != null)
+ {
+ foreach (var lambdaParameter in lambdaSymbol.Parameters)
+ {
+ yield return lambdaParameter.Name;
+ }
+ }
+ }
+ else if (parentOperation.Kind == OperationKind.LocalFunction)
+ {
+ var localFunction = ((ILocalFunctionOperation)parentOperation).Symbol;
+ foreach (var localFunctionParameter in localFunction.Parameters)
+ {
+ yield return localFunctionParameter.Name;
+ }
+ }
+
+ parentOperation = parentOperation.Parent;
+ }
+ }
+
+ private static bool HasAMatchInScope(string stringText, IEnumerable searchCollection)
+ {
+ foreach (var name in searchCollection)
+ {
+ if (stringText == name)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/xlf/MicrosoftMaintainabilityAnalyzersResources.cs.xlf b/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/xlf/MicrosoftMaintainabilityAnalyzersResources.cs.xlf
index 11a9c6c7b6..3e79e05724 100644
--- a/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/xlf/MicrosoftMaintainabilityAnalyzersResources.cs.xlf
+++ b/src/Microsoft.CodeQuality.Analyzers/Core/Maintainability/xlf/MicrosoftMaintainabilityAnalyzersResources.cs.xlf
@@ -127,6 +127,21 @@
{0} volá {1}, ale nepoužívá hodnotu, kterou tato metoda vrací. Protože {1} je označená jako metoda Pure, nemůže mít vedlejší účinky. Použijte výsledek v podmíněném příkazu, přiřaďte výsledek proměnné nebo ho předejte jako argument jiné metodě.
+
+ Using nameof helps keep your code valid when refactoring.
+ Using nameof helps keep your code valid when refactoring.
+
+
+
+ Use nameof in place of string literal '{0}'
+ Use nameof in place of string literal '{0}'
+
+
+
+ Use nameof to express symbol names
+ Use nameof to express symbol names
+
+