Skip to content

Commit

Permalink
Consider pure functions as part of CA1806. Fixes dotnet#1164.
Browse files Browse the repository at this point in the history
  • Loading branch information
333fred committed Apr 27, 2017
1 parent a555339 commit 2b60c74
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/Analyzer.Utilities/WellKnownTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -340,5 +340,10 @@ public static INamedTypeSymbol ObsoleteAttribute(Compilation compilation)
{
return compilation.GetTypeByMetadataName("System.ObsoleteAttribute");
}

public static INamedTypeSymbol PureAttribute(Compilation compilation)
{
return compilation.GetTypeByMetadataName("System.Diagnostics.Contracts.PureAttribute");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Semantics;
using System.Diagnostics.Contracts;
using System.Linq;

namespace Microsoft.Maintainability.Analyzers
{
Expand Down Expand Up @@ -46,6 +48,7 @@ public sealed class DoNotIgnoreMethodResultsAnalyzer : DiagnosticAnalyzer
private static readonly LocalizableString s_localizableMessageObjectCreation = new LocalizableResourceString(nameof(MicrosoftMaintainabilityAnalyzersResources.DoNotIgnoreMethodResultsMessageObjectCreation), MicrosoftMaintainabilityAnalyzersResources.ResourceManager, typeof(MicrosoftMaintainabilityAnalyzersResources));
private static readonly LocalizableString s_localizableMessageStringCreation = new LocalizableResourceString(nameof(MicrosoftMaintainabilityAnalyzersResources.DoNotIgnoreMethodResultsMessageStringCreation), MicrosoftMaintainabilityAnalyzersResources.ResourceManager, typeof(MicrosoftMaintainabilityAnalyzersResources));
private static readonly LocalizableString s_localizableMessageHResultOrErrorCode = new LocalizableResourceString(nameof(MicrosoftMaintainabilityAnalyzersResources.DoNotIgnoreMethodResultsMessageHResultOrErrorCode), MicrosoftMaintainabilityAnalyzersResources.ResourceManager, typeof(MicrosoftMaintainabilityAnalyzersResources));
private static readonly LocalizableString s_localizableMessagePureMethod = new LocalizableResourceString(nameof(MicrosoftMaintainabilityAnalyzersResources.DoNotIgnoreMethodResultsMessagePureMethod), MicrosoftMaintainabilityAnalyzersResources.ResourceManager, typeof(MicrosoftMaintainabilityAnalyzersResources));
private static readonly LocalizableString s_localizableMessageTryParse = new LocalizableResourceString(nameof(MicrosoftMaintainabilityAnalyzersResources.DoNotIgnoreMethodResultsMessageTryParse), MicrosoftMaintainabilityAnalyzersResources.ResourceManager, typeof(MicrosoftMaintainabilityAnalyzersResources));
private static readonly LocalizableString s_localizableDescription = new LocalizableResourceString(nameof(MicrosoftMaintainabilityAnalyzersResources.DoNotIgnoreMethodResultsDescription), MicrosoftMaintainabilityAnalyzersResources.ResourceManager, typeof(MicrosoftMaintainabilityAnalyzersResources));

Expand Down Expand Up @@ -79,6 +82,17 @@ public sealed class DoNotIgnoreMethodResultsAnalyzer : DiagnosticAnalyzer
helpLinkUri: "https://msdn.microsoft.com/en-us/library/ms182273.aspx",
customTags: WellKnownDiagnosticTags.Telemetry);

internal static DiagnosticDescriptor PureMethodRule = new DiagnosticDescriptor(RuleId,
s_localizableTitle,
s_localizableMessagePureMethod,
DiagnosticCategory.Performance,
DiagnosticHelpers.DefaultDiagnosticSeverity,
isEnabledByDefault: true,
description: s_localizableDescription,
helpLinkUri: "https://msdn.microsoft.com/en-us/library/ms182273.aspx",
customTags: WellKnownDiagnosticTags.Telemetry);


internal static DiagnosticDescriptor TryParseRule = new DiagnosticDescriptor(RuleId,
s_localizableTitle,
s_localizableMessageTryParse,
Expand Down Expand Up @@ -140,6 +154,10 @@ public override void Initialize(AnalysisContext analysisContext)
{
rule = HResultOrErrorCodeRule;
}
else if (IsPureMethod(targetMethod, opContext.Compilation))
{
rule = PureMethodRule;
}

targetMethodName = targetMethod.Name;
break;
Expand Down Expand Up @@ -175,5 +193,10 @@ private static bool IsHResultOrErrorCodeReturningMethod(IMethodSymbol method)
(method.ReturnType.SpecialType == SpecialType.System_Int32 ||
method.ReturnType.SpecialType == SpecialType.System_UInt32);
}

private static bool IsPureMethod(IMethodSymbol method, Compilation compilation)
{
return method.GetAttributes().Any(attr => attr.AttributeClass.Equals(WellKnownTypes.PureAttribute(compilation)));
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,7 @@
<data name="CategoryPerformance" xml:space="preserve">
<value>Performance</value>
</data>
<data name="DoNotIgnoreMethodResultsMessagePureMethod" xml:space="preserve">
<value>{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.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,43 @@ End Interface
GetBasicHResultOrErrorCodeResultAt(6, 9, "M", "NativeMethod"));
}

[Fact]
[WorkItem(1164, "https://github.com/dotnet/roslyn-analyzers/issues/1164")]
public void UnusedPureMethodTriggersError()
{
VerifyCSharp(@"
using System.Diagnostics.Contracts;
class C
{
[Pure]
public int Returns1() => 1;
public void DoesNotUseResult()
{
Returns1();
}
}",
GetCSharpPureMethodResultAt(11, 9, "DoesNotUseResult", "Returns1"));

VerifyBasic(@"
Imports System.Diagnostics.Contracts
Module Module1
<Pure>
Function Returns1() As Integer
Return 1
End Function
Sub DoesNotUseResult()
Returns1()
End Sub
End Module
",
GetBasicPureMethodResultAt(11, 9, "DoesNotUseResult", "Returns1"));
}

#endregion

#region Helpers
Expand Down Expand Up @@ -308,6 +345,18 @@ private static DiagnosticResult GetBasicHResultOrErrorCodeResultAt(int line, int
return GetBasicResultAt(line, column, DoNotIgnoreMethodResultsAnalyzer.RuleId, message);
}

private static DiagnosticResult GetCSharpPureMethodResultAt(int line, int column, string containingMethodName, string invokedMethodName)
{
string message = string.Format(MicrosoftMaintainabilityAnalyzersResources.DoNotIgnoreMethodResultsMessagePureMethod, containingMethodName, invokedMethodName);
return GetCSharpResultAt(line, column, DoNotIgnoreMethodResultsAnalyzer.RuleId, message);
}

private static DiagnosticResult GetBasicPureMethodResultAt(int line, int column, string containingMethodName, string invokedMethodName)
{
string message = string.Format(MicrosoftMaintainabilityAnalyzersResources.DoNotIgnoreMethodResultsMessagePureMethod, containingMethodName, invokedMethodName);
return GetBasicResultAt(line, column, DoNotIgnoreMethodResultsAnalyzer.RuleId, message);
}

#endregion
}
}

0 comments on commit 2b60c74

Please sign in to comment.