Skip to content

Commit 448327e

Browse files
committed
Fix rest of nullable warnings in CheckedExceptions proj
1 parent a66f6dc commit 448327e

File tree

6 files changed

+73
-105
lines changed

6 files changed

+73
-105
lines changed

CheckedExceptions/AttributeHelper.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
namespace Sundstrom.CheckedExceptions;
2-
3-
using System.Diagnostics;
4-
1+
namespace Sundstrom.CheckedExceptions;
2+
3+
using System.Diagnostics;
4+
55
using Microsoft.CodeAnalysis;
66
using Microsoft.CodeAnalysis.CSharp.Syntax;
77

88
public static class AttributeHelper
99
{
10-
public static AttributeData? GetSpecificAttributeData(AttributeSyntax attributeSyntax, SemanticModel semanticModel)
10+
public static AttributeData? GetSpecificAttributeData(AttributeSyntax? attributeSyntax, SemanticModel? semanticModel)
1111
{
1212
if (attributeSyntax is null || semanticModel is null)
1313
return null;

CheckedExceptions/CheckedExceptionsAnalyzer.Inheritance.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ MethodKind.EventAdd or
2020
MethodKind.EventRemove))
2121
return;
2222

23-
ImmutableHashSet<ISymbol> declaredExceptions = GetDistictExceptionTypes(throwsAttributes).Where(x => x is not null).ToImmutableHashSet(SymbolEqualityComparer.Default)!;
23+
ImmutableHashSet<ISymbol> declaredExceptions = GetDistinctExceptionTypes(throwsAttributes).Where(x => x is not null).ToImmutableHashSet(SymbolEqualityComparer.Default)!;
2424
Debug.Assert(!declaredExceptions.Any(x => x is null));
2525

2626
if (declaredExceptions.Count == 0)

