/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Globalization/UseOrdinalStringComparison.cs

https://gitlab.com/sharadag/TestProject2 · C# · 139 lines · 115 code · 16 blank · 8 comment · 24 complexity · 3cb10989325221634cfb506583d1e57a MD5 · raw file

  1. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  2. using System.Collections.Immutable;
  3. using Microsoft.CodeAnalysis.Diagnostics;
  4. using Microsoft.CodeAnalysis;
  5. namespace System.Runtime.Analyzers
  6. {
  7. public abstract class UseOrdinalStringComparisonAnalyzer : DiagnosticAnalyzer
  8. {
  9. internal const string RuleId = "CA1309";
  10. private static readonly LocalizableString s_localizableMessageAndTitle = new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.StringComparisonShouldBeOrdinalOrOrdinalIgnoreCase), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources));
  11. private static readonly LocalizableString s_localizableDescription = new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.StringComparisonShouldBeOrdinalDescription), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources));
  12. internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId,
  13. s_localizableMessageAndTitle,
  14. s_localizableMessageAndTitle,
  15. DiagnosticCategory.Globalization,
  16. DiagnosticSeverity.Warning,
  17. isEnabledByDefault: false,
  18. description: s_localizableDescription,
  19. helpLinkUri: "http://msdn.microsoft.com/library/bb385972.aspx",
  20. customTags: WellKnownDiagnosticTags.Telemetry);
  21. internal const string CompareMethodName = "Compare";
  22. internal const string EqualsMethodName = "Equals";
  23. internal const string OrdinalText = "Ordinal";
  24. internal const string OrdinalIgnoreCaseText = "OrdinalIgnoreCase";
  25. internal const string StringComparisonTypeName = "System.StringComparison";
  26. internal const string IgnoreCaseText = "IgnoreCase";
  27. protected abstract void GetAnalyzer(CompilationStartAnalysisContext context, INamedTypeSymbol stringComparisonType);
  28. public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
  29. public override void Initialize(AnalysisContext analysisContext)
  30. {
  31. analysisContext.RegisterCompilationStartAction(
  32. (context) =>
  33. {
  34. var stringComparisonType = context.Compilation.GetTypeByMetadataName(StringComparisonTypeName);
  35. if (stringComparisonType != null)
  36. {
  37. GetAnalyzer(context, stringComparisonType);
  38. }
  39. });
  40. }
  41. protected abstract class AbstractCodeBlockAnalyzer
  42. {
  43. protected INamedTypeSymbol StringComparisonType { get; }
  44. public AbstractCodeBlockAnalyzer(INamedTypeSymbol stringComparisonType)
  45. {
  46. this.StringComparisonType = stringComparisonType;
  47. }
  48. protected static bool IsEqualsOrCompare(string methodName)
  49. {
  50. return string.Equals(methodName, EqualsMethodName, StringComparison.Ordinal) ||
  51. string.Equals(methodName, CompareMethodName, StringComparison.Ordinal);
  52. }
  53. protected static bool IsAcceptableOverload(IMethodSymbol methodSymbol, SemanticModel model)
  54. {
  55. var stringComparisonType = WellKnownTypes.StringComparison(model.Compilation);
  56. return methodSymbol.IsStatic
  57. ? IsAcceptableStaticOverload(methodSymbol, stringComparisonType)
  58. : IsAcceptableInstanceOverload(methodSymbol, stringComparisonType);
  59. }
  60. protected static bool IsAcceptableInstanceOverload(IMethodSymbol methodSymbol, INamedTypeSymbol stringComparisonType)
  61. {
  62. if (string.Equals(methodSymbol.Name, EqualsMethodName, StringComparison.Ordinal))
  63. {
  64. switch (methodSymbol.Parameters.Length)
  65. {
  66. case 1:
  67. // the instance method .Equals(object) is OK
  68. return methodSymbol.Parameters[0].Type.SpecialType == SpecialType.System_Object;
  69. case 2:
  70. return methodSymbol.Parameters[0].Type.SpecialType == SpecialType.System_String &&
  71. methodSymbol.Parameters[1].Type.Equals(stringComparisonType);
  72. }
  73. }
  74. // all other overloads are unacceptable
  75. return false;
  76. }
  77. protected static bool IsAcceptableStaticOverload(IMethodSymbol methodSymbol, INamedTypeSymbol stringComparisonType)
  78. {
  79. if (string.Equals(methodSymbol.Name, CompareMethodName, StringComparison.Ordinal))
  80. {
  81. switch (methodSymbol.Parameters.Length)
  82. {
  83. case 3:
  84. // (string, string, StringComparison) is acceptable
  85. return methodSymbol.Parameters[0].Type.SpecialType == SpecialType.System_String &&
  86. methodSymbol.Parameters[1].Type.SpecialType == SpecialType.System_String &&
  87. methodSymbol.Parameters[2].Type.Equals(stringComparisonType);
  88. case 6:
  89. // (string, int, string, int, int, StringComparison) is acceptable
  90. return methodSymbol.Parameters[0].Type.SpecialType == SpecialType.System_String &&
  91. methodSymbol.Parameters[1].Type.SpecialType == SpecialType.System_Int32 &&
  92. methodSymbol.Parameters[2].Type.SpecialType == SpecialType.System_String &&
  93. methodSymbol.Parameters[3].Type.SpecialType == SpecialType.System_Int32 &&
  94. methodSymbol.Parameters[4].Type.SpecialType == SpecialType.System_Int32 &&
  95. methodSymbol.Parameters[5].Type.Equals(stringComparisonType);
  96. }
  97. }
  98. else if (string.Equals(methodSymbol.Name, EqualsMethodName, StringComparison.Ordinal))
  99. {
  100. switch (methodSymbol.Parameters.Length)
  101. {
  102. case 2:
  103. // (object, object) is acceptable
  104. return methodSymbol.Parameters[0].Type.SpecialType == SpecialType.System_Object &&
  105. methodSymbol.Parameters[1].Type.SpecialType == SpecialType.System_Object;
  106. case 3:
  107. // (string, string, StringComparison) is acceptable
  108. return methodSymbol.Parameters[0].Type.SpecialType == SpecialType.System_String &&
  109. methodSymbol.Parameters[1].Type.SpecialType == SpecialType.System_String &&
  110. methodSymbol.Parameters[2].Type.Equals(stringComparisonType);
  111. }
  112. }
  113. // all other overloads are unacceptable
  114. return false;
  115. }
  116. protected static bool IsOrdinalOrOrdinalIgnoreCase(string name)
  117. {
  118. return string.Compare(name, OrdinalText, StringComparison.Ordinal) == 0 ||
  119. string.Compare(name, OrdinalIgnoreCaseText, StringComparison.Ordinal) == 0;
  120. }
  121. }
  122. }
  123. }