UDA to disable linting: handle check status in NoLint struct

This commit is contained in:
Axel Ricard 2023-10-12 21:20:04 +02:00
parent 43c93e2537
commit 7fc1081630
4 changed files with 65 additions and 77 deletions

View file

@ -1,8 +1,8 @@
module dscanner.analysis.base;
import dscanner.analysis.nolint;
import dparse.ast;
import dparse.lexer : IdType, str, Token, tok;
import dscanner.analysis.nolint;
import dsymbol.scope_ : Scope;
import std.array;
import std.container;
@ -413,8 +413,9 @@ public:
*/
override void visit(const(ModuleDeclaration) moduleDeclaration)
{
if(stopLinting(moduleDeclaration))
return;
auto currNoLint = NoLintFactory.fromModuleDeclaration(moduleDeclaration);
noLint.push(currNoLint);
scope(exit) noLint.pop(currNoLint);
moduleDeclaration.accept(this);
}
@ -426,12 +427,11 @@ public:
*/
override void visit(const(Declaration) decl)
{
const msgDisabled = maybeDisableErrorMessage(decl);
auto currNoLint = NoLintFactory.fromDeclaration(decl);
noLint.push(currNoLint);
scope(exit) noLint.pop(currNoLint);
decl.accept(this);
if(msgDisabled)
reenableErrorMessage();
}
AutoFix.CodeReplacement[] resolveAutoFix(
@ -452,7 +452,7 @@ protected:
bool inAggregate;
bool skipTests;
int errorMsgDisabled;
NoLint noLint;
template visitTemplate(T)
{
@ -467,42 +467,42 @@ protected:
deprecated("Use the overload taking start and end locations or a Node instead")
void addErrorMessage(size_t line, size_t column, string key, string message)
{
if(!errorMsgEnabled())
if(noLint.containsCheck(this.getName()))
return;
_messages.insert(Message(fileName, line, column, key, message, getName()));
}
void addErrorMessage(const BaseNode node, string key, string message, AutoFix[] autofixes = null)
{
if(!errorMsgEnabled())
if(noLint.containsCheck(this.getName()))
return;
addErrorMessage(Message.Diagnostic.from(fileName, node, message), key, autofixes);
}
void addErrorMessage(const Token token, string key, string message, AutoFix[] autofixes = null)
{
if(!errorMsgEnabled())
if(noLint.containsCheck(this.getName()))
return;
addErrorMessage(Message.Diagnostic.from(fileName, token, message), key, autofixes);
}
void addErrorMessage(const Token[] tokens, string key, string message, AutoFix[] autofixes = null)
{
if(!errorMsgEnabled())
if(noLint.containsCheck(this.getName()))
return;
addErrorMessage(Message.Diagnostic.from(fileName, tokens, message), key, autofixes);
}
void addErrorMessage(size_t[2] index, size_t line, size_t[2] columns, string key, string message, AutoFix[] autofixes = null)
{
if(!errorMsgEnabled())
if(noLint.containsCheck(this.getName()))
return;
addErrorMessage(index, [line, line], columns, key, message, autofixes);
}
void addErrorMessage(size_t[2] index, size_t[2] lines, size_t[2] columns, string key, string message, AutoFix[] autofixes = null)
{
if(!errorMsgEnabled())
if(noLint.containsCheck(this.getName()))
return;
auto d = Message.Diagnostic.from(fileName, index, lines, columns, message);
_messages.insert(Message(d, key, getName(), autofixes));
@ -510,57 +510,18 @@ protected:
void addErrorMessage(Message.Diagnostic diagnostic, string key, AutoFix[] autofixes = null)
{
if(!errorMsgEnabled())
if(noLint.containsCheck(this.getName()))
return;
_messages.insert(Message(diagnostic, key, getName(), autofixes));
}
void addErrorMessage(Message.Diagnostic diagnostic, Message.Diagnostic[] supplemental, string key, AutoFix[] autofixes = null)
{
if(!errorMsgEnabled())
if(noLint.containsCheck(this.getName()))
return;
_messages.insert(Message(diagnostic, supplemental, key, getName(), autofixes));
}
void reenableErrorMessage()
in(this.errorMsgDisabled > 0)
{
this.errorMsgDisabled--;
}
bool errorMsgEnabled() const
{
return this.errorMsgDisabled == 0;
}
// Disable error message if declaration contains UDA :
// @("nolint(..)") and @nolint(".."), ..
// that indicates to skip linting on this declaration
// Return wheter the message is actually disabled or not
bool maybeDisableErrorMessage(const Declaration decl)
{
if(stopLinting(decl))
{
this.errorMsgDisabled++;
return true;
}
else
return false;
}
bool stopLinting(AstNode)(const AstNode node)
{
import std.typecons: Nullable;
Nullable!NoLint noLint;
static if(is(AstNode == ModuleDeclaration))
noLint = NoLintFactory.fromModuleDeclaration(node);
else static if(is(AstNode == Declaration))
noLint = NoLintFactory.fromDeclaration(node);
return !noLint.isNull && noLint.get.containsCheck(this.getName());
}
/**
* The file name
*/

View file

@ -13,28 +13,47 @@ struct NoLint
{
bool containsCheck(in string check) const
{
return disabledChecks.canFind(check);
return (check in disabledChecks) !is null &&
disabledChecks[check] > 0;
}
package:
const(string[]) getDisabledChecks() const
const(int[string]) getDisabledChecks() const
{
return this.disabledChecks;
}
void addCheck(in string check)
void pushCheck(in string check)
{
disabledChecks ~= check;
disabledChecks[check]++;
}
void merge(in Nullable!NoLint other)
void push(in Nullable!NoLint other)
{
if(!other.isNull)
this.disabledChecks ~= other.get.getDisabledChecks();
if(other.isNull)
return;
foreach(item; other.get.getDisabledChecks.byKeyValue)
this.disabledChecks[item.key] += item.value;
}
void pop(in Nullable!NoLint other)
{
if(other.isNull)
return;
foreach(item; other.get.getDisabledChecks.byKeyValue)
{
assert((item.key in disabledChecks) !is null &&
this.disabledChecks[item.key] >= item.value);
this.disabledChecks[item.key] -= item.value;
}
}
private:
string[] disabledChecks;
int[string] disabledChecks;
}
struct NoLintFactory
@ -44,7 +63,7 @@ struct NoLintFactory
NoLint noLint;
foreach(atAttribute; moduleDeclaration.atAttributes)
noLint.merge(NoLintFactory.fromAtAttribute(atAttribute));
noLint.push(NoLintFactory.fromAtAttribute(atAttribute));
if(!noLint.getDisabledChecks.length)
return nullNoLint;
@ -56,7 +75,7 @@ struct NoLintFactory
{
NoLint noLint;
foreach(attribute; declaration.attributes)
noLint.merge(NoLintFactory.fromAttribute(attribute));
noLint.push(NoLintFactory.fromAttribute(attribute));
if(!noLint.getDisabledChecks.length)
return nullNoLint;
@ -115,7 +134,7 @@ private:
if(primaryExpression.primary != tok!"stringLiteral")
continue;
noLint.addCheck(primaryExpression.primary.text.strip("\""));
noLint.pushCheck(primaryExpression.primary.text.strip("\""));
}
}
@ -144,7 +163,7 @@ private:
auto str = primaryExpression.primary.text.strip("\"");
Nullable!NoLint currNoLint = NoLintFactory.fromString(str);
noLint.merge(currNoLint);
noLint.push(currNoLint);
}
}
@ -175,7 +194,7 @@ private:
while(matches)
{
noLint.addCheck(matches.hit);
noLint.pushCheck(matches.hit);
matches.popFront;
}
@ -195,8 +214,14 @@ unittest
const s3 = " nolint ( abc , efg ) ";
const s4 = "OtherUda(abc)";
assert(NoLintFactory.fromString(s1).get == NoLint(["abc"]));
assert(NoLintFactory.fromString(s2).get == NoLint(["abc", "efg", "hij"]));
assert(NoLintFactory.fromString(s3).get == NoLint(["abc", "efg"]));
assert(NoLintFactory.fromString(s1).get.containsCheck("abc"));
assert(NoLintFactory.fromString(s2).get.containsCheck("abc"));
assert(NoLintFactory.fromString(s2).get.containsCheck("efg"));
assert(NoLintFactory.fromString(s2).get.containsCheck("hij"));
assert(NoLintFactory.fromString(s3).get.containsCheck("abc"));
assert(NoLintFactory.fromString(s3).get.containsCheck("efg"));
assert(NoLintFactory.fromString(s4).isNull);
}

