Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1f4234a
Add ConstantExpectedAnalyzer
wzchua Feb 25, 2022
f39fc60
Fix floating point string culture issue
wzchua Feb 25, 2022
74d9533
Update tests
wzchua Feb 25, 2022
d13a77e
Fix typos
wzchua Feb 25, 2022
8b3d43e
Rework test cases
wzchua Feb 25, 2022
d4fe364
run pack command
wzchua Feb 25, 2022
5f8922f
Reorganize and combine some rules.
wzchua Feb 25, 2022
7b883e0
Apply suggestions from code review
wzchua Feb 25, 2022
f784732
Merge branch 'main' into new-analyzer/constant-expected
wzchua May 28, 2022
d12e2fb
Apply suggestion from feedback
wzchua May 29, 2022
9d4c1a3
Merge branch 'main' into new-analyzer/constant-expected
wzchua Jul 16, 2022
db80589
Apply suggestions from code review
wzchua Jul 16, 2022
68e6e28
Apply suggestions from code review
wzchua Jul 16, 2022
52f5e3f
rebuild
wzchua Jul 16, 2022
f991607
Use const variable for Min Max literal
wzchua Jul 16, 2022
eab469f
Drop nint nuint support from ConstantExpected
wzchua Jul 16, 2022
5e1b4c3
Add early exit if symbol for attribute is not found
wzchua Jul 16, 2022
e7ac792
Add check for enums
wzchua Jul 23, 2022
1196110
Merge branch 'main' into new-analyzer/constant-expected
wzchua Aug 27, 2022
65de245
Fix RS1032
wzchua Aug 27, 2022
04ad5b1
Fix IDE0200: Lambda expression can be removed
wzchua Aug 27, 2022
011d9eb
Rework attribute symbol matching
wzchua Aug 27, 2022
ec3f1ae
Update diagnostic Ids
wzchua Aug 27, 2022
59fdd58
Update test to use ReferenceAssemblies.Net70
wzchua Aug 27, 2022
865974c
Add performance tests
wzchua Aug 27, 2022
c87ee13
Apply suggestions from code review
buyaa-n Sep 13, 2022
5f07e36
Update localized messages
buyaa-n Sep 13, 2022
7c8b93b
Merge branch 'main' into new-analyzer/constant-expected
wzchua Nov 12, 2022
266fba8
Run pack
wzchua Nov 12, 2022
86dbee4
Merge branch 'main' into new-analyzer/constant-expected
buyaa-n Nov 16, 2022
774008b
Apply suggestions from code review
buyaa-n Nov 16, 2022
ca89072
Fix generated file
buyaa-n Nov 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rework test cases
Add new warning for missing attribute from interface or base class
  • Loading branch information
