Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support // @nolint(...) comments as well #941

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 88 additions & 8 deletions src/dscanner/analysis/base.d
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,29 @@
const Scope* sc;
bool skipTests = false;

// auto-generated members:
size_t[typeof(Token.line)] lineEndTokenIndices;
size_t[typeof(Token.line)] lineStartTokenIndices;

void preprocess()
{
if (!tokens.length)
return;

typeof(Token.line) line = -1;
foreach (i, t; tokens)
{
if (t.line != line)
{
lineStartTokenIndices[t.line] = i;
if (i != 0)
lineEndTokenIndices[tokens[i - 1].line] = i - 1;
}
}

lineEndTokenIndices[tokens[$ - 1].line] = tokens.length - 1;
}

BaseAnalyzerArguments setSkipTests(bool v)
{
auto ret = this;
Expand Down Expand Up @@ -406,6 +429,8 @@
this.tokens = args.tokens;
this.fileName = args.fileName;
this.skipTests = args.skipTests;
this.lineEndTokenIndices = args.lineEndTokenIndices;
this.lineStartTokenIndices = args.lineStartTokenIndices;
_messages = new MessageSet;
}

Expand Down Expand Up @@ -481,6 +506,8 @@
bool inAggregate;
bool skipTests;
const(Token)[] tokens;
size_t[typeof(Token.line)] lineEndTokenIndices;
size_t[typeof(Token.line)] lineStartTokenIndices;
NoLint noLint;

template visitTemplate(T)
Expand All @@ -496,57 +523,57 @@
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 (noLint.containsCheck(key))
if (checkNoLint(key, [findToken(line, column)]))
return;
_messages.insert(Message(fileName, line, column, key, message, getName()));
}

void addErrorMessage(const BaseNode node, string key, string message, AutoFix[] autofixes = null)
{
if (noLint.containsCheck(key))
if (checkNoLint(key, node.tokens))
return;
addErrorMessage(Message.Diagnostic.from(fileName, node, message), key, autofixes);
}

void addErrorMessage(const Token token, string key, string message, AutoFix[] autofixes = null)
{
if (noLint.containsCheck(key))
if (checkNoLint(key, [token]))
return;
addErrorMessage(Message.Diagnostic.from(fileName, token, message), key, autofixes);
}

void addErrorMessage(const Token[] tokens, string key, string message, AutoFix[] autofixes = null)
{
if (noLint.containsCheck(key))
if (checkNoLint(key, tokens))
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 (noLint.containsCheck(key))
if (checkNoLint(key, [findToken(index[0]), findToken(index[1])]))
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 (noLint.containsCheck(key))
if (checkNoLint(key, [findToken(index[0]), findToken(index[1])]))
return;
auto d = Message.Diagnostic.from(fileName, index, lines, columns, message);
_messages.insert(Message(d, key, getName(), autofixes));
}

void addErrorMessage(Message.Diagnostic diagnostic, string key, AutoFix[] autofixes = null)
{
if (noLint.containsCheck(key))
if (checkNoLint(key, null)) // TODO
return;
_messages.insert(Message(diagnostic, key, getName(), autofixes));
}

void addErrorMessage(Message.Diagnostic diagnostic, Message.Diagnostic[] supplemental, string key, AutoFix[] autofixes = null)
{
if (noLint.containsCheck(key))
if (checkNoLint(key, null)) // TODO
return;
_messages.insert(Message(diagnostic, supplemental, key, getName(), autofixes));
}
Expand All @@ -559,6 +586,59 @@
const(Scope)* sc;

MessageSet _messages;

private const Token findToken(typeof(Token.index) index)

Check warning on line 590 in src/dscanner/analysis/base.d

View workflow job for this annotation

GitHub Actions / Run all tests (dmd-latest, dmd, ubuntu-22.04, dub, current)

Warning (unused_parameter_check)

Parameter index is never used.
{
return Token.init; // todo
}

private const Token findToken(typeof(Token.line) line, typeof(Token.column) column)

Check warning on line 595 in src/dscanner/analysis/base.d

View workflow job for this annotation

GitHub Actions / Run all tests (dmd-latest, dmd, ubuntu-22.04, dub, current)

Warning (unused_parameter_check)

Parameter line is never used.

Check warning on line 595 in src/dscanner/analysis/base.d

View workflow job for this annotation

GitHub Actions / Run all tests (dmd-latest, dmd, ubuntu-22.04, dub, current)

Warning (unused_parameter_check)

Parameter column is never used.
{
return Token.init; // todo
}

