Merge pull request #340 from BBasile/skip-tests

Added an option that alows to skip the unittests analysis
This commit is contained in:
Brian Schott 2016-05-12 13:51:09 -07:00
commit d5929a4226
39 changed files with 370 additions and 234 deletions

View File

@ -43,6 +43,12 @@ analysis and it does not compile the code.
The "--styleCheck" or "-S" option runs some basic static analysis checks against The "--styleCheck" or "-S" option runs some basic static analysis checks against
the given source files. the given source files.
#### Skip style checks in the tests
Static checks in the unit tests can produce irrelevant warnings. For example,
it's legit to declare a variable that's not used if the goal is to verify that
a templatized function can be instantiated by inference of the type of this variable.
To avoid these cases, it's possible to pass the "--skipTests" option.
#### Configuration #### Configuration
By default all checks are enabled. Individual checks can be enabled or disabled By default all checks are enabled. Individual checks can be enabled or disabled
by using a configuration file. Running ```dscanner --defaultConfig``` will by using a configuration file. Running ```dscanner --defaultConfig``` will
@ -50,6 +56,16 @@ generate a default configuration file and print the file's location. The
"--config" option will allow you to specify the path to a configuration file if "--config" option will allow you to specify the path to a configuration file if
you do not want to use the one created by the "--defaultConfig" option. you do not want to use the one created by the "--defaultConfig" option.
For each check, three values are possible:
* `"disabled"`: the check is not performed.
* `"enabled"`: the check is performed.
* `"skip-unittest"`: the check is performed but not in the unit tests.
Any other value deactivates a check.
Note that the "--skipTests" option is the equivalent of changing each
`"enabled"` check by a `"skip-unittest"` check.
#### Implemented checks #### Implemented checks
* Old alias syntax (i.e "alias a b;" should be replaced with "alias b = a;"). * Old alias syntax (i.e "alias a b;" should be replaced with "alias b = a;").
* Implicit concatenation of string literals. * Implicit concatenation of string literals.
@ -85,7 +101,7 @@ you do not want to use the one created by the "--defaultConfig" option.
* Unused labels. * Unused labels.
* Lines longer than 120 characters. * Lines longer than 120 characters.
* Incorrect infinite range definitions. * Incorrect infinite range definitions.
* Some assertions that check conditions that will always be true. * Some assertions that check conditions that will always be true. This check can't be skipped in the tests.
#### Wishlist #### Wishlist

View File

