diff --git a/Directory.Build.props b/Directory.Build.props
index 86609829..c1307957 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -4,5 +4,6 @@
10.0
true
true
+ enable
diff --git a/src/D2L.CodeStyle.Analyzers/D2L.CodeStyle.Analyzers.csproj b/src/D2L.CodeStyle.Analyzers/D2L.CodeStyle.Analyzers.csproj
index 1d0b724d..4cd61a0b 100644
--- a/src/D2L.CodeStyle.Analyzers/D2L.CodeStyle.Analyzers.csproj
+++ b/src/D2L.CodeStyle.Analyzers/D2L.CodeStyle.Analyzers.csproj
@@ -17,7 +17,6 @@
True
False
True
- enable
CA2016,Nullable
false
true
diff --git a/src/D2L.CodeStyle.TestAnalyzers/Common/NotNullWhenAttribute.cs b/src/D2L.CodeStyle.TestAnalyzers/Common/NotNullWhenAttribute.cs
new file mode 100644
index 00000000..461512e8
--- /dev/null
+++ b/src/D2L.CodeStyle.TestAnalyzers/Common/NotNullWhenAttribute.cs
@@ -0,0 +1,14 @@
+#if !NETSTANDARD2_1
+
+namespace System.Diagnostics.CodeAnalysis;
+
+[AttributeUsage( AttributeTargets.Parameter )]
+internal sealed class NotNullWhenAttribute : Attribute {
+ public bool ReturnValue { get; }
+
+ public NotNullWhenAttribute( bool returnValue ) {
+ ReturnValue = returnValue;
+ }
+}
+
+#endif
diff --git a/src/D2L.CodeStyle.TestAnalyzers/Extensions/Microsoft.CodeAnalysis.cs b/src/D2L.CodeStyle.TestAnalyzers/Extensions/Microsoft.CodeAnalysis.cs
index d4c6c59e..059370c2 100644
--- a/src/D2L.CodeStyle.TestAnalyzers/Extensions/Microsoft.CodeAnalysis.cs
+++ b/src/D2L.CodeStyle.TestAnalyzers/Extensions/Microsoft.CodeAnalysis.cs
@@ -9,7 +9,7 @@ public static class RoslynExtensions {
// Copied from the non-test assembly because we do not reference it.
- public static bool IsNullOrErrorType( this ITypeSymbol symbol ) {
+ public static bool IsNullOrErrorType( this ITypeSymbol? symbol ) {
if( symbol == null ) {
return true;
@@ -26,6 +26,19 @@ public static bool IsNullOrErrorType( this ITypeSymbol symbol ) {
return false;
}
+ public static bool IsErrorType( this ITypeSymbol symbol ) {
+
+ if( symbol.Kind == SymbolKind.ErrorType ) {
+ return true;
+ }
+
+ if( symbol.TypeKind == TypeKind.Error ) {
+ return true;
+ }
+
+ return false;
+ }
+
public static bool IsNullOrErrorType( this ISymbol symbol ) {
if( symbol == null ) {
diff --git a/src/D2L.CodeStyle.TestAnalyzers/NUnit/CategoryAnalyzer.cs b/src/D2L.CodeStyle.TestAnalyzers/NUnit/CategoryAnalyzer.cs
index faf8fab8..b5c5582c 100644
--- a/src/D2L.CodeStyle.TestAnalyzers/NUnit/CategoryAnalyzer.cs
+++ b/src/D2L.CodeStyle.TestAnalyzers/NUnit/CategoryAnalyzer.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using D2L.CodeStyle.TestAnalyzers.Common;
@@ -42,7 +43,7 @@ public override void Initialize( AnalysisContext context ) {
}
private static void OnCompilationStart( CompilationStartAnalysisContext context ) {
- if( !TryLoadNUnitTypes( context.Compilation, out NUnitTypes types ) ) {
+ if( !TryLoadNUnitTypes( context.Compilation, out NUnitTypes? types ) ) {
return;
}
@@ -53,7 +54,7 @@ private static void OnCompilationStart( CompilationStartAnalysisContext context
context: ctx,
bannedCategories: bannedCategories,
types: types,
- syntax: ctx.Node as MethodDeclarationSyntax
+ syntax: (ctx.Node as MethodDeclarationSyntax)!
),
SyntaxKind.MethodDeclaration
);
@@ -69,9 +70,16 @@ private static void OnCompilationEnd( CompilationAnalysisContext context, NUnitT
return;
}
+ var syntaxReference = attribute.ApplicationSyntaxReference;
+
+ if( syntaxReference == null ) {
+ // ??
+ return;
+ }
+
context.ReportDiagnostic( Diagnostic.Create(
Diagnostics.NUnitCategory,
- attribute.ApplicationSyntaxReference.GetSyntax( context.CancellationToken ).GetLocation(),
+ syntaxReference.GetSyntax( context.CancellationToken ).GetLocation(),
$"Assemblies cannot be categorized as any of [{string.Join( ", ", ProhibitedAssemblyCategories )}], but saw '{category}'."
) );
} );
@@ -85,7 +93,7 @@ MethodDeclarationSyntax syntax
) {
SemanticModel model = context.SemanticModel;
- IMethodSymbol method = model.GetDeclaredSymbol( syntax, context.CancellationToken );
+ IMethodSymbol? method = model.GetDeclaredSymbol( syntax, context.CancellationToken );
if( method == null ) {
return;
}
@@ -117,8 +125,8 @@ private static bool IsTestMethod(
IMethodSymbol method
) {
foreach( AttributeData attribute in method.GetAttributes() ) {
- INamedTypeSymbol attributeType = attribute.AttributeClass;
- if( types.TestAttributes.Contains( attributeType ) ) {
+ INamedTypeSymbol? attributeType = attribute.AttributeClass;
+ if( attributeType != null && types.TestAttributes.Contains( attributeType ) ) {
return true;
}
}
@@ -159,7 +167,7 @@ private static void VisitCategories(
Action visitor
) {
foreach( AttributeData attribute in symbol.GetAttributes() ) {
- INamedTypeSymbol attributeType = attribute.AttributeClass;
+ INamedTypeSymbol? attributeType = attribute.AttributeClass;
if( types.CategoryAttribute.Equals( attributeType, SymbolEqualityComparer.Default ) ) {
VisitCategoryAttribute( attribute, visitor );
continue;
@@ -189,11 +197,16 @@ Action visitor
TypedConstant arg = args[0];
- if( arg.Type.SpecialType != SpecialType.System_String ) {
+ if( arg.Type?.SpecialType != SpecialType.System_String ) {
+ return;
+ }
+
+ string? category = arg.Value as string;
+
+ if( category == null ) {
return;
}
- string category = arg.Value as string;
visitor( category, attribute );
}
@@ -208,11 +221,16 @@ Action visitor
TypedConstant arg = namedArg.Value;
- if( arg.Type.SpecialType != SpecialType.System_String ) {
+ if( arg.Type?.SpecialType != SpecialType.System_String ) {
+ continue;
+ }
+
+ string? categoryCsv = arg.Value as string;
+
+ if( categoryCsv == null ) {
continue;
}
- string categoryCsv = arg.Value as string;
foreach( string category in categoryCsv.Split( ',' ) ) {
visitor( category.Trim(), attribute );
}
@@ -221,24 +239,29 @@ Action visitor
private static bool TryLoadNUnitTypes(
Compilation compilation,
- out NUnitTypes types
+ [NotNullWhen( true )]
+ out NUnitTypes? types
) {
- INamedTypeSymbol categoryAttribute = compilation.GetTypeByMetadataName( "NUnit.Framework.CategoryAttribute" );
+ INamedTypeSymbol? categoryAttribute = compilation.GetTypeByMetadataName( "NUnit.Framework.CategoryAttribute" );
if( categoryAttribute == null || categoryAttribute.TypeKind == TypeKind.Error ) {
types = null;
return false;
}
- ImmutableHashSet testAttributes = ImmutableHashSet
- .Create(
- SymbolEqualityComparer.Default,
- compilation.GetTypeByMetadataName( "NUnit.Framework.TestAttribute" ),
- compilation.GetTypeByMetadataName( "NUnit.Framework.TestCaseAttribute" ),
- compilation.GetTypeByMetadataName( "NUnit.Framework.TestCaseSourceAttribute" ),
- compilation.GetTypeByMetadataName( "NUnit.Framework.TheoryAttribute" )
- );
+ ImmutableHashSet testAttributes = new[] {
+ compilation.GetTypeByMetadataName( "NUnit.Framework.TestAttribute" ),
+ compilation.GetTypeByMetadataName( "NUnit.Framework.TestCaseAttribute" ),
+ compilation.GetTypeByMetadataName( "NUnit.Framework.TestCaseSourceAttribute" ),
+ compilation.GetTypeByMetadataName( "NUnit.Framework.TheoryAttribute" )
+ }.Where( x => x != null )!
+ .ToImmutableHashSet( SymbolEqualityComparer.Default );
- INamedTypeSymbol testFixtureAttribute = compilation.GetTypeByMetadataName( "NUnit.Framework.TestFixtureAttribute" );
+ INamedTypeSymbol? testFixtureAttribute = compilation.GetTypeByMetadataName( "NUnit.Framework.TestFixtureAttribute" );
+
+ if( testFixtureAttribute == null ) {
+ types = null;
+ return false;
+ }
types = new NUnitTypes( categoryAttribute, testAttributes, testFixtureAttribute );
return true;
@@ -268,7 +291,7 @@ AnalyzerOptions options
StringComparer.Ordinal
);
- AdditionalText bannedListFile = options.AdditionalFiles.FirstOrDefault(
+ AdditionalText? bannedListFile = options.AdditionalFiles.FirstOrDefault(
file => Path.GetFileName( file.Path ) == "BannedTestCategoriesList.txt"
);
@@ -276,7 +299,11 @@ AnalyzerOptions options
return bannedList.ToImmutableHashSet();
}
- SourceText allowedListText = bannedListFile.GetText();
+ SourceText? allowedListText = bannedListFile.GetText();
+
+ if( allowedListText == null ) {
+ throw new Exception( "Couldn't read config" );
+ }
foreach( TextLine line in allowedListText.Lines ) {
bannedList.Add( line.ToString().Trim() );
diff --git a/src/D2L.CodeStyle.TestAnalyzers/NUnit/ConfigTestSetupStringsAnalyzer.cs b/src/D2L.CodeStyle.TestAnalyzers/NUnit/ConfigTestSetupStringsAnalyzer.cs
index 44382406..6828a5c6 100644
--- a/src/D2L.CodeStyle.TestAnalyzers/NUnit/ConfigTestSetupStringsAnalyzer.cs
+++ b/src/D2L.CodeStyle.TestAnalyzers/NUnit/ConfigTestSetupStringsAnalyzer.cs
@@ -27,10 +27,10 @@ public override void Initialize( AnalysisContext context ) {
private static void Register( CompilationStartAnalysisContext context ) {
- INamedTypeSymbol attributeType =
+ INamedTypeSymbol? attributeType =
context.Compilation.GetTypeByMetadataName( AttributeTypeName );
- if( attributeType.IsNullOrErrorType() ) {
+ if( attributeType == null || attributeType.IsErrorType() ) {
return;
}
@@ -73,12 +73,12 @@ INamedTypeSymbol attributeType
foreach( AttributeSyntax attribute in attributes ) {
- ISymbol symbol = context
+ ISymbol? symbol = context
.SemanticModel
.GetSymbolInfo( attribute, context.CancellationToken )
.Symbol;
- if( symbol.IsNullOrErrorType() ) {
+ if( symbol == null || symbol.Kind == SymbolKind.ErrorType ) {
continue;
}
@@ -88,9 +88,9 @@ INamedTypeSymbol attributeType
}
SeparatedSyntaxList arguments =
- attribute.ArgumentList.Arguments;
+ attribute.ArgumentList?.Arguments ?? default;
- if( arguments.Count != 1 ) {
+ if( arguments == default || arguments.Count != 1 ) {
continue;
}
diff --git a/src/D2L.CodeStyle.TestAnalyzers/ServiceLocator/CustomTestServiceLocatorAnalyzer.cs b/src/D2L.CodeStyle.TestAnalyzers/ServiceLocator/CustomTestServiceLocatorAnalyzer.cs
index 421aef3e..c07cc0a5 100644
--- a/src/D2L.CodeStyle.TestAnalyzers/ServiceLocator/CustomTestServiceLocatorAnalyzer.cs
+++ b/src/D2L.CodeStyle.TestAnalyzers/ServiceLocator/CustomTestServiceLocatorAnalyzer.cs
@@ -28,10 +28,10 @@ public override void Initialize( AnalysisContext context ) {
public static void RegisterServiceLocatorAnalyzer(
CompilationStartAnalysisContext context
) {
- INamedTypeSymbol factoryType = context.Compilation
+ INamedTypeSymbol? factoryType = context.Compilation
.GetTypeByMetadataName( TestServiceLocatorFactoryType );
- if( factoryType.IsNullOrErrorType() ) {
+ if( factoryType == null || factoryType.IsErrorType() ) {
return;
}