forked from space-wizards/RobustToolbox
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'upstream/master' into spinbox-button-di…
…sabling
- Loading branch information
Showing
109 changed files
with
2,972 additions
and
916 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.CSharp.Testing; | ||
using Microsoft.CodeAnalysis.Testing; | ||
using Microsoft.CodeAnalysis.Testing.Verifiers; | ||
using NUnit.Framework; | ||
using VerifyCS = | ||
Microsoft.CodeAnalysis.CSharp.Testing.NUnit.AnalyzerVerifier<Robust.Analyzers.MustCallBaseAnalyzer>; | ||
|
||
namespace Robust.Analyzers.Tests; | ||
|
||
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)] | ||
[TestFixture] | ||
public sealed class MustCallBaseAnalyzerTest | ||
{ | ||
private static Task Verifier(string code, params DiagnosticResult[] expected) | ||
{ | ||
var test = new CSharpAnalyzerTest<MustCallBaseAnalyzer, NUnitVerifier>() | ||
{ | ||
TestState = | ||
{ | ||
Sources = { code } | ||
}, | ||
}; | ||
|
||
TestHelper.AddEmbeddedSources( | ||
test.TestState, | ||
"Robust.Shared.IoC.MustCallBaseAttribute.cs" | ||
); | ||
|
||
// ExpectedDiagnostics cannot be set, so we need to AddRange here... | ||
test.TestState.ExpectedDiagnostics.AddRange(expected); | ||
|
||
return test.RunAsync(); | ||
} | ||
|
||
[Test] | ||
public async Task Test() | ||
{ | ||
const string code = """ | ||
using Robust.Shared.Analyzers; | ||
public class Foo | ||
{ | ||
[MustCallBase] | ||
public virtual void Function() | ||
{ | ||
} | ||
[MustCallBase(true)] | ||
public virtual void Function2() | ||
{ | ||
} | ||
} | ||
public class Bar : Foo | ||
{ | ||
public override void Function() | ||
{ | ||
} | ||
public override void Function2() | ||
{ | ||
} | ||
} | ||
public class Baz : Foo | ||
{ | ||
public override void Function() | ||
{ | ||
base.Function(); | ||
} | ||
} | ||
public class Bal : Bar | ||
{ | ||
public override void Function2() | ||
{ | ||
} | ||
} | ||
"""; | ||
|
||
await Verifier(code, | ||
// /0/Test0.cs(20,26): warning RA0028: Overriders of this function must always call the base function | ||
VerifyCS.Diagnostic().WithSpan(20, 26, 20, 34), | ||
// /0/Test0.cs(41,26): warning RA0028: Overriders of this function must always call the base function | ||
VerifyCS.Diagnostic().WithSpan(41, 26, 41, 35)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using Robust.Roslyn.Shared; | ||
|
||
namespace Robust.Analyzers; | ||
|
||
#nullable enable | ||
|
||
/// <summary> | ||
/// Enforces <c>MustCallBaseAttribute</c>. | ||
/// </summary> | ||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public sealed class MustCallBaseAnalyzer : DiagnosticAnalyzer | ||
{ | ||
private const string Attribute = "Robust.Shared.Analyzers.MustCallBaseAttribute"; | ||
|
||
private static readonly DiagnosticDescriptor Rule = new( | ||
Diagnostics.IdMustCallBase, | ||
"No base call in overriden function", | ||
"Overriders of this function must always call the base function", | ||
"Usage", | ||
DiagnosticSeverity.Warning, | ||
isEnabledByDefault: true); | ||
|
||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule); | ||
|
||
public override void Initialize(AnalysisContext context) | ||
{ | ||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | ||
context.EnableConcurrentExecution(); | ||
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.Method); | ||
} | ||
|
||
private static void AnalyzeSymbol(SymbolAnalysisContext context) | ||
{ | ||
if (context.Symbol is not IMethodSymbol { IsOverride: true } method) | ||
return; | ||
|
||
var attrSymbol = context.Compilation.GetTypeByMetadataName(Attribute); | ||
if (attrSymbol == null) | ||
return; | ||
|
||
if (DoesMethodOverriderHaveAttribute(method, attrSymbol) is not { } data) | ||
return; | ||
|
||
if (data is { onlyOverrides: true, depth: < 2 }) | ||
return; | ||
|
||
var syntax = (MethodDeclarationSyntax) method.DeclaringSyntaxReferences[0].GetSyntax(); | ||
if (HasBaseCall(syntax)) | ||
return; | ||
|
||
var diag = Diagnostic.Create(Rule, syntax.Identifier.GetLocation()); | ||
context.ReportDiagnostic(diag); | ||
} | ||
|
||
private static (int depth, bool onlyOverrides)? DoesMethodOverriderHaveAttribute( | ||
IMethodSymbol method, | ||
INamedTypeSymbol attributeSymbol) | ||
{ | ||
var depth = 0; | ||
while (method.OverriddenMethod != null) | ||
{ | ||
depth += 1; | ||
method = method.OverriddenMethod; | ||
if (GetAttribute(method, attributeSymbol) is not { } attribute) | ||
continue; | ||
|
||
var onlyOverrides = attribute.ConstructorArguments is [{Kind: TypedConstantKind.Primitive, Value: true}]; | ||
return (depth, onlyOverrides); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private static bool HasBaseCall(MethodDeclarationSyntax syntax) | ||
{ | ||
return syntax.Accept(new BaseCallLocator()); | ||
} | ||
|
||
private static AttributeData? GetAttribute(ISymbol namedTypeSymbol, INamedTypeSymbol attrSymbol) | ||
{ | ||
return namedTypeSymbol.GetAttributes() | ||
.SingleOrDefault(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attrSymbol)); | ||
} | ||
|
||
private sealed class BaseCallLocator : CSharpSyntaxVisitor<bool> | ||
{ | ||
public override bool VisitBaseExpression(BaseExpressionSyntax node) | ||
{ | ||
return true; | ||
} | ||
|
||
public override bool DefaultVisit(SyntaxNode node) | ||
{ | ||
foreach (var childNode in node.ChildNodes()) | ||
{ | ||
if (childNode is not CSharpSyntaxNode cSharpSyntax) | ||
continue; | ||
|
||
if (cSharpSyntax.Accept(this)) | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.