@ -16,9 +16,9 @@ class AliasSyntaxCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName) this(string fileName, bool skipTests = false)
{ {
super(fileName, null); super(fileName, null, skipTests);
} }
override void visit(const AliasDeclaration ad) override void visit(const AliasDeclaration ad)
@ -40,11 +40,11 @@ private:
unittest unittest
{ {
import analysis.helpers : assertAnalyzerWarnings; import analysis.helpers : assertAnalyzerWarnings;
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
import std.stdio : stderr; import std.stdio : stderr;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.alias_syntax_check = true; sac.alias_syntax_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
alias int abcde; // [warn]: Prefer the new "'alias' identifier '=' type ';'" syntax to the old "'alias' type identifier ';'" syntax. alias int abcde; // [warn]: Prefer the new "'alias' identifier '=' type ';'" syntax to the old "'alias' type identifier ';'" syntax.
alias abcde = int; alias abcde = int;

View File

@ -20,9 +20,9 @@ class AsmStyleCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const AsmBrExp brExp) override void visit(const AsmBrExp brExp)
@ -39,10 +39,10 @@ class AsmStyleCheck : BaseAnalyzer
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.asm_style_check = true; sac.asm_style_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
void testAsm() void testAsm()
{ {

View File

@ -15,9 +15,9 @@ import analysis.base;
class AutoRefAssignmentCheck : BaseAnalyzer class AutoRefAssignmentCheck : BaseAnalyzer
{ {
/// ///
this(string fileName) this(string fileName, bool skipTests = false)
{ {
super(fileName, null); super(fileName, null, skipTests);
} }
override void visit(const Module m) override void visit(const Module m)
@ -113,11 +113,11 @@ unittest
{ {
import std.stdio : stderr; import std.stdio : stderr;
import std.format : format; import std.format : format;
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
import analysis.helpers : assertAnalyzerWarnings; import analysis.helpers : assertAnalyzerWarnings;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.auto_ref_assignment_check = true; sac.auto_ref_assignment_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
int doStuff(T)(auto ref int a) int doStuff(T)(auto ref int a)
{ {

View File

@ -27,10 +27,11 @@ alias MessageSet = RedBlackTree!(Message, comparitor, true);
abstract class BaseAnalyzer : ASTVisitor abstract class BaseAnalyzer : ASTVisitor
{ {
public: public:
this(string fileName, const Scope* sc) this(string fileName, const Scope* sc, bool skipTests = false)
{ {
this.sc = sc; this.sc = sc;
this.fileName = fileName; this.fileName = fileName;
this.skipTests = skipTests;
_messages = new MessageSet; _messages = new MessageSet;
} }
@ -39,9 +40,24 @@ public:
return _messages[].array; return _messages[].array;
} }
alias visit = ASTVisitor.visit;
/**
* Visits a unittest.
*
* When overriden, the protected bool "skipTests" should be handled
* so that the content of the test is not analyzed.
*/
override void visit(const Unittest unittest_)
{
if (!skipTests)
unittest_.accept(this);
}
protected: protected:
bool inAggregate = false; bool inAggregate = false;
bool skipTests;
template visitTemplate(T) template visitTemplate(T)
{ {

View File

@ -30,9 +30,9 @@ class BuiltinPropertyNameCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const FunctionDeclaration fd) override void visit(const FunctionDeclaration fd)
@ -101,10 +101,10 @@ private:
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.builtin_property_names_check = true; sac.builtin_property_names_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
class SomeClass class SomeClass
{ {

View File

@ -17,9 +17,9 @@ class CommaExpressionCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const Expression ex) override void visit(const Expression ex)

View File

@ -10,113 +10,138 @@ import inifiled;
StaticAnalysisConfig defaultStaticAnalysisConfig() StaticAnalysisConfig defaultStaticAnalysisConfig()
{ {
StaticAnalysisConfig config; StaticAnalysisConfig config;
foreach (mem; __traits(allMembers, StaticAnalysisConfig)) config.fillConfig!(Check.enabled);
mixin("config." ~ mem ~ " = true;");
return config; return config;
} }
enum Check: string
{
disabled = "disabled",
enabled = "enabled",
skipTests = "skip-unittest"
}
void fillConfig(string check)(ref StaticAnalysisConfig config)
{
foreach (mem; __traits(allMembers, StaticAnalysisConfig))
{
static if (is(typeof(__traits(getMember, StaticAnalysisConfig, mem))))
static if (is(typeof(__traits(getMember, config, mem)) == string))
__traits(getMember, config, mem) = check;
}
}
unittest
{
StaticAnalysisConfig c;
c.fillConfig!(Check.enabled);
assert(c.enum_array_literal_check == Check.enabled);
fillConfig!(Check.skipTests)(c);
assert(c.alias_syntax_check == Check.skipTests);
}
@INI("Configure which static analysis checks are enabled") @INI("Configure which static analysis checks are enabled")
struct StaticAnalysisConfig struct StaticAnalysisConfig
{ {
@INI("Check variable, class, struct, interface, union, and function names against the Phobos style guide") @INI("Check variable, class, struct, interface, union, and function names against the Phobos style guide")
bool style_check; string style_check = Check.disabled;
@INI("Check for array literals that cause unnecessary allocation") @INI("Check for array literals that cause unnecessary allocation")
bool enum_array_literal_check; string enum_array_literal_check = Check.disabled;
@INI("Check for poor exception handling practices") @INI("Check for poor exception handling practices")
bool exception_check; string exception_check = Check.disabled;
@INI("Check for use of the deprecated 'delete' keyword") @INI("Check for use of the deprecated 'delete' keyword")
bool delete_check; string delete_check = Check.disabled;
@INI("Check for use of the deprecated floating point operators") @INI("Check for use of the deprecated floating point operators")
bool float_operator_check; string float_operator_check = Check.disabled;
@INI("Check number literals for readability") @INI("Check number literals for readability")
bool number_style_check; string number_style_check = Check.disabled;
@INI("Checks that opEquals, opCmp, toHash, and toString are either const, immutable, or inout.") @INI("Checks that opEquals, opCmp, toHash, and toString are either const, immutable, or inout.")
bool object_const_check; string object_const_check = Check.disabled;
@INI("Checks for .. expressions where the left side is larger than the right.") @INI("Checks for .. expressions where the left side is larger than the right.")
bool backwards_range_check; string backwards_range_check = Check.disabled;
@INI("Checks for if statements whose 'then' block is the same as the 'else' block") @INI("Checks for if statements whose 'then' block is the same as the 'else' block")
bool if_else_same_check; string if_else_same_check = Check.disabled;
@INI("Checks for some problems with constructors") @INI("Checks for some problems with constructors")
bool constructor_check; string constructor_check = Check.disabled;
@INI("Checks for unused variables and function parameters") @INI("Checks for unused variables and function parameters")
bool unused_variable_check; string unused_variable_check = Check.disabled;
@INI("Checks for unused labels") @INI("Checks for unused labels")
bool unused_label_check; string unused_label_check = Check.disabled;
@INI("Checks for duplicate attributes") @INI("Checks for duplicate attributes")
bool duplicate_attribute; string duplicate_attribute = Check.disabled;
@INI("Checks that opEquals and toHash are both defined or neither are defined") @INI("Checks that opEquals and toHash are both defined or neither are defined")
bool opequals_tohash_check; string opequals_tohash_check = Check.disabled;
@INI("Checks for subtraction from .length properties") @INI("Checks for subtraction from .length properties")
bool length_subtraction_check; string length_subtraction_check = Check.disabled;
@INI("Checks for methods or properties whose names conflict with built-in properties") @INI("Checks for methods or properties whose names conflict with built-in properties")
bool builtin_property_names_check; string builtin_property_names_check = Check.disabled;
@INI("Checks for confusing code in inline asm statements") @INI("Checks for confusing code in inline asm statements")
bool asm_style_check; string asm_style_check = Check.disabled;
@INI("Checks for confusing logical operator precedence") @INI("Checks for confusing logical operator precedence")
bool logical_precedence_check; string logical_precedence_check = Check.disabled;
@INI("Checks for undocumented public declarations") @INI("Checks for undocumented public declarations")
bool undocumented_declaration_check; string undocumented_declaration_check = Check.disabled;
@INI("Checks for poor placement of function attributes") @INI("Checks for poor placement of function attributes")
bool function_attribute_check; string function_attribute_check = Check.disabled;
@INI("Checks for use of the comma operator") @INI("Checks for use of the comma operator")
bool comma_expression_check; string comma_expression_check = Check.disabled;
@INI("Checks for local imports that are too broad") @INI("Checks for local imports that are too broad")
bool local_import_check; string local_import_check = Check.disabled;
@INI("Checks for variables that could be declared immutable") @INI("Checks for variables that could be declared immutable")
bool could_be_immutable_check = false; // disabled by default for now string could_be_immutable_check = Check.disabled; // disabled by default for now
@INI("Checks for redundant expressions in if statements") @INI("Checks for redundant expressions in if statements")
bool redundant_if_check; string redundant_if_check = Check.disabled;
@INI("Checks for redundant parenthesis") @INI("Checks for redundant parenthesis")
bool redundant_parens_check; string redundant_parens_check = Check.disabled;
@INI("Checks for mismatched argument and parameter names") @INI("Checks for mismatched argument and parameter names")
bool mismatched_args_check; string mismatched_args_check = Check.disabled;
@INI("Checks for labels with the same name as variables") @INI("Checks for labels with the same name as variables")
bool label_var_same_name_check; string label_var_same_name_check = Check.disabled;
@INI("Checks for lines longer than 120 characters") @INI("Checks for lines longer than 120 characters")
bool long_line_check; string long_line_check = Check.disabled;
@INI("Checks for assignment to auto-ref function parameters") @INI("Checks for assignment to auto-ref function parameters")
bool auto_ref_assignment_check; string auto_ref_assignment_check = Check.disabled;
@INI("Checks for incorrect infinite range definitions") @INI("Checks for incorrect infinite range definitions")
bool incorrect_infinite_range_check; string incorrect_infinite_range_check = Check.disabled;
@INI("Checks for asserts that are always true") @INI("Checks for asserts that are always true")
bool useless_assert_check; string useless_assert_check = Check.disabled;
@INI("Check for uses of the old-style alias syntax") @INI("Check for uses of the old-style alias syntax")
bool alias_syntax_check; string alias_syntax_check = Check.disabled;
@INI("Checks for else if that should be else static if") @INI("Checks for else if that should be else static if")
bool static_if_else_check; string static_if_else_check = Check.disabled;
@INI("Check for unclear lambda syntax") @INI("Check for unclear lambda syntax")
bool lambda_return_check; string lambda_return_check = Check.disabled;
} }

View File

@ -11,9 +11,9 @@ class ConstructorCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const ClassDeclaration classDeclaration) override void visit(const ClassDeclaration classDeclaration)
@ -90,10 +90,10 @@ private:
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.constructor_check = true; sac.constructor_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
class Cat // [warn]: This class has a zero-argument constructor as well as a constructor with one default argument. This can be confusing. class Cat // [warn]: This class has a zero-argument constructor as well as a constructor with one default argument. This can be confusing.
{ {

View File

@ -18,9 +18,9 @@ class DeleteCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const DeleteExpression d) override void visit(const DeleteExpression d)
@ -33,11 +33,11 @@ class DeleteCheck : BaseAnalyzer
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
import analysis.helpers : assertAnalyzerWarnings; import analysis.helpers : assertAnalyzerWarnings;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.delete_check = true; sac.delete_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
void testDelete() void testDelete()
{ {

View File

@ -21,9 +21,9 @@ class DuplicateAttributeCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const Declaration node) override void visit(const Declaration node)
@ -153,10 +153,10 @@ class DuplicateAttributeCheck : BaseAnalyzer
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.duplicate_attribute = true; sac.duplicate_attribute = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
class ExampleAttributes class ExampleAttributes
{ {

View File

@ -19,9 +19,9 @@ class EnumArrayLiteralCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
bool looking = false; bool looking = false;

View File

@ -21,9 +21,9 @@ class FloatOperatorCheck : BaseAnalyzer
enum string KEY = "dscanner.deprecated.floating_point_operators"; enum string KEY = "dscanner.deprecated.floating_point_operators";
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const RelExpression r) override void visit(const RelExpression r)
@ -42,10 +42,10 @@ class FloatOperatorCheck : BaseAnalyzer
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.float_operator_check = true; sac.float_operator_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
void testFish() void testFish()
{ {

View File

@ -25,9 +25,9 @@ class FunctionAttributeCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const InterfaceDeclaration dec) override void visit(const InterfaceDeclaration dec)

View File

@ -13,9 +13,9 @@ import dsymbol.scope_ : Scope;
class IfStatementCheck : BaseAnalyzer class IfStatementCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const IfStatement ifStatement) override void visit(const IfStatement ifStatement)

View File

@ -24,9 +24,9 @@ class IfElseSameCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const IfStatement ifStatement) override void visit(const IfStatement ifStatement)
@ -77,10 +77,10 @@ class IfElseSameCheck : BaseAnalyzer
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.if_else_same_check = true; sac.if_else_same_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
void testSizeT() void testSizeT()
{ {

View File

@ -18,9 +18,9 @@ class IncorrectInfiniteRangeCheck : BaseAnalyzer
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
/// ///
this(string fileName) this(string fileName, bool skipTests = false)
{ {
super(fileName, null); super(fileName, null, skipTests);
} }
override void visit(const StructBody structBody) override void visit(const StructBody structBody)
@ -88,11 +88,11 @@ private:
unittest unittest
{ {
import std.stdio : stderr; import std.stdio : stderr;
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
import std.format : format; import std.format : format;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.incorrect_infinite_range_check = true; sac.incorrect_infinite_range_check = Check.enabled;
assertAnalyzerWarnings(q{struct InfiniteRange assertAnalyzerWarnings(q{struct InfiniteRange
{ {
bool empty() // [warn]: %1$s bool empty() // [warn]: %1$s

View File

@ -15,9 +15,9 @@ import analysis.helpers;
*/ */
class LabelVarNameCheck : BaseAnalyzer class LabelVarNameCheck : BaseAnalyzer
{ {
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
mixin ScopedVisit!Module; mixin ScopedVisit!Module;
@ -118,11 +118,11 @@ private:
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
import std.stdio : stderr; import std.stdio : stderr;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.label_var_same_name_check = true; sac.label_var_same_name_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
unittest unittest
{ {

View File

@ -13,9 +13,9 @@ class LambdaReturnCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName) this(string fileName, bool skipTests = false)
{ {
super(fileName, null); super(fileName, null, skipTests);
} }
override void visit(const FunctionLiteralExpression fLit) override void visit(const FunctionLiteralExpression fLit)
@ -47,11 +47,11 @@ private:
unittest unittest
{ {
import analysis.helpers : assertAnalyzerWarnings; import analysis.helpers : assertAnalyzerWarnings;
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
import std.stdio : stderr; import std.stdio : stderr;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.lambda_return_check = true; sac.lambda_return_check = Check.enabled;
auto code = ` auto code = `
void main() void main()

View File

@ -20,9 +20,9 @@ class LengthSubtractionCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const AddExpression addExpression) override void visit(const AddExpression addExpression)
@ -58,10 +58,10 @@ class LengthSubtractionCheck : BaseAnalyzer
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.length_subtraction_check = true; sac.length_subtraction_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
void testSizeT() void testSizeT()
{ {

View File

@ -15,9 +15,9 @@ import analysis.base : BaseAnalyzer;
class LineLengthCheck : BaseAnalyzer class LineLengthCheck : BaseAnalyzer
{ {
/// ///
this(string fileName, const(Token)[] tokens) this(string fileName, const(Token)[] tokens, bool skipTests = false)
{ {
super(fileName, null); super(fileName, null, skipTests);
this.tokens = tokens; this.tokens = tokens;
} }

View File

@ -23,9 +23,9 @@ class LocalImportCheck : BaseAnalyzer
/** /**
* Construct with the given file name. * Construct with the given file name.
*/ */
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
mixin visitThing!StructBody; mixin visitThing!StructBody;
@ -84,10 +84,10 @@ private:
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.local_import_check = true; sac.local_import_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
void testLocalImport() void testLocalImport()
{ {

View File

@ -25,9 +25,9 @@ class LogicPrecedenceCheck : BaseAnalyzer
enum string KEY = "dscanner.confusing.logical_precedence"; enum string KEY = "dscanner.confusing.logical_precedence";
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const OrOrExpression orOr) override void visit(const OrOrExpression orOr)
@ -48,10 +48,10 @@ class LogicPrecedenceCheck : BaseAnalyzer
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.logical_precedence_check = true; sac.logical_precedence_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
void testFish() void testFish()
{ {

View File

@ -11,9 +11,9 @@ import dsymbol.builtin.names;
final class MismatchedArgumentCheck : BaseAnalyzer final class MismatchedArgumentCheck : BaseAnalyzer
{ {
/// ///
this(string fileName, const Scope* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const FunctionCallExpression fce) override void visit(const FunctionCallExpression fce)

View File

@ -24,9 +24,9 @@ public:
/** /**
* Constructs the style checker with the given file name. * Constructs the style checker with the given file name.
*/ */
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const Token t) override void visit(const Token t)
@ -49,10 +49,10 @@ private:
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.number_style_check = true; sac.number_style_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
void testNumbers() void testNumbers()
{ {

View File

@ -21,9 +21,9 @@ class ObjectConstCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
mixin visitTemplate!ClassDeclaration; mixin visitTemplate!ClassDeclaration;
@ -71,10 +71,10 @@ class ObjectConstCheck : BaseAnalyzer
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.object_const_check = true; sac.object_const_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
void testConsts() void testConsts()
{ {

View File

@ -20,9 +20,9 @@ class OpEqualsWithoutToHashCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const ClassDeclaration node) override void visit(const ClassDeclaration node)
@ -89,10 +89,10 @@ class OpEqualsWithoutToHashCheck : BaseAnalyzer
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.opequals_tohash_check = true; sac.opequals_tohash_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
// Success because it has opEquals and toHash // Success because it has opEquals and toHash
class Chimp class Chimp

View File

@ -30,9 +30,9 @@ class PokemonExceptionCheck : BaseAnalyzer
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const LastCatch lc) override void visit(const LastCatch lc)
@ -85,10 +85,10 @@ class PokemonExceptionCheck : BaseAnalyzer
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.exception_check = true; sac.exception_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
void testCatch() void testCatch()
{ {

View File

@ -27,9 +27,9 @@ class BackwardsRangeCheck : BaseAnalyzer
* Params: * Params:
* fileName = the name of the file being analyzed * fileName = the name of the file being analyzed
*/ */
this(string fileName, const(Scope)* sc) this(string fileName, const Scope* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const ForeachStatement foreachStatement) override void visit(const ForeachStatement foreachStatement)
@ -157,10 +157,10 @@ private:
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.backwards_range_check = true; sac.backwards_range_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
void testRange() void testRange()
{ {

View File

@ -18,9 +18,9 @@ class RedundantParenCheck : BaseAnalyzer
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
/// ///
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const IfStatement statement) override void visit(const IfStatement statement)

View File

@ -205,6 +205,8 @@ MessageSet analyze(string fileName, const Module m, const StaticAnalysisConfig a
return null; return null;
auto symbolAllocator = scoped!ASTAllocator(); auto symbolAllocator = scoped!ASTAllocator();
version (unittest) enum ut = true; else enum ut = false;
auto first = scoped!FirstPass(m, internString(fileName), symbolAllocator, auto first = scoped!FirstPass(m, internString(fileName), symbolAllocator,
symbolAllocator, true, &moduleCache, null); symbolAllocator, true, &moduleCache, null);
first.run(); first.run();
@ -216,75 +218,142 @@ MessageSet analyze(string fileName, const Module m, const StaticAnalysisConfig a
scope(exit) typeid(Scope).destroy(first.moduleScope); scope(exit) typeid(Scope).destroy(first.moduleScope);
BaseAnalyzer[] checks; BaseAnalyzer[] checks;
if (analysisConfig.asm_style_check) if (analysisConfig.asm_style_check != Check.disabled)
checks ~= new AsmStyleCheck(fileName, moduleScope); checks ~= new AsmStyleCheck(fileName, moduleScope,
if (analysisConfig.backwards_range_check) analysisConfig.asm_style_check == Check.skipTests && !ut);
checks ~= new BackwardsRangeCheck(fileName, moduleScope);
if (analysisConfig.builtin_property_names_check) if (analysisConfig.backwards_range_check != Check.disabled)
checks ~= new BuiltinPropertyNameCheck(fileName, moduleScope); checks ~= new BackwardsRangeCheck(fileName, moduleScope,
if (analysisConfig.comma_expression_check) analysisConfig.backwards_range_check == Check.skipTests && !ut);
checks ~= new CommaExpressionCheck(fileName, moduleScope);
if (analysisConfig.constructor_check) if (analysisConfig.builtin_property_names_check != Check.disabled)
checks ~= new ConstructorCheck(fileName, moduleScope); checks ~= new BuiltinPropertyNameCheck(fileName, moduleScope,
if (analysisConfig.could_be_immutable_check) analysisConfig.builtin_property_names_check == Check.skipTests && !ut);
checks ~= new UnmodifiedFinder(fileName, moduleScope);
if (analysisConfig.delete_check) if (analysisConfig.comma_expression_check != Check.disabled)
checks ~= new DeleteCheck(fileName, moduleScope); checks ~= new CommaExpressionCheck(fileName, moduleScope,
if (analysisConfig.duplicate_attribute) analysisConfig.comma_expression_check == Check.skipTests && !ut);
checks ~= new DuplicateAttributeCheck(fileName, moduleScope);
if (analysisConfig.enum_array_literal_check) if (analysisConfig.constructor_check != Check.disabled)
checks ~= new EnumArrayLiteralCheck(fileName, moduleScope); checks ~= new ConstructorCheck(fileName, moduleScope,
if (analysisConfig.exception_check) analysisConfig.constructor_check == Check.skipTests && !ut);
checks ~= new PokemonExceptionCheck(fileName, moduleScope);
if (analysisConfig.float_operator_check) if (analysisConfig.could_be_immutable_check != Check.disabled)
checks ~= new FloatOperatorCheck(fileName, moduleScope); checks ~= new UnmodifiedFinder(fileName, moduleScope,
if (analysisConfig.function_attribute_check) analysisConfig.could_be_immutable_check == Check.skipTests && !ut);
checks ~= new FunctionAttributeCheck(fileName, moduleScope);
if (analysisConfig.if_else_same_check) if (analysisConfig.delete_check != Check.disabled)
checks ~= new IfElseSameCheck(fileName, moduleScope); checks ~= new DeleteCheck(fileName, moduleScope,
if (analysisConfig.label_var_same_name_check) analysisConfig.delete_check == Check.skipTests && !ut);
checks ~= new LabelVarNameCheck(fileName, moduleScope);
if (analysisConfig.length_subtraction_check) if (analysisConfig.duplicate_attribute != Check.disabled)
checks ~= new LengthSubtractionCheck(fileName, moduleScope); checks ~= new DuplicateAttributeCheck(fileName, moduleScope,
if (analysisConfig.local_import_check) analysisConfig.duplicate_attribute == Check.skipTests && !ut);
checks ~= new LocalImportCheck(fileName, moduleScope);
if (analysisConfig.logical_precedence_check) if (analysisConfig.enum_array_literal_check != Check.disabled)
checks ~= new LogicPrecedenceCheck(fileName, moduleScope); checks ~= new EnumArrayLiteralCheck(fileName, moduleScope,
if (analysisConfig.mismatched_args_check) analysisConfig.enum_array_literal_check == Check.skipTests && !ut);
checks ~= new MismatchedArgumentCheck(fileName, moduleScope);
if (analysisConfig.number_style_check) if (analysisConfig.exception_check != Check.disabled)
checks ~= new NumberStyleCheck(fileName, moduleScope); checks ~= new PokemonExceptionCheck(fileName, moduleScope,
if (analysisConfig.object_const_check) analysisConfig.exception_check == Check.skipTests && !ut);
checks ~= new ObjectConstCheck(fileName, moduleScope);
if (analysisConfig.opequals_tohash_check) if (analysisConfig.float_operator_check != Check.disabled)
checks ~= new OpEqualsWithoutToHashCheck(fileName, moduleScope); checks ~= new FloatOperatorCheck(fileName, moduleScope,
if (analysisConfig.redundant_parens_check) analysisConfig.float_operator_check == Check.skipTests && !ut);
checks ~= new RedundantParenCheck(fileName, moduleScope);
if (analysisConfig.style_check) if (analysisConfig.function_attribute_check != Check.disabled)
checks ~= new StyleChecker(fileName, moduleScope); checks ~= new FunctionAttributeCheck(fileName, moduleScope,
if (analysisConfig.undocumented_declaration_check) analysisConfig.function_attribute_check == Check.skipTests && !ut);
checks ~= new UndocumentedDeclarationCheck(fileName, moduleScope);
if (analysisConfig.unused_label_check) if (analysisConfig.if_else_same_check != Check.disabled)
checks ~= new UnusedLabelCheck(fileName, moduleScope); checks ~= new IfElseSameCheck(fileName, moduleScope,
if (analysisConfig.unused_variable_check) analysisConfig.if_else_same_check == Check.skipTests&& !ut);
checks ~= new UnusedVariableCheck(fileName, moduleScope);
if (analysisConfig.long_line_check) if (analysisConfig.label_var_same_name_check != Check.disabled)
checks ~= new LineLengthCheck(fileName, tokens); checks ~= new LabelVarNameCheck(fileName, moduleScope,
if (analysisConfig.auto_ref_assignment_check) analysisConfig.label_var_same_name_check == Check.skipTests && !ut);
checks ~= new AutoRefAssignmentCheck(fileName);
if (analysisConfig.incorrect_infinite_range_check) if (analysisConfig.length_subtraction_check != Check.disabled)
checks ~= new IncorrectInfiniteRangeCheck(fileName); checks ~= new LengthSubtractionCheck(fileName, moduleScope,
if (analysisConfig.useless_assert_check) analysisConfig.length_subtraction_check == Check.skipTests && !ut);
checks ~= new UselessAssertCheck(fileName);
if (analysisConfig.alias_syntax_check) if (analysisConfig.local_import_check != Check.disabled)
checks ~= new AliasSyntaxCheck(fileName); checks ~= new LocalImportCheck(fileName, moduleScope,
if (analysisConfig.static_if_else_check) analysisConfig.local_import_check == Check.skipTests && !ut);
checks ~= new StaticIfElse(fileName);
if (analysisConfig.lambda_return_check) if (analysisConfig.logical_precedence_check != Check.disabled)
checks ~= new LambdaReturnCheck(fileName); checks ~= new LogicPrecedenceCheck(fileName, moduleScope,
analysisConfig.logical_precedence_check == Check.skipTests && !ut);
if (analysisConfig.mismatched_args_check != Check.disabled)
checks ~= new MismatchedArgumentCheck(fileName, moduleScope,
analysisConfig.mismatched_args_check == Check.skipTests && !ut);
if (analysisConfig.number_style_check != Check.disabled)
checks ~= new NumberStyleCheck(fileName, moduleScope,
analysisConfig.number_style_check == Check.skipTests && !ut);
if (analysisConfig.object_const_check != Check.disabled)
checks ~= new ObjectConstCheck(fileName, moduleScope,
analysisConfig.object_const_check == Check.skipTests && !ut);
if (analysisConfig.opequals_tohash_check != Check.disabled)
checks ~= new OpEqualsWithoutToHashCheck(fileName, moduleScope,
analysisConfig.opequals_tohash_check == Check.skipTests && !ut);
if (analysisConfig.redundant_parens_check != Check.disabled)
checks ~= new RedundantParenCheck(fileName, moduleScope,
analysisConfig.redundant_parens_check == Check.skipTests && !ut);
if (analysisConfig.style_check != Check.disabled)
checks ~= new StyleChecker(fileName, moduleScope,
analysisConfig.style_check == Check.skipTests && !ut);
if (analysisConfig.undocumented_declaration_check != Check.disabled)
checks ~= new UndocumentedDeclarationCheck(fileName, moduleScope,
analysisConfig.undocumented_declaration_check == Check.skipTests && !ut);
if (analysisConfig.unused_label_check != Check.disabled)
checks ~= new UnusedLabelCheck(fileName, moduleScope,
analysisConfig.unused_label_check == Check.skipTests && !ut);
if (analysisConfig.unused_variable_check != Check.disabled)
checks ~= new UnusedVariableCheck(fileName, moduleScope,
analysisConfig.unused_variable_check == Check.skipTests && !ut);
if (analysisConfig.long_line_check != Check.disabled)
checks ~= new LineLengthCheck(fileName, tokens,
analysisConfig.long_line_check == Check.skipTests && !ut);
if (analysisConfig.auto_ref_assignment_check != Check.disabled)
checks ~= new AutoRefAssignmentCheck(fileName,
analysisConfig.auto_ref_assignment_check == Check.skipTests && !ut);
if (analysisConfig.incorrect_infinite_range_check != Check.disabled)
checks ~= new IncorrectInfiniteRangeCheck(fileName,
analysisConfig.incorrect_infinite_range_check == Check.skipTests && !ut);
if (analysisConfig.useless_assert_check != Check.disabled)
checks ~= new UselessAssertCheck(fileName,
analysisConfig.useless_assert_check == Check.skipTests && !ut);
if (analysisConfig.alias_syntax_check != Check.disabled)
checks ~= new AliasSyntaxCheck(fileName,
analysisConfig.alias_syntax_check == Check.skipTests && !ut);
if (analysisConfig.static_if_else_check != Check.disabled)
checks ~= new StaticIfElse(fileName,
analysisConfig.static_if_else_check == Check.skipTests && !ut);
if (analysisConfig.lambda_return_check != Check.disabled)
checks ~= new LambdaReturnCheck(fileName,
analysisConfig.lambda_return_check == Check.skipTests && !ut);
version (none) version (none)
if (analysisConfig.redundant_if_check) if (analysisConfig.redundant_if_check != Check.disabled)
checks ~= new IfStatementCheck(fileName, moduleScope); checks ~= new IfStatementCheck(fileName, moduleScope,
analysisConfig.redundant_if_check == Check.skipTests && !ut);
foreach (check; checks) foreach (check; checks)
{ {
@ -297,3 +366,4 @@ MessageSet analyze(string fileName, const Module m, const StaticAnalysisConfig a
set.insert(message); set.insert(message);
return set; return set;
} }

View File

@ -25,9 +25,9 @@ class StaticIfElse : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string filename) this(string fileName, bool skipTests = false)
{ {
super(filename, null); super(fileName, null, skipTests);
} }
override void visit(const ConditionalStatement cc) override void visit(const ConditionalStatement cc)
@ -66,11 +66,11 @@ class StaticIfElse : BaseAnalyzer
unittest unittest
{ {
import analysis.helpers : assertAnalyzerWarnings; import analysis.helpers : assertAnalyzerWarnings;
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
import std.stdio : stderr; import std.stdio : stderr;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.static_if_else_check = true; sac.static_if_else_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
void foo() { void foo() {
static if (false) static if (false)

View File

@ -25,9 +25,9 @@ class StyleChecker : BaseAnalyzer
enum string moduleNameRegex = `^[\p{Ll}_\d]+$`; enum string moduleNameRegex = `^[\p{Ll}_\d]+$`;
enum string KEY = "dscanner.style.phobos_naming_convention"; enum string KEY = "dscanner.style.phobos_naming_convention";
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const ModuleDeclaration dec) override void visit(const ModuleDeclaration dec)
@ -93,10 +93,10 @@ class StyleChecker : BaseAnalyzer
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.style_check = true; sac.style_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
module AMODULE; // [warn]: Module/package name 'AMODULE' does not match style guidelines. module AMODULE; // [warn]: Module/package name 'AMODULE' does not match style guidelines.

View File

@ -21,9 +21,9 @@ class UndocumentedDeclarationCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const Module mod) override void visit(const Module mod)

View File

@ -18,9 +18,9 @@ class UnmodifiedFinder : BaseAnalyzer
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
/// ///
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const Module mod) override void visit(const Module mod)

View File

@ -22,9 +22,9 @@ class UnusedVariableCheck : BaseAnalyzer
* Params: * Params:
* fileName = the name of the file being analyzed * fileName = the name of the file being analyzed
*/ */
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
re = regex("[\\p{Alphabetic}_][\\w_]*"); re = regex("[\\p{Alphabetic}_][\\w_]*");
} }
@ -410,11 +410,11 @@ private:
unittest unittest
{ {
import std.stdio : stderr; import std.stdio : stderr;
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
import analysis.helpers : assertAnalyzerWarnings; import analysis.helpers : assertAnalyzerWarnings;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.unused_variable_check = true; sac.unused_variable_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
// Issue 274 // Issue 274

View File

@ -14,9 +14,9 @@ class UnusedLabelCheck : BaseAnalyzer
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
this(string fileName, const(Scope)* sc) this(string fileName, const(Scope)* sc, bool skipTests = false)
{ {
super(fileName, sc); super(fileName, sc, skipTests);
} }
override void visit(const Module mod) override void visit(const Module mod)
@ -137,11 +137,11 @@ private:
unittest unittest
{ {
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
import std.stdio : stderr; import std.stdio : stderr;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.unused_label_check = true; sac.unused_label_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
int testUnusedLabel() int testUnusedLabel()
{ {

View File

@ -20,9 +20,10 @@ class UselessAssertCheck : BaseAnalyzer
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzer.visit;
/// ///
this(string fileName) this(string fileName, bool skipTests = false)
{ {
super(fileName, null); // assertions likely to be in unittest so never skip
super(fileName, null, false);
} }
override void visit(const AssertExpression ae) override void visit(const AssertExpression ae)
@ -96,11 +97,11 @@ private:
unittest unittest
{ {
import std.stdio : stderr; import std.stdio : stderr;
import analysis.config : StaticAnalysisConfig; import analysis.config : StaticAnalysisConfig, Check;
import std.format : format; import std.format : format;
StaticAnalysisConfig sac; StaticAnalysisConfig sac;
sac.useless_assert_check = true; sac.useless_assert_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
unittest unittest
{ {

View File

@ -59,6 +59,7 @@ else
bool styleCheck; bool styleCheck;
bool defaultConfig; bool defaultConfig;
bool report; bool report;
bool skipTests;
string symbolName; string symbolName;
string configLocation; string configLocation;
string[] importPaths; string[] importPaths;
@ -89,7 +90,8 @@ else
"I", &importPaths, "I", &importPaths,
"version", &printVersion, "version", &printVersion,
"muffinButton", &muffin, "muffinButton", &muffin,
"explore", &explore); "explore", &explore,
"skipTests", &skipTests);
//dfmt on //dfmt on
} }
catch (ConvException e) catch (ConvException e)
@ -218,6 +220,8 @@ else
string s = configLocation is null ? getConfigurationLocation() : configLocation; string s = configLocation is null ? getConfigurationLocation() : configLocation;
if (s.exists()) if (s.exists())
readINIFile(config, s); readINIFile(config, s);
if (skipTests)
config.fillConfig!(Check.skipTests);
if (report) if (report)
generateReport(expandArgs(args), config, cache, moduleCache); generateReport(expandArgs(args), config, cache, moduleCache);
else else
@ -368,7 +372,7 @@ Options:
If no files are specified, input is read from stdin. %1$s will exit with If no files are specified, input is read from stdin. %1$s will exit with
a status code of zero if no errors are found, 1 otherwise. a status code of zero if no errors are found, 1 otherwise.
--styleCheck <file | directory>..., <file | directory>... --styleCheck|S <file | directory>..., <file | directory>...
Lexes and parses sourceFiles, printing the line and column number of any Lexes and parses sourceFiles, printing the line and column number of any
static analysis check failures stdout. %1$s will exit with a status code static analysis check failures stdout. %1$s will exit with a status code
of zero if no warnings or errors are found, 1 otherwise. of zero if no warnings or errors are found, 1 otherwise.
@ -406,7 +410,11 @@ Options:
$HOME/.config/dscanner/dscanner.ini $HOME/.config/dscanner/dscanner.ini
--defaultConfig --defaultConfig
Generates a default configuration file for the static analysis checks`, Generates a default configuration file for the static analysis checks,
--skipTests
Does not analyze in the unittests. Only works if --styleCheck.`,
programName); programName);
} }