private const Token getLastLineToken(typeof(Token.line) line)
{
if (auto pi = line in lineEndTokenIndices)
return tokens[*pi];
return Token.init;
}

private bool checkNoLint(string key, const(Token)[] tokens)
{
if (noLint.containsCheck(key))
return true;
if (!tokens.length)
return false;
auto first = tokens[0].leadingTrivia;

Check warning on line 613 in src/dscanner/analysis/base.d

View workflow job for this annotation

GitHub Actions / Run all tests (dmd-latest, dmd, ubuntu-22.04, dub, current)

Warning (unused_variable_check)

Variable first is never used.
auto last = tokens[$ - 1].trailingTrivia;

Check warning on line 614 in src/dscanner/analysis/base.d

View workflow job for this annotation

GitHub Actions / Run all tests (dmd-latest, dmd, ubuntu-22.04, dub, current)

Warning (unused_variable_check)

Variable last is never used.
auto line = getLastLineToken(tokens[$ - 1].line).trailingTrivia;

Check warning on line 615 in src/dscanner/analysis/base.d

View workflow job for this annotation

GitHub Actions / Run all tests (dmd-latest, dmd, ubuntu-22.04, dub, current)

Warning (unused_variable_check)

Variable line is never used.

bool checkComments(typeof(Token.leadingTrivia) tokens)
{
foreach (token; tokens)
{
if (token.type == tok!"comment"
&& token.text.startsWith(
"// @nolint",
"// @suppress")) // in use in some projects since this was introduced in code-d
{
auto nolintUDA = token.text[3 .. $];
auto n = NoLintFactory.fromString(nolintUDA);
if (!n.isNull && n.get.containsCheck(key))
return true;
}
}
return false;
}

if (checkComments(getLastLineToken(tokens[$ - 1].line).trailingTrivia)
|| checkComments(tokens[$ - 1].trailingTrivia)
|| checkComments(tokens[0].leadingTrivia))
return true;

return false;
}
}

/// Find the token with the given type, otherwise returns the whole range or a user-specified fallback, if set.
Expand Down
64 changes: 32 additions & 32 deletions src/dscanner/analysis/nolint.d
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,38 @@ struct NoLintFactory
return noLint.nullable;
}

// Transform a string with form "nolint(abc, efg)"
// into a NoLint struct
static Nullable!NoLint fromString(in string str)
{
static immutable re = regex(`[\w-_.]+`, "g");
auto matches = matchAll(str, re);

if (!matches)
return nullNoLint;

const udaName = matches.hit;
if (udaName != "nolint")
return nullNoLint;

matches.popFront;

NoLint noLint;

while (matches)
{
noLint.pushCheck(matches.hit);
matches.popFront;
}

if (!noLint.getDisabledChecks.length)
return nullNoLint;

return noLint.nullable;
}

static nullNoLint = Nullable!NoLint.init;

private:
static Nullable!NoLint fromAttribute(const(Attribute) attribute)
{
Expand Down Expand Up @@ -205,38 +237,6 @@ private:
return noLint.nullable;

}

// Transform a string with form "nolint(abc, efg)"
// into a NoLint struct
static Nullable!NoLint fromString(in string str)
{
static immutable re = regex(`[\w-_.]+`, "g");
auto matches = matchAll(str, re);

if (!matches)
return nullNoLint;

const udaName = matches.hit;
if (udaName != "nolint")
return nullNoLint;

matches.popFront;

NoLint noLint;

while (matches)
{
noLint.pushCheck(matches.hit);
matches.popFront;
}

if (!noLint.getDisabledChecks.length)
return nullNoLint;

return noLint.nullable;
}

static nullNoLint = Nullable!NoLint.init;
}

unittest
Expand Down
1 change: 1 addition & 0 deletions src/dscanner/analysis/run.d
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,7 @@ private BaseAnalyzer[] getAnalyzersForModuleAndConfig(string fileName,
tokens,
moduleScope
);
args.preprocess();

if (moduleName.shouldRun!AsmStyleCheck(analysisConfig))
checks ~= new AsmStyleCheck(args.setSkipTests(
Expand Down
3 changes: 2 additions & 1 deletion src/dscanner/analysis/useless_initializer.d
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,8 @@ public:
assertAnalyzerWarnings(q{
@("nolint(dscanner.useless-initializer)")
int a = 0;
int a = 0; /+
int a = 0; // @nolint(dscanner.useless-initializer)
int a = 0; /+
^ [warn]: X +/

@("nolint(dscanner.useless-initializer)")
Expand Down
Loading