wzchua committed Feb 25, 2022
commit 8b3d43e8c76319a60d76a62b5a6bc94456880282
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ protected override void RegisterAttributeSyntax(CompilationStartAnalysisContext
private void OnAttributeNode(SyntaxNodeAnalysisContext context)
{
var attributeSyntax = (AttributeSyntax)context.Node;
var sm = context.SemanticModel;
if (!attributeSyntax.Name.IsEquivalentTo(_constantExpectedIdentifier) && !attributeSyntax.Name.IsEquivalentTo(_constantExpectedAttributeIdentifier))
{
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1870,6 +1870,9 @@
<data name="ConstantExpectedAttributeOutOfBoundsMessage" xml:space="preserve">
<value>The ConstantExpectedAttribute does not fit within the parameter value bounds of '{0}' to '{1}'.</value>
</data>
<data name="ConstantExpectedAttributExpectedMessage" xml:space="preserve">
<value>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</value>
Comment thread
wzchua marked this conversation as resolved.
Outdated
Comment thread
wzchua marked this conversation as resolved.
Outdated
</data>
<data name="ConstantExpectedAttributeNotSameTypeMessage" xml:space="preserve">
<value>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ public abstract partial class ConstantExpectedAnalyzer : DiagnosticAnalyzer
isPortedFxCopRule: false,
isDataflowRule: false);

internal static readonly DiagnosticDescriptor AttributeExpectedRule = DiagnosticDescriptorHelper.Create(
CA1861,
s_localizableUsageTitle,
CreateLocalizableResourceString(nameof(ConstantExpectedAttributExpectedMessage)),
DiagnosticCategory.Performance,
RuleLevel.BuildWarning,
description: s_localizableUsageDescription,
isPortedFxCopRule: false,
isDataflowRule: false);

internal static readonly DiagnosticDescriptor AttributeNotSameTypeRule = DiagnosticDescriptorHelper.Create(
CA1861,
s_localizableUsageTitle,
Expand All @@ -115,7 +125,7 @@ public abstract partial class ConstantExpectedAnalyzer : DiagnosticAnalyzer
isDataflowRule: false);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(
InvalidTypeRule, IncompatibleConstantTypeRule, IncompatibleConstantForMinMaxRule, InvalidBoundsRule, InvertedRangeRule,
ConstantOutOfBoundsRule, ConstantNotConstantRule, AttributeOutOfBoundsRule, AttributeNotSameTypeRule);
ConstantOutOfBoundsRule, ConstantNotConstantRule, AttributeOutOfBoundsRule, AttributeExpectedRule, AttributeNotSameTypeRule);

protected abstract DiagnosticHelper Helper { get; }

Expand All @@ -129,9 +139,40 @@ public override void Initialize(AnalysisContext context)
private void OnCompilationStart(CompilationStartAnalysisContext context)
{
context.RegisterOperationAction(OnInvocation, OperationKind.Invocation);
context.RegisterSymbolAction(context => OnMethodSymbol(context), SymbolKind.Method);
RegisterAttributeSyntax(context);
return;
Comment thread
wzchua marked this conversation as resolved.
Outdated
}
private static void OnMethodSymbol(SymbolAnalysisContext context)
{
var methodSymbol = (IMethodSymbol)context.Symbol;
if (TryGetMethodInterface(methodSymbol, out var interfaceMethodSymbol))
{
CheckAttribute(context, methodSymbol.Parameters, interfaceMethodSymbol.Parameters);
}
else if (methodSymbol.OverriddenMethod is not null)
{
CheckAttribute(context, methodSymbol.Parameters, methodSymbol.OverriddenMethod.Parameters);
}

static void CheckAttribute(SymbolAnalysisContext context, ImmutableArray<IParameterSymbol> parameters, ImmutableArray<IParameterSymbol> baseParameters)
{
for (var i = 0; i < parameters.Length; i++)
{
var parameter = parameters[i];
if (!IsConstantCompatible(parameter.Type))
{
continue;
}
var baseParameter = baseParameters[i];
if (HasConstantExpectedAttributeData(baseParameter) && !HasConstantExpectedAttributeData(parameter))
{
var diagnostic = parameter.DeclaringSyntaxReferences[0].GetSyntax().CreateDiagnostic(AttributeExpectedRule);
context.ReportDiagnostic(diagnostic);
}
}
}
}

private static void OnInvocation(OperationAnalysisContext context)
{
Expand Down Expand Up @@ -299,6 +340,12 @@ private static bool TryGetConstantExpectedAttributeData(IParameterSymbol paramet
return constantExpectedAttributeData is not null;
}

private static bool HasConstantExpectedAttributeData(IParameterSymbol parameter)
{
return parameter.GetAttributes()
.Any(attrData => IsConstantExpectedAttribute(attrData.AttributeClass));
}

private static bool IsConstantExpectedAttribute(INamedTypeSymbol namedType)
{
return namedType.Name.Equals(ConstantExpectedAttribute, StringComparison.Ordinal) &&
Comment thread
wzchua marked this conversation as resolved.
Outdated
Expand Down Expand Up @@ -396,6 +443,7 @@ public static (object? MinConstant, object? MaxConstant) GetAttributeConstants(A
}

return (minConstant, maxConstant);

static object? ToObject(TypedConstant typedConstant)
{
if (typedConstant.IsNull)
Expand All @@ -406,6 +454,59 @@ public static (object? MinConstant, object? MaxConstant) GetAttributeConstants(A
}
}

private static bool TryGetMethodInterface(IMethodSymbol methodSymbol, [NotNullWhen(true)] out IMethodSymbol? interfaceMethodSymbol)
{
var explicitInterface = methodSymbol.ExplicitInterfaceImplementations
.FirstOrDefault(exInterface => methodSymbol.IsImplementationOfInterfaceMember(exInterface));
if (explicitInterface is not null)
{
interfaceMethodSymbol = explicitInterface;
return true;
}

if (methodSymbol.ContainingType != null)
Comment thread
wzchua marked this conversation as resolved.
Outdated
{
foreach (INamedTypeSymbol interfaceSymbol in methodSymbol.ContainingType.AllInterfaces)
{
foreach (var interfaceMember in interfaceSymbol.GetMembers().OfType<IMethodSymbol>())
{
if (methodSymbol.IsImplementationOfInterfaceMember(interfaceMember))
{
interfaceMethodSymbol = interfaceMember;
return true;
}
}
}
}

interfaceMethodSymbol = null;
return false;
}

private static bool IsConstantCompatible(ITypeSymbol type)
{
return type.SpecialType switch
{
SpecialType.System_Char => true,
SpecialType.System_Byte => true,
SpecialType.System_UInt16 => true,
SpecialType.System_UInt32 => true,
SpecialType.System_UInt64 => true,
SpecialType.System_UIntPtr => true,
SpecialType.System_SByte => true,
SpecialType.System_Int16 => true,
SpecialType.System_Int32 => true,
SpecialType.System_Int64 => true,
SpecialType.System_IntPtr => true,
SpecialType.System_Single => true,
SpecialType.System_Double => true,
SpecialType.System_Boolean => true,
SpecialType.System_String => true,
SpecialType.None when type.TypeKind == TypeKind.TypeParameter => true,
_ => false,
};
}

protected abstract class DiagnosticHelper
{
public abstract Location? GetMinLocation(SyntaxNode attributeSyntax);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<target state="new">Incorrect use of ConstantExpectedAttribute</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributExpectedMessage">
<source>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</source>
<target state="new">The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributeNotSameTypeMessage">
<source>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</source>
<target state="new">The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<target state="new">Incorrect use of ConstantExpectedAttribute</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributExpectedMessage">
<source>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</source>
<target state="new">The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributeNotSameTypeMessage">
<source>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</source>
<target state="new">The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<target state="new">Incorrect use of ConstantExpectedAttribute</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributExpectedMessage">
<source>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</source>
<target state="new">The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributeNotSameTypeMessage">
<source>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</source>
<target state="new">The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<target state="new">Incorrect use of ConstantExpectedAttribute</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributExpectedMessage">
<source>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</source>
<target state="new">The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributeNotSameTypeMessage">
<source>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</source>
<target state="new">The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<target state="new">Incorrect use of ConstantExpectedAttribute</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributExpectedMessage">
<source>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</source>
<target state="new">The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributeNotSameTypeMessage">
<source>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</source>
<target state="new">The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<target state="new">Incorrect use of ConstantExpectedAttribute</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributExpectedMessage">
<source>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</source>
<target state="new">The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributeNotSameTypeMessage">
<source>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</source>
<target state="new">The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<target state="new">Incorrect use of ConstantExpectedAttribute</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributExpectedMessage">
<source>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</source>
<target state="new">The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributeNotSameTypeMessage">
<source>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</source>
<target state="new">The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<target state="new">Incorrect use of ConstantExpectedAttribute</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributExpectedMessage">
<source>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</source>
<target state="new">The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributeNotSameTypeMessage">
<source>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</source>
<target state="new">The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<target state="new">Incorrect use of ConstantExpectedAttribute</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributExpectedMessage">
<source>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</source>
<target state="new">The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributeNotSameTypeMessage">
<source>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</source>
<target state="new">The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<target state="new">Incorrect use of ConstantExpectedAttribute</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributExpectedMessage">
<source>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</source>
<target state="new">The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributeNotSameTypeMessage">
<source>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</source>
<target state="new">The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<target state="new">Incorrect use of ConstantExpectedAttribute</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributExpectedMessage">
<source>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</source>
<target state="new">The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributeNotSameTypeMessage">
<source>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</source>
<target state="new">The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<target state="new">Incorrect use of ConstantExpectedAttribute</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributExpectedMessage">
<source>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</source>
<target state="new">The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributeNotSameTypeMessage">
<source>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</source>
<target state="new">The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<target state="new">Incorrect use of ConstantExpectedAttribute</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributExpectedMessage">
<source>The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</source>
<target state="new">The ConstantExpectedAttribute expected for the parameter due to the interface/base method.</target>
<note />
</trans-unit>
<trans-unit id="ConstantExpectedAttributeNotSameTypeMessage">
<source>The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</source>
<target state="new">The ConstantExpectedAttribute does not have the same '{0}' type as the ConstantExpectedAttribute in the invoked method parameter.</target>
Expand Down
Loading