View file

@ -14,6 +14,7 @@ import std.conv;
import std.format;
import dscanner.analysis.helpers;
import dscanner.analysis.base;
import dscanner.analysis.nolint;
import dsymbol.scope_ : Scope;
final class StyleChecker : BaseAnalyzer
@ -33,8 +34,9 @@ final class StyleChecker : BaseAnalyzer
override void visit(const ModuleDeclaration dec)
{
if(stopLinting(dec))
return;
auto currNoLint = NoLintFactory.fromModuleDeclaration(dec);
noLint.push(currNoLint);
scope(exit) noLint.pop(currNoLint);
foreach (part; dec.moduleName.identifiers)
{

View file

@ -5,6 +5,7 @@
module dscanner.analysis.useless_initializer;
import dscanner.analysis.base;
import dscanner.analysis.nolint;
import dscanner.utils : safeAccess;
import containers.dynamicarray;
import containers.hashmap;
@ -93,13 +94,12 @@ public:
{
_inStruct.insert(decl.structDeclaration !is null);
const msgDisabled = maybeDisableErrorMessage(decl);
auto currNoLint = NoLintFactory.fromDeclaration(decl);
noLint.push(currNoLint);
scope(exit) noLint.pop(currNoLint);
decl.accept(this);
if(msgDisabled)
reenableErrorMessage();
if (_inStruct.length > 1 && _inStruct[$-2] && decl.constructor &&
((decl.constructor.parameters && decl.constructor.parameters.parameters.length == 0) ||
!decl.constructor.parameters))