CheckedExceptions/CheckedExceptionsAnalyzer.Shared.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ partial class CheckedExceptionsAnalyzer
99
/// <summary>
1010
/// Retrieves the name of the exception type from a ThrowsAttribute's AttributeData.
1111
/// </summary>
12-
private string GetExceptionTypeName(AttributeData attributeData)
12+
private string GetExceptionTypeName(AttributeData? attributeData)
1313
{
1414
if (attributeData is null)
1515
return string.Empty;

CheckedExceptions/CheckedExceptionsAnalyzer.cs

Lines changed: 64 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System.Collections.Concurrent;
44
using System.Collections.Immutable;
55
using System.Linq;
6-
using System.Reflection;
76
using System.Text.Json;
87

98
using Microsoft.CodeAnalysis;
@@ -25,7 +24,7 @@ public partial class CheckedExceptionsAnalyzer : DiagnosticAnalyzer
2524
public const string DiagnosticIdMissingThrowsOnBaseMember = "THROW006";
2625
public const string DiagnosticIdMissingThrowsFromBaseMember = "THROW007";
2726

28-
public static IEnumerable<string> AllDiagnosticsIds = [DiagnosticIdUnhandled, DiagnosticIdGeneralThrows, DiagnosticIdGeneralThrow, DiagnosticIdDuplicateDeclarations];
27+
public static readonly IEnumerable<string> AllDiagnosticsIds = [DiagnosticIdUnhandled, DiagnosticIdGeneralThrows, DiagnosticIdGeneralThrow, DiagnosticIdDuplicateDeclarations];
2928

3029
private static readonly DiagnosticDescriptor RuleUnhandledException = new(
3130
DiagnosticIdUnhandled,
@@ -130,7 +129,7 @@ public override void Initialize(AnalysisContext context)
130129

131130
private AnalyzerSettings LoadAnalyzerSettings(AnalyzerOptions analyzerOptions)
132131
{
133-
return configs.GetOrAdd(analyzerOptions, key =>
132+
return configs.GetOrAdd(analyzerOptions, _ =>
134133
{
135134
var configFileText = analyzerOptions.AdditionalFiles
136135
.FirstOrDefault(f => SettingsFileName.Equals(Path.GetFileName(f.Path), StringComparison.OrdinalIgnoreCase))
@@ -143,7 +142,7 @@ private AnalyzerSettings LoadAnalyzerSettings(AnalyzerOptions analyzerOptions)
143142
val = JsonSerializer.Deserialize<AnalyzerSettings>(configFileText, _settingsFileJsonOptions);
144143
}
145144

146-
return val ?? AnalyzerSettings.CreateWithDefaults(); // Return default options if config file is not found
145+
return val ?? AnalyzerSettings.CreateWithDefaults(); // Return default options if the config file is not found
147146
});
148147
}
149148

@@ -186,9 +185,6 @@ private void AnalyzeMethodSymbol(SymbolAnalysisContext context)
186185
{
187186
var methodSymbol = (IMethodSymbol)context.Symbol;
188187

189-
if (methodSymbol is null)
190-
return;
191-
192188
var throwsAttributes = GetThrowsAttributes(methodSymbol).ToImmutableArray();
193189

194190
CheckForCompatibilityWithBaseOrInterface(context, throwsAttributes);
@@ -211,7 +207,7 @@ public static bool IsThrowsAttributeForException(AttributeData attribute, string
211207
if (!attribute.ConstructorArguments.Any())
212208
return false;
213209

214-
var exceptionTypes = GetDistictExceptionTypes(attribute);
210+
var exceptionTypes = GetDistinctExceptionTypes(attribute);
215211
return exceptionTypes.Any(exceptionType => exceptionType?.Name == exceptionTypeName);
216212
}
217213

@@ -239,11 +235,12 @@ public static IEnumerable<INamedTypeSymbol> GetExceptionTypes(params IEnumerable
239235
}
240236
}
241237

242-
public static IEnumerable<INamedTypeSymbol> GetDistictExceptionTypes(params IEnumerable<AttributeData> exceptionAttributes)
238+
public static IEnumerable<INamedTypeSymbol> GetDistinctExceptionTypes(params IEnumerable<AttributeData> exceptionAttributes)
243239
{
244240
var exceptionTypes = GetExceptionTypes(exceptionAttributes);
245241

246-
return exceptionTypes.Distinct(SymbolEqualityComparer.Default)
242+
return exceptionTypes
243+
.Distinct(SymbolEqualityComparer.Default)
247244
.OfType<INamedTypeSymbol>();
248245
}
249246

@@ -259,26 +256,23 @@ private void AnalyzeThrowStatement(SyntaxNodeAnalysisContext context)
259256
// Handle rethrows (throw;)
260257
if (throwStatement.Expression is null)
261258
{
262-
if (IsWithinCatchBlock(throwStatement, out var catchClause))
259+
if (IsWithinCatchBlock(throwStatement, out var catchClause) && catchClause is not null)
263260
{
264-
if (catchClause is not null)
261+
if (catchClause.Declaration is null)
265262
{
266-
if (catchClause.Declaration is null)
267-
{
268-
// General catch block with 'throw;'
269-
// Analyze exceptions thrown in the try block
270-
var tryStatement = catchClause.Ancestors().OfType<TryStatementSyntax>().FirstOrDefault();
271-
if (tryStatement is not null)
272-
{
273-
AnalyzeExceptionsInTryBlock(context, tryStatement, catchClause, throwStatement, settings);
274-
}
275-
}
276-
else
263+
// General catch block with 'throw;'
264+
// Analyze exceptions thrown in the try block
265+
var tryStatement = catchClause.Ancestors().OfType<TryStatementSyntax>().FirstOrDefault();
266+
if (tryStatement is not null)
277267
{
278-
var exceptionType = context.SemanticModel.GetTypeInfo(catchClause.Declaration.Type).Type as INamedTypeSymbol;
279-
AnalyzeExceptionThrowingNode(context, throwStatement, exceptionType, settings);
268+
AnalyzeExceptionsInTryBlock(context, tryStatement, catchClause, throwStatement, settings);
280269
}
281270
}
271+
else
272+
{
273+
var exceptionType = context.SemanticModel.GetTypeInfo(catchClause.Declaration.Type).Type as INamedTypeSymbol;
274+
AnalyzeExceptionThrowingNode(context, throwStatement, exceptionType, settings);
275+
}
282276
}
283277

284278
return; // No further analysis for rethrows
@@ -492,7 +486,7 @@ void CollectExpressionsForPropertySymbols(ExpressionSyntax expression)
492486

493487
public bool ShouldIncludeException(INamedTypeSymbol exceptionType, SyntaxNode node, AnalyzerSettings settings)
494488
{
495-
var exceptions = new HashSet<INamedTypeSymbol>(SymbolEqualityComparer.Default);
489+
// var exceptions = new HashSet<INamedTypeSymbol>(SymbolEqualityComparer.Default);
496490

497491
var exceptionName = exceptionType.ToDisplayString();
498492

@@ -595,7 +589,7 @@ private void AnalyzeAwait(SyntaxNodeAnalysisContext context)
595589
/// <summary>
596590
/// Determines if a node is within a catch block.
597591
/// </summary>
598-
private bool IsWithinCatchBlock(SyntaxNode node, out CatchClauseSyntax catchClause)
592+
private bool IsWithinCatchBlock(SyntaxNode node, out CatchClauseSyntax? catchClause)
599593
{
600594
catchClause = node.Ancestors().OfType<CatchClauseSyntax>().FirstOrDefault();
601595
return catchClause is not null;
@@ -784,14 +778,9 @@ private void AnalyzeIdentifier(SyntaxNodeAnalysisContext context)
784778

785779
private void AnalyzeIdentifierAndMemberAccess(SyntaxNodeAnalysisContext context, ExpressionSyntax expression, AnalyzerSettings settings)
786780
{
787-
var s = context.SemanticModel.GetSymbolInfo(expression).Symbol;
788-
var symbol = s as IPropertySymbol;
789-
if (symbol is null)
790-
return;
791-
792-
if (symbol is IPropertySymbol propertySymbol)
781+
if (context.SemanticModel.GetSymbolInfo(expression).Symbol is IPropertySymbol propertySymbol)
793782
{
794-
AnalyzePropertyExceptions(context, expression, symbol, settings);
783+
AnalyzePropertyExceptions(context, expression, propertySymbol, settings);
795784
}
796785
}
797786

@@ -804,13 +793,9 @@ private void AnalyzeElementAccess(SyntaxNodeAnalysisContext context)
804793

805794
var elementAccess = (ElementAccessExpressionSyntax)context.Node;
806795

807-
var symbol = context.SemanticModel.GetSymbolInfo(elementAccess).Symbol as IPropertySymbol;
808-
if (symbol is null)
809-
return;
810-
811-
if (symbol is IPropertySymbol propertySymbol)
796+
if (context.SemanticModel.GetSymbolInfo(elementAccess).Symbol is IPropertySymbol propertySymbol)
812797
{
813-
AnalyzePropertyExceptions(context, elementAccess, symbol, settings);
798+
AnalyzePropertyExceptions(context, elementAccess, propertySymbol, settings);
814799
}
815800
}
816801

@@ -873,28 +858,17 @@ private HashSet<INamedTypeSymbol> GetPropertyExceptionTypes(SyntaxNodeAnalysisCo
873858
var xmlDocumentedExceptions = GetExceptionTypesFromDocumentationCommentXml(context.Compilation, propertySymbol);
874859

875860
// Filter exceptions documented specifically for the getter and setter
876-
var getterExceptions = xmlDocumentedExceptions.Where(x =>
877-
x.Description.Contains(" get ") ||
878-
x.Description.Contains(" gets ") ||
879-
x.Description.Contains(" getting ") ||
880-
x.Description.Contains(" retrieved "));
881-
882-
var setterExceptions = xmlDocumentedExceptions.Where(x =>
883-
x.Description.Contains(" set ") ||
884-
x.Description.Contains(" sets ") ||
885-
x.Description.Contains(" setting "));
861+
var getterExceptions = xmlDocumentedExceptions.Where(IsGetterException);
862+
var setterExceptions = xmlDocumentedExceptions.Where(IsSetterException);
886863

887864
if (isSetter && propertySymbol.SetMethod is not null)
888865
{
889-
// Will filter away
866+
// Will filter away
890867
setterExceptions = ProcessNullable(context, expression, propertySymbol.SetMethod, setterExceptions);
891868
}
892869

893870
// Handle exceptions that don't explicitly belong to getters or setters
894-
var allOtherExceptions = xmlDocumentedExceptions
895-
.Except(getterExceptions);
896-
allOtherExceptions = allOtherExceptions
897-
.Except(setterExceptions);
871+
var allOtherExceptions = xmlDocumentedExceptions.Where(x => !IsGetterException(x) && !IsSetterException(x));
898872

899873
if (isSetter && propertySymbol.SetMethod is not null)
900874
{
@@ -925,12 +899,23 @@ private HashSet<INamedTypeSymbol> GetPropertyExceptionTypes(SyntaxNodeAnalysisCo
925899
// Add other exceptions not specific to getters or setters
926900
exceptionTypes.AddRange(allOtherExceptions.Select(x => x.ExceptionType));
927901
return exceptionTypes;
902+
903+
static bool IsGetterException(ExceptionInfo ei) =>
904+
ei.Description.Contains(" get ") ||
905+
ei.Description.Contains(" gets ") ||
906+
ei.Description.Contains(" getting ") ||
907+
ei.Description.Contains(" retrieved ");
908+
909+
static bool IsSetterException(ExceptionInfo ei) =>
910+
ei.Description.Contains(" set ") ||
911+
ei.Description.Contains(" sets ") ||
912+
ei.Description.Contains(" setting ");
928913
}
929914

930915
/// <summary>
931916
/// Analyzes exceptions thrown by a method, constructor, or other member.
932917
/// </summary>
933-
private void AnalyzeMemberExceptions(SyntaxNodeAnalysisContext context, SyntaxNode node, IMethodSymbol methodSymbol,
918+
private void AnalyzeMemberExceptions(SyntaxNodeAnalysisContext context, SyntaxNode node, IMethodSymbol? methodSymbol,
934919
AnalyzerSettings settings)
935920
{
936921
if (methodSymbol is null)
@@ -1027,7 +1012,7 @@ private static IEnumerable<INamedTypeSymbol> GetExceptionTypes(IMethodSymbol met
10271012
// Get exceptions from Throws attributes
10281013
var exceptionAttributes = GetThrowsAttributes(methodSymbol);
10291014

1030-
return GetDistictExceptionTypes(exceptionAttributes);
1015+
return GetDistinctExceptionTypes(exceptionAttributes);
10311016
}
10321017

10331018
private static IEnumerable<AttributeData> GetThrowsAttributes(ISymbol symbol)
@@ -1062,7 +1047,7 @@ private bool CatchClauseHandlesException(CatchClauseSyntax catchClause, Semantic
10621047
/// </summary>
10631048
private bool IsExceptionHandled(SyntaxNode node, INamedTypeSymbol exceptionType, SemanticModel semanticModel)
10641049
{
1065-
SyntaxNode? prevNode = null;
1050+
// SyntaxNode? prevNode = null;
10661051

10671052
var current = node.Parent;
10681053
while (current is not null)
@@ -1078,7 +1063,7 @@ private bool IsExceptionHandled(SyntaxNode node, INamedTypeSymbol exceptionType,
10781063
if (current is TryStatementSyntax tryStatement)
10791064
{
10801065
// Prevents analysis within the first try-catch,
1081-
// when coming from either a catch clause or a finally clause.
1066+
// when coming from either a catch clause or a finally clause.
10821067

10831068
// Skip if the node is within a catch or finally block of the current try statement
10841069
bool isInCatchOrFinally = tryStatement.Catches.Any(c => c.Contains(node)) ||
@@ -1097,7 +1082,7 @@ private bool IsExceptionHandled(SyntaxNode node, INamedTypeSymbol exceptionType,
10971082
}
10981083
}
10991084

1100-
prevNode = current;
1085+
// prevNode = current;
11011086
current = current.Parent;
11021087
}
11031088

@@ -1182,48 +1167,34 @@ private bool IsExceptionDeclaredInMethod(SyntaxNodeAnalysisContext context, Synt
11821167
{
11831168
foreach (var ancestor in node.Ancestors())
11841169
{
1185-
IMethodSymbol? methodSymbol = null;
1186-
1187-
switch (ancestor)
1170+
IMethodSymbol? methodSymbol = ancestor switch
11881171
{
1189-
case MethodDeclarationSyntax methodDeclaration:
1190-
methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodDeclaration);
1191-
break;
1192-
case ConstructorDeclarationSyntax constructorDeclaration:
1193-
methodSymbol = context.SemanticModel.GetDeclaredSymbol(constructorDeclaration);
1194-
break;
1195-
case AccessorDeclarationSyntax accessorDeclaration:
1196-
methodSymbol = context.SemanticModel.GetDeclaredSymbol(accessorDeclaration);
1197-
break;
1198-
case LocalFunctionStatementSyntax localFunction:
1199-
methodSymbol = context.SemanticModel.GetDeclaredSymbol(localFunction);
1200-
break;
1201-
case AnonymousFunctionExpressionSyntax anonymousFunction:
1202-
methodSymbol = context.SemanticModel.GetSymbolInfo(anonymousFunction).Symbol as IMethodSymbol;
1203-
break;
1204-
default:
1205-
// Continue up to next node
1206-
continue;
1207-
}
1172+
MethodDeclarationSyntax methodDeclaration => context.SemanticModel.GetDeclaredSymbol(methodDeclaration),
1173+
ConstructorDeclarationSyntax constructorDeclaration => context.SemanticModel.GetDeclaredSymbol(constructorDeclaration),
1174+
AccessorDeclarationSyntax accessorDeclaration => context.SemanticModel.GetDeclaredSymbol(accessorDeclaration),
1175+
LocalFunctionStatementSyntax localFunction => context.SemanticModel.GetDeclaredSymbol(localFunction),
1176+
AnonymousFunctionExpressionSyntax anonymousFunction => context.SemanticModel.GetSymbolInfo(anonymousFunction).Symbol as IMethodSymbol,
1177+
_ => null,
1178+
};
12081179

1209-
if (methodSymbol is not null)
1210-
{
1211-
if (IsExceptionDeclaredInSymbol(methodSymbol, exceptionType))
1212-
return true;
1180+
if (methodSymbol is null)
1181+
continue; // Continue up to next node
12131182

1214-
if (ancestor is AnonymousFunctionExpressionSyntax or LocalFunctionStatementSyntax)
1215-
{
1216-
// Break because you are analyzing a local function or anonymous function (lambda)
1217-
// If you don't then it will got to the method, and it will affect analysis of this inline function.
1218-
break;
1219-
}
1183+
if (IsExceptionDeclaredInSymbol(methodSymbol, exceptionType))
1184+
return true;
1185+
1186+
if (ancestor is AnonymousFunctionExpressionSyntax or LocalFunctionStatementSyntax)
1187+
{
1188+
// Break because you are analyzing a local function or anonymous function (lambda)
1189+
// If you don't then it will got to the method, and it will affect analysis of this inline function.
1190+
break;
12201191
}
12211192
}
12221193

12231194
return false;
12241195
}
12251196

1226-
private bool IsExceptionDeclaredInSymbol(IMethodSymbol methodSymbol, INamedTypeSymbol exceptionType)
1197+
private bool IsExceptionDeclaredInSymbol(IMethodSymbol? methodSymbol, INamedTypeSymbol exceptionType)
12271198
{
12281199
if (methodSymbol is null)
12291200
return false;

CheckedExceptions/TypeSymbolExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public static class TypeSymbolExtensions
1010
/// <summary>
1111
/// Determines if a type inherits from a base type.
1212
/// </summary>
13-
public static bool InheritsFrom(this INamedTypeSymbol type, INamedTypeSymbol baseType)
13+
public static bool InheritsFrom(this INamedTypeSymbol? type, INamedTypeSymbol? baseType)
1414
{
1515
if (type is null || baseType is null)
1616
return false;

CheckedExceptions/XmlDocumentationHelper.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
using System.Text;
21
using System.Xml.Linq;
32

4-
using Microsoft.CodeAnalysis;
5-
63
namespace Sundstrom.CheckedExceptions;
74

85
public static class XmlDocumentationHelper
@@ -16,7 +13,7 @@ public static Dictionary<string, XElement> CreateMemberLookup(XDocument xmlDoc)
1613
var lookup = members
1714
.Where(m => m.Attribute("name") is not null) // Ensure the member has a 'name' attribute
1815
.ToDictionary(
19-
m => m.Attribute("name").Value, // Key: the member's name attribute
16+
m => m.Attribute("name")!.Value, // Key: the member's name attribute
2017
m => m // Value: the inner XML or text content
2118
);
2219

0 commit comments

Comments
 (0)