Add Analyzer to disallow discarding locals e.g. `_ = result;`
fixes70bd081a9
,a2185d9ef
This commit is contained in:
parent
a2185d9ef0
commit
8a5921182e
|
@ -16,6 +16,9 @@
|
||||||
<!-- Default branch of switch expression should throw InvalidOperationException/SwitchExpressionException or not throw -->
|
<!-- Default branch of switch expression should throw InvalidOperationException/SwitchExpressionException or not throw -->
|
||||||
<Rule Id="BHI1005" Action="Error" />
|
<Rule Id="BHI1005" Action="Error" />
|
||||||
|
|
||||||
|
<!-- Do not discard local variables -->
|
||||||
|
<Rule Id="BHI1006" Action="Error" />
|
||||||
|
|
||||||
<!-- Don't call this.GetType() in sealed type, use typeof operator -->
|
<!-- Don't call this.GetType() in sealed type, use typeof operator -->
|
||||||
<Rule Id="BHI1100" Action="Error" />
|
<Rule Id="BHI1100" Action="Error" />
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,14 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer
|
||||||
defaultSeverity: DiagnosticSeverity.Error,
|
defaultSeverity: DiagnosticSeverity.Error,
|
||||||
isEnabledByDefault: true);
|
isEnabledByDefault: true);
|
||||||
|
|
||||||
|
private static readonly DiagnosticDescriptor DiagNoDiscardingLocals = new(
|
||||||
|
id: "BHI1006",
|
||||||
|
title: "Do not discard local variables",
|
||||||
|
messageFormat: "RHS is a local, so this discard has no effect, and is at best unhelpful for humans",
|
||||||
|
category: "Usage",
|
||||||
|
defaultSeverity: DiagnosticSeverity.Error,
|
||||||
|
isEnabledByDefault: true);
|
||||||
|
|
||||||
private static readonly DiagnosticDescriptor DiagNoQueryExpression = new(
|
private static readonly DiagnosticDescriptor DiagNoQueryExpression = new(
|
||||||
id: "BHI1003",
|
id: "BHI1003",
|
||||||
title: "Do not use query expression syntax",
|
title: "Do not use query expression syntax",
|
||||||
|
@ -58,11 +66,14 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer
|
||||||
DiagInterpStringIsDollarAt,
|
DiagInterpStringIsDollarAt,
|
||||||
DiagNoAnonClasses,
|
DiagNoAnonClasses,
|
||||||
DiagNoAnonDelegates,
|
DiagNoAnonDelegates,
|
||||||
|
DiagNoDiscardingLocals,
|
||||||
DiagNoQueryExpression,
|
DiagNoQueryExpression,
|
||||||
DiagSwitchShouldThrowIOE);
|
DiagSwitchShouldThrowIOE);
|
||||||
|
|
||||||
public override void Initialize(AnalysisContext context)
|
public override void Initialize(AnalysisContext context)
|
||||||
{
|
{
|
||||||
|
static bool IsDiscard(AssignmentExpressionSyntax aes)
|
||||||
|
=> aes.OperatorToken.RawKind is (int) SyntaxKind.EqualsToken && aes.Left is IdentifierNameSyntax { Identifier.Text: "_" };
|
||||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
|
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
|
||||||
context.EnableConcurrentExecution();
|
context.EnableConcurrentExecution();
|
||||||
INamedTypeSymbol? invalidOperationExceptionSym = null;
|
INamedTypeSymbol? invalidOperationExceptionSym = null;
|
||||||
|
@ -83,6 +94,9 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer
|
||||||
case AnonymousObjectCreationExpressionSyntax:
|
case AnonymousObjectCreationExpressionSyntax:
|
||||||
snac.ReportDiagnostic(Diagnostic.Create(DiagNoAnonClasses, snac.Node.GetLocation()));
|
snac.ReportDiagnostic(Diagnostic.Create(DiagNoAnonClasses, snac.Node.GetLocation()));
|
||||||
break;
|
break;
|
||||||
|
case AssignmentExpressionSyntax aes when IsDiscard(aes) && snac.SemanticModel.GetSymbolInfo(aes.Right).Symbol?.Kind is SymbolKind.Local:
|
||||||
|
snac.ReportDiagnostic(Diagnostic.Create(DiagNoDiscardingLocals, snac.Node.GetLocation()));
|
||||||
|
break;
|
||||||
case InterpolatedStringExpressionSyntax ises:
|
case InterpolatedStringExpressionSyntax ises:
|
||||||
if (ises.StringStartToken.Text[0] is '@') snac.ReportDiagnostic(Diagnostic.Create(DiagInterpStringIsDollarAt, ises.GetLocation()));
|
if (ises.StringStartToken.Text[0] is '@') snac.ReportDiagnostic(Diagnostic.Create(DiagInterpStringIsDollarAt, ises.GetLocation()));
|
||||||
break;
|
break;
|
||||||
|
@ -113,6 +127,7 @@ public class HawkSourceAnalyzer : DiagnosticAnalyzer
|
||||||
SyntaxKind.AnonymousMethodExpression,
|
SyntaxKind.AnonymousMethodExpression,
|
||||||
SyntaxKind.InterpolatedStringExpression,
|
SyntaxKind.InterpolatedStringExpression,
|
||||||
SyntaxKind.QueryExpression,
|
SyntaxKind.QueryExpression,
|
||||||
|
SyntaxKind.SimpleAssignmentExpression,
|
||||||
SyntaxKind.SwitchExpressionArm);
|
SyntaxKind.SwitchExpressionArm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
./build_debug.sh
|
||||||
|
cd ../../ExternalToolProjects/HelloWorld
|
||||||
|
rm -fr bin obj
|
||||||
|
./build_debug.sh
|
Binary file not shown.
|
@ -796,7 +796,7 @@ namespace BizHawk.Client.Common
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = game!; // shouldn't be null if `nextEmulator` isn't? just in case
|
if (game is null) throw new Exception("RomLoader returned core but no GameInfo"); // shouldn't be null if `nextEmulator` isn't? just in case
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,9 +63,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
tuple =>
|
tuple =>
|
||||||
{
|
{
|
||||||
var instance = tuple.Ctor.Invoke(tuple.CtorTypes.Select(t => avail[t]).ToArray());
|
var instance = tuple.Ctor.Invoke(tuple.CtorTypes.Select(t => avail[t]).ToArray());
|
||||||
var success = ServiceInjector.UpdateServices(serviceProvider, instance, mayCache: true);
|
if (!ServiceInjector.UpdateServices(serviceProvider, instance, mayCache: true)) throw new Exception("ApiHawk impl. has required service(s) that can't be fulfilled");
|
||||||
Debug.Assert(success);
|
|
||||||
_ = success;
|
|
||||||
return (IExternalApi) instance;
|
return (IExternalApi) instance;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,9 +66,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|| lib.GetCustomAttribute<LuaLibraryAttribute>(inherit: false)?.Released is not false)
|
|| lib.GetCustomAttribute<LuaLibraryAttribute>(inherit: false)?.Released is not false)
|
||||||
{
|
{
|
||||||
var instance = (LuaLibraryBase)Activator.CreateInstance(lib, this, _apiContainer, (Action<string>)LogToLuaConsole);
|
var instance = (LuaLibraryBase)Activator.CreateInstance(lib, this, _apiContainer, (Action<string>)LogToLuaConsole);
|
||||||
var updateSuccess = ServiceInjector.UpdateServices(serviceProvider, instance, mayCache: true);
|
if (!ServiceInjector.UpdateServices(serviceProvider, instance, mayCache: true)) throw new Exception("Lua lib has required service(s) that can't be fulfilled");
|
||||||
Debug.Assert(updateSuccess);
|
|
||||||
_ = updateSuccess;
|
|
||||||
|
|
||||||
// TODO: make EmuHawk libraries have a base class with common properties such as this
|
// TODO: make EmuHawk libraries have a base class with common properties such as this
|
||||||
// and inject them here
|
// and inject them here
|
||||||
|
|
Loading…
Reference in New Issue