replace libdparse in explicitly annotated unittests check (#44)

This commit is contained in:
lucica28 2022-11-14 13:05:19 +02:00 committed by Vladiwostok
parent 50e992c219
commit 65720ab41f
2 changed files with 60 additions and 92 deletions

View file

@ -4,124 +4,93 @@
module dscanner.analysis.explicitly_annotated_unittests;
import dparse.lexer;
import dparse.ast;
import dscanner.analysis.base;
import std.stdio;
import dscanner.analysis.helpers;
/**
* Requires unittests to be explicitly annotated with either @safe or @system
*/
final class ExplicitlyAnnotatedUnittestCheck : BaseAnalyzer
extern(C++) class ExplicitlyAnnotatedUnittestCheck(AST) : BaseAnalyzerDmd
{
mixin AnalyzerInfo!"explicitly_annotated_unittests";
alias visit = BaseAnalyzerDmd.visit;
extern(D) this(string fileName)
{
super(fileName);
}
override void visit(AST.UnitTestDeclaration d)
{
import dmd.astenums : STC;
if (!(d.storage_class & STC.safe || d.storage_class & STC.system))
addErrorMessage(cast(ulong) d.loc.linnum, cast(ulong) d.loc.charnum,
KEY, MESSAGE);
super.visit(d);
}
private:
enum string KEY = "dscanner.style.explicitly_annotated_unittest";
enum string MESSAGE = "A unittest should be annotated with at least @safe or @system";
mixin AnalyzerInfo!"explicitly_annotated_unittests";
///
this(BaseAnalyzerArguments args)
{
super(args);
}
override void visit(const Declaration decl)
{
if (decl.unittest_ !is null)
{
bool isSafeOrSystem;
if (decl.attributes !is null)
foreach (attribute; decl.attributes)
{
if (attribute.atAttribute !is null)
{
const token = attribute.atAttribute.identifier.text;
if (token == "safe" || token == "system")
{
isSafeOrSystem = true;
break;
}
}
}
if (!isSafeOrSystem)
{
auto token = decl.unittest_.findTokenForDisplay(tok!"unittest");
addErrorMessage(token, KEY, MESSAGE,
[
AutoFix.insertionBefore(token[0], "@safe ", "Mark unittest @safe"),
AutoFix.insertionBefore(token[0], "@system ", "Mark unittest @system")
]);
}
}
decl.accept(this);
}
alias visit = BaseAnalyzer.visit;
}
unittest
{
import dscanner.analysis.config : Check, disabledConfig, StaticAnalysisConfig;
import dscanner.analysis.helpers : assertAnalyzerWarnings, assertAutoFix;
import std.format : format;
import std.stdio : stderr;
import std.format : format;
import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
import dscanner.analysis.helpers : assertAnalyzerWarnings;
StaticAnalysisConfig sac = disabledConfig();
sac.explicitly_annotated_unittests = Check.enabled;
assertAnalyzerWarnings(q{
assertAnalyzerWarningsDMD(q{
@disable foo() {}
@safe unittest {}
@system unittest {}
pure nothrow @system @nogc unittest {}
unittest {} /+
^^^^^^^^ [warn]: %s +/
pure nothrow @nogc unittest {} /+
^^^^^^^^ [warn]: %s +/
}c.format(
ExplicitlyAnnotatedUnittestCheck.MESSAGE,
ExplicitlyAnnotatedUnittestCheck.MESSAGE,
), sac);
unittest {} // [warn]: A unittest should be annotated with at least @safe or @system
pure nothrow @nogc unittest {} // [warn]: A unittest should be annotated with at least @safe or @system
}c, sac);
// nested
assertAnalyzerWarnings(q{
assertAnalyzerWarningsDMD(q{
struct Foo
{
@safe unittest {}
@system unittest {}
unittest {} /+
^^^^^^^^ [warn]: %s +/
pure nothrow @nogc unittest {} /+
^^^^^^^^ [warn]: %s +/
}
}c.format(
ExplicitlyAnnotatedUnittestCheck.MESSAGE,
ExplicitlyAnnotatedUnittestCheck.MESSAGE,
), sac);
// nested
assertAutoFix(q{
unittest {} // fix:0
pure nothrow @nogc unittest {} // fix:0
struct Foo
{
unittest {} // fix:1
pure nothrow @nogc unittest {} // fix:1
}
}c, q{
@safe unittest {} // fix:0
pure nothrow @nogc @safe unittest {} // fix:0
struct Foo
{
@system unittest {} // fix:1
pure nothrow @nogc @system unittest {} // fix:1
unittest {} // [warn]: A unittest should be annotated with at least @safe or @system
pure nothrow @nogc unittest {} // [warn]: A unittest should be annotated with at least @safe or @system
}
}c, sac);
// TODO: Check and fix
//// nested
//assertAutoFix(q{
//unittest {} // fix:0
//pure nothrow @nogc unittest {} // fix:0
//struct Foo
//{
//unittest {} // fix:1
//pure nothrow @nogc unittest {} // fix:1
//}
//}c, q{
//@safe unittest {} // fix:0
//pure nothrow @nogc @safe unittest {} // fix:0
//struct Foo
//{
//@system unittest {} // fix:1
//pure nothrow @nogc @system unittest {} // fix:1
//}
//}c, sac);
stderr.writeln("Unittest for ExplicitlyAnnotatedUnittestCheck passed.");
}

View file

@ -945,10 +945,6 @@ private BaseAnalyzer[] getAnalyzersForModuleAndConfig(string fileName,
checks ~= new AutoFunctionChecker(args.setSkipTests(
analysisConfig.auto_function_check == Check.skipTests && !ut));
if (moduleName.shouldRun!ExplicitlyAnnotatedUnittestCheck(analysisConfig))
checks ~= new ExplicitlyAnnotatedUnittestCheck(args.setSkipTests(
analysisConfig.explicitly_annotated_unittests == Check.skipTests && !ut));
if (moduleName.shouldRun!ProperlyDocumentedPublicFunctions(analysisConfig))
checks ~= new ProperlyDocumentedPublicFunctions(args.setSkipTests(
analysisConfig.properly_documented_public_functions == Check.skipTests && !ut));
@ -1326,6 +1322,9 @@ MessageSet analyzeDmd(string fileName, ASTBase.Module m, const char[] moduleName
if (moduleName.shouldRunDmd!(LengthSubtractionCheck!ASTBase)(config))
visitors ~= new LengthSubtractionCheck!ASTBase(fileName);
if (moduleName.shouldRunDmd!(ExplicitlyAnnotatedUnittestCheck!ASTBase)(config))
visitors ~= new ExplicitlyAnnotatedUnittestCheck!ASTBase(fileName);
foreach (visitor; visitors)
{
m.accept(visitor);