Skip to content

Commit 10068ba

Browse files
committed
REFL023 The type does not implement the interface. #23
1 parent af735b2 commit 10068ba

File tree

9 files changed

+218
-1
lines changed

9 files changed

+218
-1
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,9 @@ Analyzers checking System.Reflection
8080
<td><a href="https://github.com/DotNetAnalyzers/ReflectionAnalyzers/tree/master/documentation/REFL020.md">REFL020</a></td>
8181
<td>More than one interface is matching the name.</td>
8282
</tr>
83+
<tr>
84+
<td><a href="https://github.com/DotNetAnalyzers/ReflectionAnalyzers/tree/master/documentation/REFL023.md">REFL023</a></td>
85+
<td>The type does not implement the interface.</td>
86+
</tr>
8387
<table>
8488
<!-- end generated table -->
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
namespace ReflectionAnalyzers.Tests.REFL023TypeDoesNotImplementInterfaceTests
2+
{
3+
using Gu.Roslyn.Asserts;
4+
using Microsoft.CodeAnalysis.Diagnostics;
5+
using NUnit.Framework;
6+
7+
public class Diagnostics
8+
{
9+
private static readonly DiagnosticAnalyzer Analyzer = new GetInterfaceAnalyzer();
10+
private static readonly ExpectedDiagnostic ExpectedDiagnostic = ExpectedDiagnostic.Create(REFL023TypeDoesNotImplementInterface.Descriptor);
11+
12+
[TestCase("GetInterface(↓\"System.Collections.Generic.IEnumerable`1\")")]
13+
[TestCase("GetInterface(↓\"IEnumerable`1\")")]
14+
[TestCase("GetInterface(typeof(IEnumerable<>).FullName)")]
15+
public void GetInterface(string call)
16+
{
17+
var code = @"
18+
namespace RoslynSandbox
19+
{
20+
using System;
21+
using System.Collections;
22+
using System.Collections.Generic;
23+
24+
public class Foo
25+
{
26+
public Foo()
27+
{
28+
var type = typeof(Foo).GetInterface(↓""System.Collections.Generic.IEnumerable`1"");
29+
}
30+
}
31+
}".AssertReplace("GetInterface(↓\"System.Collections.Generic.IEnumerable`1\")", call);
32+
33+
AnalyzerAssert.Diagnostics(Analyzer, ExpectedDiagnostic, code);
34+
}
35+
}
36+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
namespace ReflectionAnalyzers.Tests.REFL023TypeDoesNotImplementInterfaceTests
2+
{
3+
using Gu.Roslyn.Asserts;
4+
using Microsoft.CodeAnalysis.Diagnostics;
5+
using NUnit.Framework;
6+
7+
public class ValidCode
8+
{
9+
private static readonly DiagnosticAnalyzer Analyzer = new GetInterfaceAnalyzer();
10+
private static readonly ExpectedDiagnostic ExpectedDiagnostic = ExpectedDiagnostic.Create(REFL023TypeDoesNotImplementInterface.Descriptor);
11+
12+
[TestCase("GetInterface(\"System.Collections.Generic.IEnumerable`1\")")]
13+
[TestCase("GetInterface(\"IEnumerable`1\")")]
14+
[TestCase("GetInterface(typeof(IEnumerable).FullName)")]
15+
[TestCase("GetInterface(typeof(IEnumerable).Name)")]
16+
[TestCase("GetInterface(typeof(IEnumerable<>).FullName)")]
17+
[TestCase("GetInterface(typeof(IEnumerable<>).Name)")]
18+
[TestCase("GetInterface(\"IEnumerable\")")]
19+
[TestCase("GetInterface(\"System.Collections.IEnumerable\")")]
20+
public void GetInterface(string call)
21+
{
22+
var code = @"
23+
namespace RoslynSandbox
24+
{
25+
using System.Collections;
26+
using System.Collections.Generic;
27+
28+
public class Foo : IEnumerable<int>
29+
{
30+
private readonly List<int> ints = new List<int>();
31+
32+
public Foo()
33+
{
34+
var type = typeof(Foo).GetInterface(""System.Collections.Generic.IEnumerable`1"");
35+
}
36+
37+
public IEnumerator<int> GetEnumerator() => this.ints.GetEnumerator();
38+
39+
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
40+
}
41+
}".AssertReplace("GetInterface(\"System.Collections.Generic.IEnumerable`1\")", call);
42+
43+
AnalyzerAssert.Valid(Analyzer, ExpectedDiagnostic, code);
44+
}
45+
}
46+
}

ReflectionAnalyzers.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".docs", ".docs", "{1C271AF2
5050
documentation\REFL018.md = documentation\REFL018.md
5151
documentation\REFL019.md = documentation\REFL019.md
5252
documentation\REFL020.md = documentation\REFL020.md
53+
documentation\REFL023.md = documentation\REFL023.md
5354
RELEASE_NOTES.md = RELEASE_NOTES.md
5455
EndProjectSection
5556
EndProject

ReflectionAnalyzers/NodeAnalzers/GetInterfaceAnalyzer.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ internal class GetInterfaceAnalyzer : DiagnosticAnalyzer
1313
{
1414
/// <inheritdoc/>
1515
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(
16-
REFL020AmbiguousMatchInterface.Descriptor);
16+
REFL020AmbiguousMatchInterface.Descriptor,
17+
REFL023TypeDoesNotImplementInterface.Descriptor);
1718

1819
/// <inheritdoc/>
1920
public override void Initialize(AnalysisContext context)
@@ -38,6 +39,11 @@ context.Node is InvocationExpressionSyntax invocation &&
3839
{
3940
context.ReportDiagnostic(Diagnostic.Create(REFL020AmbiguousMatchInterface.Descriptor, nameArg.GetLocation()));
4041
}
42+
43+
if (count == 0)
44+
{
45+
context.ReportDiagnostic(Diagnostic.Create(REFL023TypeDoesNotImplementInterface.Descriptor, nameArg.GetLocation()));
46+
}
4147
}
4248

4349
bool IsMatch(ITypeSymbol candidate)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace ReflectionAnalyzers
2+
{
3+
using Microsoft.CodeAnalysis;
4+
5+
internal static class REFL021TypeDoesNotExist
6+
{
7+
public const string DiagnosticId = "REFL021";
8+
9+
internal static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
10+
id: DiagnosticId,
11+
title: "The type does not exist.",
12+
messageFormat: "The type does not exist.",
13+
category: AnalyzerCategory.SystemReflection,
14+
defaultSeverity: DiagnosticSeverity.Warning,
15+
isEnabledByDefault: true,
16+
description: "The type does not exist.",
17+
helpLinkUri: HelpLink.ForId(DiagnosticId));
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace ReflectionAnalyzers
2+
{
3+
using Microsoft.CodeAnalysis;
4+
5+
internal static class REFL022UseFullyQualifiedName
6+
{
7+
public const string DiagnosticId = "REFL022";
8+
9+
internal static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
10+
id: DiagnosticId,
11+
title: "Use fully qualified name.",
12+
messageFormat: "Use fully qualified name {0}.",
13+
category: AnalyzerCategory.SystemReflection,
14+
defaultSeverity: DiagnosticSeverity.Warning,
15+
isEnabledByDefault: true,
16+
description: "Use fully qualified name.",
17+
helpLinkUri: HelpLink.ForId(DiagnosticId));
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace ReflectionAnalyzers
2+
{
3+
using Microsoft.CodeAnalysis;
4+
5+
internal static class REFL023TypeDoesNotImplementInterface
6+
{
7+
public const string DiagnosticId = "REFL023";
8+
9+
internal static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
10+
id: DiagnosticId,
11+
title: "The type does not implement the interface.",
12+
messageFormat: "The type does not implement the interface.",
13+
category: AnalyzerCategory.SystemReflection,
14+
defaultSeverity: DiagnosticSeverity.Warning,
15+
isEnabledByDefault: true,
16+
description: "The type does not implement the interface.",
17+
helpLinkUri: HelpLink.ForId(DiagnosticId));
18+
}
19+
}

documentation/REFL023.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# REFL023
2+
## The type does not implement the interface.
3+
4+
<!-- start generated table -->
5+
<table>
6+
<tr>
7+
<td>CheckId</td>
8+
<td>REFL023</td>
9+
</tr>
10+
<tr>
11+
<td>Severity</td>
12+
<td>Warning</td>
13+
</tr>
14+
<tr>
15+
<td>Enabled</td>
16+
<td>true</td>
17+
</tr>
18+
<tr>
19+
<td>Category</td>
20+
<td>ReflectionAnalyzers.SystemReflection</td>
21+
</tr>
22+
<tr>
23+
<td>Code</td>
24+
<td><a href="https://github.com/DotNetAnalyzers/ReflectionAnalyzers/blob/master/ReflectionAnalyzers/NodeAnalzers/GetInterfaceAnalyzer.cs">GetInterfaceAnalyzer</a></td>
25+
</tr>
26+
</table>
27+
<!-- end generated table -->
28+
29+
## Description
30+
31+
The type does not implement the interface.
32+
33+
## Motivation
34+
35+
ADD MOTIVATION HERE
36+
37+
## How to fix violations
38+
39+
ADD HOW TO FIX VIOLATIONS HERE
40+
41+
<!-- start generated config severity -->
42+
## Configure severity
43+
44+
### Via ruleset file.
45+
46+
Configure the severity per project, for more info see [MSDN](https://msdn.microsoft.com/en-us/library/dd264949.aspx).
47+
48+
### Via #pragma directive.
49+
```C#
50+
#pragma warning disable REFL023 // The type does not implement the interface.
51+
Code violating the rule here
52+
#pragma warning restore REFL023 // The type does not implement the interface.
53+
```
54+
55+
Or put this at the top of the file to disable all instances.
56+
```C#
57+
#pragma warning disable REFL023 // The type does not implement the interface.
58+
```
59+
60+
### Via attribute `[SuppressMessage]`.
61+
62+
```C#
63+
[System.Diagnostics.CodeAnalysis.SuppressMessage("ReflectionAnalyzers.SystemReflection",
64+
"REFL023:The type does not implement the interface.",
65+
Justification = "Reason...")]
66+
```
67+
<!-- end generated config severity -->

0 commit comments

Comments
 (0)