From 8e836fc6bc1a943fef7ff469f7a132e9a8b38f9a Mon Sep 17 00:00:00 2001 From: Vladiwostok <55026261+Vladiwostok@users.noreply.github.com> Date: Tue, 15 Oct 2024 09:36:54 +0300 Subject: [PATCH] Respect @nolint user attribute (#158) * Respect @nolint in UnmodifiedFinder * Respect @nolint in UselessInitializerChecker * Respect @nolint in StaticIfElse * Fix visibility in base.d --- src/dscanner/analysis/base.d | 23 ++++++ src/dscanner/analysis/static_if_else.d | 16 ++++ src/dscanner/analysis/unmodified.d | 23 ++++++ src/dscanner/analysis/useless_initializer.d | 85 ++++++++++++--------- 4 files changed, 111 insertions(+), 36 deletions(-) diff --git a/src/dscanner/analysis/base.d b/src/dscanner/analysis/base.d index 3a43d64..71e1cd7 100644 --- a/src/dscanner/analysis/base.d +++ b/src/dscanner/analysis/base.d @@ -9,6 +9,7 @@ import std.container; import std.meta : AliasSeq; import std.string; import std.sumtype; +import dmd.attrib : UserAttributeDeclaration; import dmd.visitor.transitive; import dmd.visitor; import dmd.func; @@ -984,4 +985,26 @@ protected: extern (D) string fileName; extern (D) MessageSet _messages; + + extern (D) bool shouldIgnoreDecl(UserAttributeDeclaration userAtt, string key) + { + import std.algorithm : startsWith; + import std.string : indexOf; + + if (userAtt is null) + return false; + + auto atts = userAtt.atts; + if (atts !is null && (*(atts)).length > 0) + { + if (auto att = (*(atts))[0].isStringExp()) + { + string attStr = cast(string) att.toStringz(); + if (attStr.startsWith("nolint") && attStr.indexOf(key) > 0) + return true; + } + } + + return false; + } } diff --git a/src/dscanner/analysis/static_if_else.d b/src/dscanner/analysis/static_if_else.d index 23da9de..3818544 100644 --- a/src/dscanner/analysis/static_if_else.d +++ b/src/dscanner/analysis/static_if_else.d @@ -31,6 +31,22 @@ extern(C++) class StaticIfElse(AST) : BaseAnalyzerDmd super(fileName, skipTests); } + override void visit(AST.UserAttributeDeclaration userAttribute) + { + if (shouldIgnoreDecl(userAttribute, KEY)) + return; + + super.visit(userAttribute); + } + + override void visit(AST.Module mod) + { + if (shouldIgnoreDecl(mod.userAttribDecl(), KEY)) + return; + + super.visit(mod); + } + override void visit(AST.ConditionalStatement s) { import dmd.astenums : STMT; diff --git a/src/dscanner/analysis/unmodified.d b/src/dscanner/analysis/unmodified.d index 3ad561f..7fcef71 100644 --- a/src/dscanner/analysis/unmodified.d +++ b/src/dscanner/analysis/unmodified.d @@ -36,6 +36,22 @@ extern (C++) class UnmodifiedFinder(AST) : BaseAnalyzerDmd pushScope(); } + override void visit(AST.UserAttributeDeclaration userAttribute) + { + if (shouldIgnoreDecl(userAttribute, KEY)) + return; + + super.visit(userAttribute); + } + + override void visit(AST.Module mod) + { + if (shouldIgnoreDecl(mod.userAttribDecl(), KEY)) + return; + + super.visit(mod); + } + override void visit(AST.CompoundStatement compoundStatement) { pushScope(); @@ -324,5 +340,12 @@ unittest } }c, sac); + assertAnalyzerWarningsDMD(q{ + @("nolint(dscanner.suspicious.unmodified)") + void foo(){ + int i = 1; + } + }, sac); + stderr.writeln("Unittest for UnmodifiedFinder passed."); } diff --git a/src/dscanner/analysis/useless_initializer.d b/src/dscanner/analysis/useless_initializer.d index 756c47c..ce989c3 100644 --- a/src/dscanner/analysis/useless_initializer.d +++ b/src/dscanner/analysis/useless_initializer.d @@ -19,7 +19,6 @@ Limitations: * Check that detects the initializers that are * not different from the implcit initializer. */ -// TODO: Fix NoLint extern (C++) class UselessInitializerChecker(AST) : BaseAnalyzerDmd { alias visit = BaseAnalyzerDmd.visit; @@ -44,6 +43,22 @@ extern (C++) class UselessInitializerChecker(AST) : BaseAnalyzerDmd super(fileName, skipTests); } + override void visit(AST.UserAttributeDeclaration userAttribute) + { + if (shouldIgnoreDecl(userAttribute, KEY)) + return; + + super.visit(userAttribute); + } + + override void visit(AST.Module mod) + { + if (shouldIgnoreDecl(mod.userAttribDecl(), KEY)) + return; + + super.visit(mod); + } + override void visit(AST.UnitTestDeclaration unitTestDecl) { if (skipTests) @@ -303,43 +318,41 @@ extern (C++) class UselessInitializerChecker(AST) : BaseAnalyzerDmd }, sac); // passes - //assertAnalyzerWarnings(q{ - // @("nolint(dscanner.useless-initializer)") - // int a = 0; - // int a = 0; /+ - // ^ [warn]: X +/ - // - // @("nolint(dscanner.useless-initializer)") - // int f() { - // int a = 0; - // } - // - // struct nolint { string s; } - // - // @nolint("dscanner.useless-initializer") - // int a = 0; - // int a = 0; /+ - // ^ [warn]: X +/ - // - // @("nolint(other_check, dscanner.useless-initializer, another_one)") - // int a = 0; - // - // @nolint("other_check", "another_one", "dscanner.useless-initializer") - // int a = 0; - // - //}, sac); + assertAnalyzerWarningsDMD(q{ + @("nolint(dscanner.useless-initializer)") + int x = 0; + int a = 0; // [warn]: %s + + @("nolint(dscanner.useless-initializer)") + int f() { + int a = 0; + } + + struct nolint { string s; } + + @("nolint(dscanner.useless-initializer)") + int c = 0; + int s = 0; // [warn]: %s + + @("nolint(other_check, dscanner.useless-initializer, another_one)") + int e = 0; + + @("nolint(other_check, another_one, dscanner.useless-initializer)") + int f = 0; + + }c.format(msgA, msgS), sac); // passes (disable check at module level) - //assertAnalyzerWarnings(q{ - // @("nolint(dscanner.useless-initializer)") - // module my_module; - // - // int a = 0; - // - // int f() { - // int a = 0; - // } - //}, sac); + assertAnalyzerWarningsDMD(q{ + @("nolint(dscanner.useless-initializer)") + module my_module; + + int a = 0; + + int f() { + int a = 0; + } + }c, sac); stderr.writeln("Unittest for UselessInitializerChecker passed."); }