Extract helpers for `Diagnostic.Create` in Analyzers
will rebuild in later commit
This commit is contained in:
parent
6eef3668a7
commit
9a388c6693
|
@ -0,0 +1,163 @@
|
|||
namespace BizHawk.Analyzers;
|
||||
|
||||
using static System.Runtime.CompilerServices.MethodImplOptions;
|
||||
|
||||
using DD = Microsoft.CodeAnalysis.DiagnosticDescriptor;
|
||||
using MI = System.Runtime.CompilerServices.MethodImplAttribute;
|
||||
using OAC = Microsoft.CodeAnalysis.Diagnostics.OperationAnalysisContext;
|
||||
using SNAC = Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext;
|
||||
|
||||
public static class DDExtensions
|
||||
{
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(
|
||||
this DD diag,
|
||||
Location location,
|
||||
DiagnosticSeverity effectiveSeverity,
|
||||
OAC ctx,
|
||||
object?[]? messageArgs = null)
|
||||
=> ctx.ReportDiagnostic(Diagnostic.Create(
|
||||
diag,
|
||||
location,
|
||||
effectiveSeverity,
|
||||
additionalLocations: null,
|
||||
properties: null,
|
||||
messageArgs: messageArgs));
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(
|
||||
this DD diag,
|
||||
Location location,
|
||||
DiagnosticSeverity effectiveSeverity,
|
||||
SNAC ctx,
|
||||
object?[]? messageArgs = null)
|
||||
=> ctx.ReportDiagnostic(Diagnostic.Create(
|
||||
diag,
|
||||
location,
|
||||
effectiveSeverity,
|
||||
additionalLocations: null,
|
||||
properties: null,
|
||||
messageArgs: messageArgs));
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, Location location, OAC ctx, object?[]? messageArgs = null)
|
||||
=> ctx.ReportDiagnostic(Diagnostic.Create(diag, location, messageArgs: messageArgs));
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, Location location, SNAC ctx, object?[]? messageArgs = null)
|
||||
=> ctx.ReportDiagnostic(Diagnostic.Create(diag, location, messageArgs: messageArgs));
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(
|
||||
this DD diag,
|
||||
SyntaxNode location,
|
||||
DiagnosticSeverity effectiveSeverity,
|
||||
OAC ctx,
|
||||
object?[]? messageArgs = null)
|
||||
=> diag.ReportAt(location.GetLocation(), effectiveSeverity, ctx, messageArgs);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(
|
||||
this DD diag,
|
||||
SyntaxNode location,
|
||||
DiagnosticSeverity effectiveSeverity,
|
||||
SNAC ctx,
|
||||
object?[]? messageArgs = null)
|
||||
=> diag.ReportAt(location.GetLocation(), effectiveSeverity, ctx, messageArgs);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(
|
||||
this DD diag,
|
||||
SyntaxNode location,
|
||||
DiagnosticSeverity effectiveSeverity,
|
||||
OAC ctx,
|
||||
string message)
|
||||
=> diag.ReportAt(location, effectiveSeverity, ctx, [ message ]);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(
|
||||
this DD diag,
|
||||
SyntaxNode location,
|
||||
DiagnosticSeverity effectiveSeverity,
|
||||
SNAC ctx,
|
||||
string message)
|
||||
=> diag.ReportAt(location, effectiveSeverity, ctx, [ message ]);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, SyntaxNode location, bool isErrorSeverity, OAC ctx, object?[]? messageArgs = null)
|
||||
=> diag.ReportAt(
|
||||
location,
|
||||
isErrorSeverity ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning,
|
||||
ctx,
|
||||
messageArgs);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, SyntaxNode location, bool isErrorSeverity, SNAC ctx, object?[]? messageArgs = null)
|
||||
=> diag.ReportAt(
|
||||
location,
|
||||
isErrorSeverity ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning,
|
||||
ctx,
|
||||
messageArgs);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, SyntaxNode location, bool isErrorSeverity, OAC ctx, string message)
|
||||
=> diag.ReportAt(location, isErrorSeverity, ctx, [ message ]);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, SyntaxNode location, bool isErrorSeverity, SNAC ctx, string message)
|
||||
=> diag.ReportAt(location, isErrorSeverity, ctx, [ message ]);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, SyntaxNode location, OAC ctx, object?[]? messageArgs = null)
|
||||
=> diag.ReportAt(location.GetLocation(), ctx, messageArgs);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, SyntaxNode location, SNAC ctx, object?[]? messageArgs = null)
|
||||
=> diag.ReportAt(location.GetLocation(), ctx, messageArgs);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, SyntaxNode location, OAC ctx, string message)
|
||||
=> diag.ReportAt(location, ctx, [ message ]);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, SyntaxNode location, SNAC ctx, string message)
|
||||
=> diag.ReportAt(location, ctx, [ message ]);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(
|
||||
this DD diag,
|
||||
IOperation location,
|
||||
DiagnosticSeverity effectiveSeverity,
|
||||
OAC ctx,
|
||||
object?[]? messageArgs = null)
|
||||
=> diag.ReportAt(location.Syntax, effectiveSeverity, ctx, messageArgs);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(
|
||||
this DD diag,
|
||||
IOperation location,
|
||||
DiagnosticSeverity effectiveSeverity,
|
||||
OAC ctx,
|
||||
string message)
|
||||
=> diag.ReportAt(location, effectiveSeverity, ctx, [ message ]);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, IOperation location, bool isErrorSeverity, OAC ctx, object?[]? messageArgs = null)
|
||||
=> diag.ReportAt(
|
||||
location,
|
||||
isErrorSeverity ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning,
|
||||
ctx,
|
||||
messageArgs);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, IOperation location, bool isErrorSeverity, OAC ctx, string message)
|
||||
=> diag.ReportAt(location, isErrorSeverity, ctx, [ message ]);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, IOperation location, OAC ctx, object?[]? messageArgs = null)
|
||||
=> diag.ReportAt(location.Syntax, ctx, messageArgs);
|
||||
|
||||
[MI(AggressiveInlining)]
|
||||
public static void ReportAt(this DD diag, IOperation location, OAC ctx, string message)
|
||||
=> diag.ReportAt(location, ctx, [ message ]);
|
||||
}
|
|
@ -47,14 +47,12 @@ public sealed class AmbiguousMoneyToFloatConversionAnalyzer : DiagnosticAnalyzer
|
|||
}
|
||||
var conversionSyn = conversionOp.Syntax;
|
||||
//TODO check the suggested methods are accessible (i.e. BizHawk.Common is referenced)
|
||||
oac.ReportDiagnostic(Diagnostic.Create(
|
||||
DiagAmbiguousMoneyToFloatConversion,
|
||||
(conversionSyn.Parent?.Kind() is SyntaxKind.CheckedExpression or SyntaxKind.UncheckedExpression
|
||||
DiagAmbiguousMoneyToFloatConversion.ReportAt(
|
||||
conversionSyn.Parent?.Kind() is SyntaxKind.CheckedExpression or SyntaxKind.UncheckedExpression
|
||||
? conversionSyn.Parent
|
||||
: conversionSyn).GetLocation(),
|
||||
conversionOp.IsChecked ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning,
|
||||
additionalLocations: null,
|
||||
properties: null,
|
||||
: conversionSyn,
|
||||
isErrorSeverity: conversionOp.IsChecked,
|
||||
oac,
|
||||
messageArgs: isToDecimal
|
||||
? [
|
||||
$"new decimal({(isDoublePrecision ? "double" : "float")})", // "checked"
|
||||
|
@ -63,7 +61,7 @@ public sealed class AmbiguousMoneyToFloatConversionAnalyzer : DiagnosticAnalyzer
|
|||
: [
|
||||
$"decimal.{(isDoublePrecision ? "ConvertToF64" : "ConvertToF32")} ext. (from NumberExtensions)", // "checked"
|
||||
$"static Decimal.{(isDoublePrecision ? "ToDouble" : "ToSingle")}", // "unchecked"
|
||||
]));
|
||||
]);
|
||||
},
|
||||
OperationKind.Conversion);
|
||||
}
|
||||
|
|
|
@ -36,8 +36,6 @@ public sealed class ExprBodiedMemberFlowAnalyzer : DiagnosticAnalyzer
|
|||
HawkSourceAnalyzer.ReportWTF(aecs, snac, message: $"[{nameof(ExprBodiedMemberFlowAnalyzer)}] Syntax node for expression-bodied member was orphaned?");
|
||||
return;
|
||||
}
|
||||
void Flag(string message)
|
||||
=> snac.ReportDiagnostic(Diagnostic.Create(DiagExprBodiedMemberFlow, parent.GetLocation(), message));
|
||||
switch (parent)
|
||||
{
|
||||
case MethodDeclarationSyntax:
|
||||
|
@ -103,7 +101,7 @@ public sealed class ExprBodiedMemberFlowAnalyzer : DiagnosticAnalyzer
|
|||
static string EscapeChar(char c)
|
||||
=> c is '\n' ? "\\n" : c.ToString();
|
||||
void Fail()
|
||||
=> Flag($"Whitespace around {kind} arrow syntax should be `{EscapeChar(expectedWhitespace.Before)}=>{EscapeChar(expectedWhitespace.After)}`");
|
||||
=> DiagExprBodiedMemberFlow.ReportAt(parent, snac, $"Whitespace around {kind} arrow syntax should be `{EscapeChar(expectedWhitespace.Before)}=>{EscapeChar(expectedWhitespace.After)}`");
|
||||
if ((aecs.ArrowToken.HasLeadingTrivia ? '\n' : ' ') != expectedWhitespace.Before)
|
||||
{
|
||||
Fail();
|
||||
|
|
|
@ -37,10 +37,10 @@ public sealed class FeatureNotImplementedAnalyzer : DiagnosticAnalyzer
|
|||
initContext.RegisterSyntaxNodeAction(
|
||||
snac =>
|
||||
{
|
||||
void MaybeReportFor(ITypeSymbol? thrownExceptionType, Location location)
|
||||
void MaybeReportFor(ITypeSymbol? thrownExceptionType, SyntaxNode location)
|
||||
{
|
||||
if (thrownExceptionType is null) snac.ReportDiagnostic(Diagnostic.Create(DiagShouldThrowNIE, location, ERR_MSG_METHOD_THROWS_UNKNOWN));
|
||||
else if (!notImplementedExceptionSym.Matches(thrownExceptionType)) snac.ReportDiagnostic(Diagnostic.Create(DiagShouldThrowNIE, location, ERR_MSG_THROWS_WRONG_TYPE));
|
||||
if (thrownExceptionType is null) DiagShouldThrowNIE.ReportAt(location, snac, ERR_MSG_METHOD_THROWS_UNKNOWN);
|
||||
else if (!notImplementedExceptionSym.Matches(thrownExceptionType)) DiagShouldThrowNIE.ReportAt(location, snac, ERR_MSG_THROWS_WRONG_TYPE);
|
||||
// else correct usage, do not flag
|
||||
}
|
||||
bool IncludesFNIAttribute(SyntaxList<AttributeListSyntax> mds)
|
||||
|
@ -48,13 +48,13 @@ public sealed class FeatureNotImplementedAnalyzer : DiagnosticAnalyzer
|
|||
.Any(aSyn => featureNotImplementedAttrSym.Matches(snac.SemanticModel.GetTypeInfo(aSyn, snac.CancellationToken).Type));
|
||||
void CheckBlockBody(BlockSyntax bs, Location location)
|
||||
{
|
||||
if (bs.Statements is [ ThrowStatementSyntax tss ]) MaybeReportFor(snac.SemanticModel.GetThrownExceptionType(tss), tss.GetLocation());
|
||||
else snac.ReportDiagnostic(Diagnostic.Create(DiagShouldThrowNIE, location, ERR_MSG_DOES_NOT_THROW));
|
||||
if (bs.Statements is [ ThrowStatementSyntax tss ]) MaybeReportFor(snac.SemanticModel.GetThrownExceptionType(tss), tss);
|
||||
else DiagShouldThrowNIE.ReportAt(location, snac, [ ERR_MSG_DOES_NOT_THROW ]);
|
||||
}
|
||||
void CheckExprBody(ArrowExpressionClauseSyntax aecs, Location location)
|
||||
{
|
||||
if (aecs.Expression is ThrowExpressionSyntax tes) MaybeReportFor(snac.SemanticModel.GetThrownExceptionType(tes), tes.GetLocation());
|
||||
else snac.ReportDiagnostic(Diagnostic.Create(DiagShouldThrowNIE, location, ERR_MSG_DOES_NOT_THROW));
|
||||
if (aecs.Expression is ThrowExpressionSyntax tes) MaybeReportFor(snac.SemanticModel.GetThrownExceptionType(tes), tes);
|
||||
else DiagShouldThrowNIE.ReportAt(location, snac, [ ERR_MSG_DOES_NOT_THROW ]);
|
||||
}
|
||||
void CheckAccessor(AccessorDeclarationSyntax ads)
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@ public sealed class FirstOrDefaultOnStructAnalyzer : DiagnosticAnalyzer
|
|||
IArrayTypeSymbol ats => ats.ElementType,
|
||||
_ => throw HawkSourceAnalyzer.ReportWTF(receiverExpr, oac, message: $"[{nameof(FirstOrDefaultOnStructAnalyzer)}] receiver parameter's effective type was of an unexpected kind (neither class/struct nor array): {receiverExprType.GetType().FullName}")
|
||||
};
|
||||
if (collectionElemType.IsValueType) oac.ReportDiagnostic(Diagnostic.Create(DiagUseFirstOrNull, operation.Syntax.GetLocation()));
|
||||
if (collectionElemType.IsValueType) DiagUseFirstOrNull.ReportAt(operation, oac);
|
||||
},
|
||||
OperationKind.Invocation);
|
||||
});
|
||||
|
|
|
@ -88,21 +88,27 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer
|
|||
isEnabledByDefault: true);
|
||||
|
||||
#if true
|
||||
public static OperationCanceledException ReportWTF(IOperation location, OperationAnalysisContext ctx, string message)
|
||||
{
|
||||
DiagWTF.ReportAt(location, ctx, message);
|
||||
return new(ctx.CancellationToken);
|
||||
}
|
||||
|
||||
public static OperationCanceledException ReportWTF(SyntaxNode location, OperationAnalysisContext ctx, string message)
|
||||
{
|
||||
ctx.ReportDiagnostic(Diagnostic.Create(DiagWTF, location.GetLocation(), message));
|
||||
DiagWTF.ReportAt(location, ctx, message);
|
||||
return new(ctx.CancellationToken);
|
||||
}
|
||||
|
||||
public static OperationCanceledException ReportWTF(SyntaxNode location, SyntaxNodeAnalysisContext ctx, string message)
|
||||
{
|
||||
ctx.ReportDiagnostic(Diagnostic.Create(DiagWTF, location.GetLocation(), message));
|
||||
DiagWTF.ReportAt(location, ctx, message);
|
||||
return new(ctx.CancellationToken);
|
||||
}
|
||||
#else // maybe move to something like this?
|
||||
public static OperationCanceledException ReportWTF(SyntaxNode alien, string analyzerName, string disambig, SyntaxNodeAnalysisContext ctx)
|
||||
{
|
||||
ctx.ReportDiagnostic(Diagnostic.Create(DiagWTF, alien.GetLocation(), $"[{analyzerName}{disambig}] AST/model contained {alien.GetType().FullName} unexpectedly; Analyzer needs updating"));
|
||||
DiagWTF.ReportAt(alien, ctx, $"[{analyzerName}{disambig}] AST/model contained {alien.GetType().FullName} unexpectedly; Analyzer needs updating");
|
||||
return new(ctx.CancellationToken);
|
||||
}
|
||||
#endif
|
||||
|
@ -152,48 +158,42 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer
|
|||
switch (snac.Node)
|
||||
{
|
||||
case AnonymousMethodExpressionSyntax:
|
||||
snac.ReportDiagnostic(Diagnostic.Create(DiagNoAnonDelegates, snac.Node.GetLocation()));
|
||||
DiagNoAnonDelegates.ReportAt(snac.Node, snac);
|
||||
break;
|
||||
case AnonymousObjectCreationExpressionSyntax:
|
||||
snac.ReportDiagnostic(Diagnostic.Create(DiagNoAnonClasses, snac.Node.GetLocation()));
|
||||
DiagNoAnonClasses.ReportAt(snac.Node, snac);
|
||||
break;
|
||||
case AssignmentExpressionSyntax aes:
|
||||
if (!IsDiscard(aes)) break;
|
||||
if (snac.SemanticModel.GetSymbolInfo(aes.Right, snac.CancellationToken).Symbol?.Kind is not SymbolKind.Local) break;
|
||||
snac.ReportDiagnostic(Diagnostic.Create(DiagNoDiscardingLocals, snac.Node.GetLocation()));
|
||||
DiagNoDiscardingLocals.ReportAt(snac.Node, snac);
|
||||
break;
|
||||
case CollectionExpressionSyntax ces:
|
||||
var cesError = CheckSpacingInList(ces.Elements, ces.OpenBracketToken, ces.ToString);
|
||||
if (cesError is not null) snac.ReportDiagnostic(Diagnostic.Create(DiagListExprSpacing, ces.GetLocation(), cesError));
|
||||
if (cesError is not null) DiagListExprSpacing.ReportAt(ces, snac, cesError);
|
||||
break;
|
||||
case InterpolatedStringExpressionSyntax ises:
|
||||
if (ises.StringStartToken.Text[0] is '@') snac.ReportDiagnostic(Diagnostic.Create(DiagInterpStringIsDollarAt, ises.GetLocation()));
|
||||
if (ises.StringStartToken.Text[0] is '@') DiagInterpStringIsDollarAt.ReportAt(ises, snac);
|
||||
break;
|
||||
case ListPatternSyntax lps:
|
||||
var lpsError = CheckSpacingInList(lps.Patterns, lps.OpenBracketToken, lps.ToString);
|
||||
if (lpsError is not null) snac.ReportDiagnostic(Diagnostic.Create(DiagListExprSpacing, lps.GetLocation(), lpsError));
|
||||
if (lpsError is not null) DiagListExprSpacing.ReportAt(lps, snac, lpsError);
|
||||
break;
|
||||
case QueryExpressionSyntax:
|
||||
snac.ReportDiagnostic(Diagnostic.Create(DiagNoQueryExpression, snac.Node.GetLocation()));
|
||||
DiagNoQueryExpression.ReportAt(snac.Node, snac);
|
||||
break;
|
||||
case RecordDeclarationSyntax rds when rds.ClassOrStructKeyword.ToString() is not "class": // `record struct`s don't use this kind
|
||||
snac.ReportDiagnostic(Diagnostic.Create(DiagRecordImplicitlyRefType, rds.GetLocation()));
|
||||
DiagRecordImplicitlyRefType.ReportAt(rds, snac);
|
||||
break;
|
||||
case SwitchExpressionArmSyntax { WhenClause: null, Pattern: DiscardPatternSyntax, Expression: ThrowExpressionSyntax tes }:
|
||||
var thrownExceptionType = snac.SemanticModel.GetThrownExceptionType(tes);
|
||||
if (thrownExceptionType is null)
|
||||
{
|
||||
snac.ReportDiagnostic(Diagnostic.Create(
|
||||
DiagSwitchShouldThrowIOE,
|
||||
tes.GetLocation(),
|
||||
DiagnosticSeverity.Warning,
|
||||
additionalLocations: null,
|
||||
properties: null,
|
||||
ERR_MSG_SWITCH_THROWS_UNKNOWN));
|
||||
DiagSwitchShouldThrowIOE.ReportAt(tes, DiagnosticSeverity.Warning, snac, ERR_MSG_SWITCH_THROWS_UNKNOWN);
|
||||
}
|
||||
else if (!invalidOperationExceptionSym.Matches(thrownExceptionType) && switchExpressionExceptionSym?.Matches(thrownExceptionType) != true)
|
||||
{
|
||||
snac.ReportDiagnostic(Diagnostic.Create(DiagSwitchShouldThrowIOE, tes.GetLocation(), ERR_MSG_SWITCH_THROWS_WRONG_TYPE));
|
||||
DiagSwitchShouldThrowIOE.ReportAt(tes, snac, ERR_MSG_SWITCH_THROWS_WRONG_TYPE);
|
||||
}
|
||||
// else correct usage, do not flag
|
||||
break;
|
||||
|
|
|
@ -119,13 +119,7 @@ public sealed class LINQOnStringsAnalyzer : DiagnosticAnalyzer
|
|||
: "Use `str.Contains(c.ToString())`";
|
||||
break;
|
||||
}
|
||||
oac.ReportDiagnostic(Diagnostic.Create(
|
||||
DiagLINQOnStrings,
|
||||
operation.Syntax.GetLocation(),
|
||||
level,
|
||||
additionalLocations: null,
|
||||
properties: null,
|
||||
messageArgs: string.Format(msgFmtStr, receiverExpr.Syntax)));
|
||||
DiagLINQOnStrings.ReportAt(operation, level, oac, string.Format(msgFmtStr, receiverExpr.Syntax));
|
||||
},
|
||||
OperationKind.Invocation);
|
||||
});
|
||||
|
|
|
@ -5,12 +5,10 @@ using System.Collections.Immutable;
|
|||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||
public sealed class NoTargetTypedThrowAnalyzer : DiagnosticAnalyzer
|
||||
{
|
||||
private const string ERR_MSG_IMPLICIT = "Specify `Exception` (or a more precise type) explicitly";
|
||||
|
||||
private static readonly DiagnosticDescriptor DiagNoTargetTypedThrow = new(
|
||||
id: "BHI1007",
|
||||
title: "Don't use target-typed new for throw expressions",
|
||||
messageFormat: "{0}",
|
||||
messageFormat: "Specify `Exception` (or a more precise type) explicitly",
|
||||
category: "Usage",
|
||||
defaultSeverity: DiagnosticSeverity.Warning,
|
||||
isEnabledByDefault: true);
|
||||
|
@ -27,8 +25,6 @@ public sealed class NoTargetTypedThrowAnalyzer : DiagnosticAnalyzer
|
|||
{
|
||||
var exceptionOp = ((IThrowOperation) oac.Operation).Exception;
|
||||
if (exceptionOp is null) return; // re-`throw;`
|
||||
void Fail(string message)
|
||||
=> oac.ReportDiagnostic(Diagnostic.Create(DiagNoTargetTypedThrow, exceptionOp.Syntax.GetLocation(), message));
|
||||
switch (exceptionOp.Kind)
|
||||
{
|
||||
case OperationKind.ObjectCreation:
|
||||
|
@ -44,10 +40,10 @@ public sealed class NoTargetTypedThrowAnalyzer : DiagnosticAnalyzer
|
|||
}
|
||||
return;
|
||||
default:
|
||||
HawkSourceAnalyzer.ReportWTF(exceptionOp.Syntax, oac, message: $"[{nameof(NoTargetTypedThrowAnalyzer)}] Argument to throw expression was of an unexpected kind: {exceptionOp.GetType().FullName}");
|
||||
HawkSourceAnalyzer.ReportWTF(exceptionOp, oac, message: $"[{nameof(NoTargetTypedThrowAnalyzer)}] Argument to throw expression was of an unexpected kind: {exceptionOp.GetType().FullName}");
|
||||
return;
|
||||
}
|
||||
Fail(ERR_MSG_IMPLICIT);
|
||||
DiagNoTargetTypedThrow.ReportAt(exceptionOp, oac);
|
||||
},
|
||||
OperationKind.Throw);
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public class OrderBySelfAnalyzer : DiagnosticAnalyzer
|
|||
var calledSym = operation.TargetMethod.ConstructedFrom;
|
||||
if (!(orderByAscSym!.Matches(calledSym) || orderByDescSym!.Matches(calledSym))) return;
|
||||
if (((ArgumentSyntax) operation.Arguments[1].Syntax).Expression is not AnonymousFunctionExpressionSyntax afes) return;
|
||||
if (IsSelfReturnLambda(afes)) oac.ReportDiagnostic(Diagnostic.Create(DiagUseOrderBySelfExt, afes.GetLocation(), orderByDescSym.Matches(calledSym) ? "Descending" : string.Empty));
|
||||
if (IsSelfReturnLambda(afes)) DiagUseOrderBySelfExt.ReportAt(afes, oac, orderByDescSym.Matches(calledSym) ? "Descending" : string.Empty);
|
||||
},
|
||||
OperationKind.Invocation);
|
||||
});
|
||||
|
|
|
@ -67,13 +67,7 @@ public sealed class TernaryInferredTypeMismatchAnalyzer : DiagnosticAnalyzer
|
|||
else if (typeTernary.Matches(typeRHS)) flaggedOp = lhs;
|
||||
message = $"ternary branches are converted to {typeTernary} before serialisation, possibly unintended";
|
||||
}
|
||||
oac.ReportDiagnostic(Diagnostic.Create(
|
||||
DiagTernaryInferredTypeMismatch,
|
||||
flaggedOp.Syntax.GetLocation(),
|
||||
fatal ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning,
|
||||
additionalLocations: null,
|
||||
properties: null,
|
||||
messageArgs: message));
|
||||
DiagTernaryInferredTypeMismatch.ReportAt(flaggedOp, fatal ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning, oac, message);
|
||||
},
|
||||
OperationKind.Conditional);
|
||||
}
|
||||
|
|
|
@ -37,13 +37,10 @@ public sealed class TryGetValueImplicitDiscardAnalyzer : DiagnosticAnalyzer
|
|||
var operation = (IInvocationOperation) oac.Operation;
|
||||
if (operation.Parent?.Kind is not OperationKind.ExpressionStatement) return;
|
||||
var calledSym = operation.TargetMethod.ConstructedFrom;
|
||||
if (calledSym.Name is STR_TGV) oac.ReportDiagnostic(Diagnostic.Create(
|
||||
DiagUncheckedTryGetValue,
|
||||
operation.Syntax.GetLocation(),
|
||||
IsBCLTryGetValue(calledSym) ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning,
|
||||
additionalLocations: null,
|
||||
properties: null,
|
||||
messageArgs: null));
|
||||
if (calledSym.Name is STR_TGV)
|
||||
{
|
||||
DiagUncheckedTryGetValue.ReportAt(operation, isErrorSeverity: IsBCLTryGetValue(calledSym), oac);
|
||||
}
|
||||
},
|
||||
OperationKind.Invocation);
|
||||
});
|
||||
|
|
|
@ -42,22 +42,16 @@ public sealed class UseNameofOperatorAnalyzer : DiagnosticAnalyzer
|
|||
case BinaryExpressionSyntax bes:
|
||||
if ((ReferenceEquals(toes, bes.Left) ? bes.Right : bes.Left) is LiteralExpressionSyntax { Token.RawKind: (int) SyntaxKind.StringLiteralToken })
|
||||
{
|
||||
snac.ReportDiagnostic(Diagnostic.Create(DiagNoToStringOnType, toes.GetLocation(), toes.Type.GetText(), " in string concatenation"));
|
||||
DiagNoToStringOnType.ReportAt(toes, snac, [ toes.Type.GetText(), " in string concatenation" ]);
|
||||
}
|
||||
break;
|
||||
case InterpolationSyntax:
|
||||
snac.ReportDiagnostic(Diagnostic.Create(DiagNoToStringOnType, toes.GetLocation(), toes.Type.GetText(), " in string interpolation"));
|
||||
DiagNoToStringOnType.ReportAt(toes, snac, [ toes.Type.GetText(), " in string interpolation" ]);
|
||||
break;
|
||||
case MemberAccessExpressionSyntax maes1:
|
||||
var accessed = snac.SemanticModel.GetSymbolInfo(maes1.Name, snac.CancellationToken).Symbol;
|
||||
if (memberInfoDotNameSym.Matches(accessed))
|
||||
{
|
||||
snac.ReportDiagnostic(Diagnostic.Create(DiagUseNameof, maes1.GetLocation(), toes.Type.GetText()));
|
||||
}
|
||||
else if (typeDotToStringSym.Matches(accessed))
|
||||
{
|
||||
snac.ReportDiagnostic(Diagnostic.Create(DiagNoToStringOnType, maes1.GetLocation(), toes.Type.GetText(), ".ToString()"));
|
||||
}
|
||||
if (memberInfoDotNameSym.Matches(accessed)) DiagUseNameof.ReportAt(maes1, snac, [ toes.Type.GetText() ]);
|
||||
else if (typeDotToStringSym.Matches(accessed)) DiagNoToStringOnType.ReportAt(maes1, snac, [ toes.Type.GetText(), ".ToString()" ]);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -58,16 +58,10 @@ public sealed class UseSimplerBoolFlipAnalyzer : DiagnosticAnalyzer
|
|||
lhsIsSimpleExpr = false;
|
||||
break;
|
||||
default:
|
||||
HawkSourceAnalyzer.ReportWTF(operation.Syntax, oac, message: $"[{nameof(UseSimplerBoolFlipAnalyzer)}] Left-hand side of XOR-assign was of an unexpected kind: {lhsOp.GetType().FullName}");
|
||||
HawkSourceAnalyzer.ReportWTF(operation, oac, message: $"[{nameof(UseSimplerBoolFlipAnalyzer)}] Left-hand side of XOR-assign was of an unexpected kind: {lhsOp.GetType().FullName}");
|
||||
return;
|
||||
}
|
||||
oac.ReportDiagnostic(Diagnostic.Create(
|
||||
DiagUseSimplerBoolFlip,
|
||||
operation.Syntax.GetLocation(),
|
||||
lhsIsSimpleExpr ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning,
|
||||
additionalLocations: null,
|
||||
properties: null,
|
||||
lhsIsSimpleExpr ? ERR_MSG_SIMPLE : ERR_MSG_COMPLEX));
|
||||
DiagUseSimplerBoolFlip.ReportAt(operation, isErrorSeverity: lhsIsSimpleExpr, oac, lhsIsSimpleExpr ? ERR_MSG_SIMPLE : ERR_MSG_COMPLEX);
|
||||
},
|
||||
OperationKind.CompoundAssignment);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public sealed class UseTypeofOperatorAnalyzer : DiagnosticAnalyzer
|
|||
var enclosingType = operation.SemanticModel!.GetDeclaredSymbol(
|
||||
((CSharpSyntaxNode) operation.Syntax).EnclosingTypeDeclarationSyntax()!,
|
||||
oac.CancellationToken)!;
|
||||
oac.ReportDiagnostic(Diagnostic.Create(enclosingType.IsSealed ? DiagNoGetTypeOnThisSealed : DiagNoGetTypeOnThis, operation.Syntax.GetLocation(), enclosingType.Name));
|
||||
(enclosingType.IsSealed ? DiagNoGetTypeOnThisSealed : DiagNoGetTypeOnThis).ReportAt(operation, oac, enclosingType.Name);
|
||||
},
|
||||
OperationKind.Invocation);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue