Track check name for error messages (#769)
* Track check name for error messages * Assert BaseAnalyzer.getName() is implemented
This commit is contained in:
parent
94d102a5f6
commit
3b9d608866
|
@ -16,6 +16,8 @@ final class AliasSyntaxCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"alias_syntax_check";
|
||||||
|
|
||||||
this(string fileName, bool skipTests = false)
|
this(string fileName, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, null, skipTests);
|
super(fileName, null, skipTests);
|
||||||
|
|
|
@ -6,7 +6,7 @@ module dscanner.analysis.allman;
|
||||||
|
|
||||||
import dparse.lexer;
|
import dparse.lexer;
|
||||||
import dparse.ast;
|
import dparse.ast;
|
||||||
import dscanner.analysis.base : BaseAnalyzer;
|
import dscanner.analysis.base;
|
||||||
import dsymbol.scope_ : Scope;
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
import std.algorithm;
|
import std.algorithm;
|
||||||
|
@ -27,6 +27,8 @@ if (param < 0)
|
||||||
*/
|
*/
|
||||||
final class AllManCheck : BaseAnalyzer
|
final class AllManCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
|
mixin AnalyzerInfo!"allman_braces_check";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, const(Token)[] tokens, bool skipTests = false)
|
this(string fileName, const(Token)[] tokens, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,8 @@ final class AsmStyleCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"asm_style_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
module dscanner.analysis.assert_without_msg;
|
module dscanner.analysis.assert_without_msg;
|
||||||
|
|
||||||
import dscanner.analysis.base : BaseAnalyzer;
|
import dscanner.analysis.base;
|
||||||
import dscanner.utils : safeAccess;
|
import dscanner.utils : safeAccess;
|
||||||
import dsymbol.scope_ : Scope;
|
import dsymbol.scope_ : Scope;
|
||||||
import dparse.lexer;
|
import dparse.lexer;
|
||||||
|
@ -20,6 +20,7 @@ final class AssertWithoutMessageCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
enum string KEY = "dscanner.style.assert_without_msg";
|
enum string KEY = "dscanner.style.assert_without_msg";
|
||||||
enum string MESSAGE = "An assert should have an explanatory message";
|
enum string MESSAGE = "An assert should have an explanatory message";
|
||||||
|
mixin AnalyzerInfo!"assert_without_msg";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
|
|
|
@ -36,6 +36,8 @@ public:
|
||||||
|
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"auto_function_check";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, bool skipTests = false)
|
this(string fileName, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,6 +14,8 @@ import dscanner.analysis.base;
|
||||||
*/
|
*/
|
||||||
final class AutoRefAssignmentCheck : BaseAnalyzer
|
final class AutoRefAssignmentCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
|
mixin AnalyzerInfo!"auto_ref_assignment_check";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, bool skipTests = false)
|
this(string fileName, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,12 +18,24 @@ struct Message
|
||||||
string key;
|
string key;
|
||||||
/// Warning message
|
/// Warning message
|
||||||
string message;
|
string message;
|
||||||
|
/// Check name
|
||||||
|
string checkName;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum comparitor = q{ a.line < b.line || (a.line == b.line && a.column < b.column) };
|
enum comparitor = q{ a.line < b.line || (a.line == b.line && a.column < b.column) };
|
||||||
|
|
||||||
alias MessageSet = RedBlackTree!(Message, comparitor, true);
|
alias MessageSet = RedBlackTree!(Message, comparitor, true);
|
||||||
|
|
||||||
|
mixin template AnalyzerInfo(string checkName)
|
||||||
|
{
|
||||||
|
enum string name = checkName;
|
||||||
|
|
||||||
|
override protected string getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class BaseAnalyzer : ASTVisitor
|
abstract class BaseAnalyzer : ASTVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -35,6 +47,11 @@ public:
|
||||||
_messages = new MessageSet;
|
_messages = new MessageSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected string getName()
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
Message[] messages()
|
Message[] messages()
|
||||||
{
|
{
|
||||||
return _messages[].array;
|
return _messages[].array;
|
||||||
|
@ -71,7 +88,7 @@ protected:
|
||||||
|
|
||||||
void addErrorMessage(size_t line, size_t column, string key, string message)
|
void addErrorMessage(size_t line, size_t column, string key, string message)
|
||||||
{
|
{
|
||||||
_messages.insert(Message(fileName, line, column, key, message));
|
_messages.insert(Message(fileName, line, column, key, message, getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -31,6 +31,8 @@ final class BuiltinPropertyNameCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"builtin_property_names_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -17,6 +17,8 @@ final class CommaExpressionCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"comma_expression_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -11,6 +11,8 @@ final class ConstructorCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"constructor_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -18,6 +18,8 @@ final class DeleteCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"delete_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -21,6 +21,8 @@ final class DuplicateAttributeCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"duplicate_attribute";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -19,6 +19,8 @@ final class EnumArrayLiteralCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"enum_array_literal_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -6,7 +6,7 @@ module dscanner.analysis.explicitly_annotated_unittests;
|
||||||
|
|
||||||
import dparse.lexer;
|
import dparse.lexer;
|
||||||
import dparse.ast;
|
import dparse.ast;
|
||||||
import dscanner.analysis.base : BaseAnalyzer;
|
import dscanner.analysis.base;
|
||||||
|
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ final class ExplicitlyAnnotatedUnittestCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
enum string KEY = "dscanner.style.explicitly_annotated_unittest";
|
enum string KEY = "dscanner.style.explicitly_annotated_unittest";
|
||||||
enum string MESSAGE = "A unittest should be annotated with at least @safe or @system";
|
enum string MESSAGE = "A unittest should be annotated with at least @safe or @system";
|
||||||
|
mixin AnalyzerInfo!"explicitly_annotated_unittests";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, bool skipTests = false)
|
this(string fileName, bool skipTests = false)
|
||||||
|
|
|
@ -66,6 +66,8 @@ public:
|
||||||
|
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"final_attribute_check";
|
||||||
|
|
||||||
enum pushPopPrivate = q{
|
enum pushPopPrivate = q{
|
||||||
const bool wasPrivate = _private;
|
const bool wasPrivate = _private;
|
||||||
_private = false;
|
_private = false;
|
||||||
|
|
|
@ -20,6 +20,7 @@ final class FloatOperatorCheck : BaseAnalyzer
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
enum string KEY = "dscanner.deprecated.floating_point_operators";
|
enum string KEY = "dscanner.deprecated.floating_point_operators";
|
||||||
|
mixin AnalyzerInfo!"float_operator_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,6 +25,8 @@ final class FunctionAttributeCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"function_attribute_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -20,6 +20,8 @@ final class HasPublicExampleCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"has_public_example";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -6,7 +6,7 @@ module dscanner.analysis.if_constraints_indent;
|
||||||
|
|
||||||
import dparse.lexer;
|
import dparse.lexer;
|
||||||
import dparse.ast;
|
import dparse.ast;
|
||||||
import dscanner.analysis.base : BaseAnalyzer, Message;
|
import dscanner.analysis.base;
|
||||||
import dsymbol.scope_ : Scope;
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
import std.algorithm.iteration : filter;
|
import std.algorithm.iteration : filter;
|
||||||
|
@ -17,6 +17,8 @@ Checks whether all if constraints have the same indention as their declaration.
|
||||||
*/
|
*/
|
||||||
final class IfConstraintsIndentCheck : BaseAnalyzer
|
final class IfConstraintsIndentCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
|
mixin AnalyzerInfo!"if_constraints_indent";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, const(Token)[] tokens, bool skipTests = false)
|
this(string fileName, const(Token)[] tokens, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,6 +13,8 @@ import dsymbol.scope_ : Scope;
|
||||||
final class IfStatementCheck : BaseAnalyzer
|
final class IfStatementCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
mixin AnalyzerInfo!"redundant_if_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -24,6 +24,8 @@ final class IfElseSameCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"if_else_same_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
module dscanner.analysis.imports_sortedness;
|
module dscanner.analysis.imports_sortedness;
|
||||||
|
|
||||||
import dscanner.analysis.base : BaseAnalyzer;
|
import dscanner.analysis.base;
|
||||||
import dparse.lexer;
|
import dparse.lexer;
|
||||||
import dparse.ast;
|
import dparse.ast;
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ final class ImportSortednessCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
enum string KEY = "dscanner.style.imports_sortedness";
|
enum string KEY = "dscanner.style.imports_sortedness";
|
||||||
enum string MESSAGE = "The imports are not sorted in alphabetical order";
|
enum string MESSAGE = "The imports are not sorted in alphabetical order";
|
||||||
|
mixin AnalyzerInfo!"imports_sortedness";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, bool skipTests = false)
|
this(string fileName, bool skipTests = false)
|
||||||
|
|
|
@ -17,6 +17,8 @@ final class IncorrectInfiniteRangeCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"incorrect_infinite_range_check";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, bool skipTests = false)
|
this(string fileName, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,6 +15,8 @@ import dscanner.analysis.helpers;
|
||||||
*/
|
*/
|
||||||
final class LabelVarNameCheck : BaseAnalyzer
|
final class LabelVarNameCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
|
mixin AnalyzerInfo!"label_var_same_name_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -14,6 +14,8 @@ final class LambdaReturnCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"lambda_return_check";
|
||||||
|
|
||||||
this(string fileName, bool skipTests = false)
|
this(string fileName, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, null, skipTests);
|
super(fileName, null, skipTests);
|
||||||
|
|
|
@ -20,6 +20,8 @@ final class LengthSubtractionCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"length_subtraction_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
module dscanner.analysis.line_length;
|
module dscanner.analysis.line_length;
|
||||||
|
|
||||||
import dscanner.analysis.base : BaseAnalyzer;
|
import dscanner.analysis.base;
|
||||||
|
|
||||||
import dparse.ast;
|
import dparse.ast;
|
||||||
import dparse.lexer;
|
import dparse.lexer;
|
||||||
|
@ -17,6 +17,8 @@ import std.typecons : tuple, Tuple;
|
||||||
*/
|
*/
|
||||||
final class LineLengthCheck : BaseAnalyzer
|
final class LineLengthCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
|
mixin AnalyzerInfo!"long_line_check";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, const(Token)[] tokens, bool skipTests = false)
|
this(string fileName, const(Token)[] tokens, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,8 @@ final class LocalImportCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"local_import_check";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct with the given file name.
|
* Construct with the given file name.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -24,6 +24,7 @@ final class LogicPrecedenceCheck : BaseAnalyzer
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
enum string KEY = "dscanner.confusing.logical_precedence";
|
enum string KEY = "dscanner.confusing.logical_precedence";
|
||||||
|
mixin AnalyzerInfo!"logical_precedence_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module dscanner.analysis.mismatched_args;
|
module dscanner.analysis.mismatched_args;
|
||||||
|
|
||||||
import dscanner.analysis.base : BaseAnalyzer;
|
import dscanner.analysis.base;
|
||||||
import dscanner.utils : safeAccess;
|
import dscanner.utils : safeAccess;
|
||||||
import dsymbol.scope_;
|
import dsymbol.scope_;
|
||||||
import dsymbol.symbol;
|
import dsymbol.symbol;
|
||||||
|
@ -11,6 +11,8 @@ import dsymbol.builtin.names;
|
||||||
/// Checks for mismatched argument and parameter names
|
/// Checks for mismatched argument and parameter names
|
||||||
final class MismatchedArgumentCheck : BaseAnalyzer
|
final class MismatchedArgumentCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
|
mixin AnalyzerInfo!"mismatched_args_check";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,8 @@ final class NumberStyleCheck : BaseAnalyzer
|
||||||
public:
|
public:
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"number_style_check";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the style checker with the given file name.
|
* Constructs the style checker with the given file name.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -21,6 +21,8 @@ final class ObjectConstCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"object_const_check";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,8 @@ final class OpEqualsWithoutToHashCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"opequals_tohash_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -27,6 +27,7 @@ final class PokemonExceptionCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
enum MESSAGE = "Catching Error or Throwable is almost always a bad idea.";
|
enum MESSAGE = "Catching Error or Throwable is almost always a bad idea.";
|
||||||
enum string KEY = "dscanner.suspicious.catch_em_all";
|
enum string KEY = "dscanner.suspicious.catch_em_all";
|
||||||
|
mixin AnalyzerInfo!"exception_check";
|
||||||
|
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ module dscanner.analysis.properly_documented_public_functions;
|
||||||
import dparse.lexer;
|
import dparse.lexer;
|
||||||
import dparse.ast;
|
import dparse.ast;
|
||||||
import dparse.formatter : astFmt = format;
|
import dparse.formatter : astFmt = format;
|
||||||
import dscanner.analysis.base : BaseAnalyzer;
|
import dscanner.analysis.base;
|
||||||
import dscanner.utils : safeAccess;
|
import dscanner.utils : safeAccess;
|
||||||
|
|
||||||
import std.format : format;
|
import std.format : format;
|
||||||
|
@ -38,6 +38,8 @@ final class ProperlyDocumentedPublicFunctions : BaseAnalyzer
|
||||||
enum string MISSING_THROW_KEY = "dscanner.style.doc_missing_throw";
|
enum string MISSING_THROW_KEY = "dscanner.style.doc_missing_throw";
|
||||||
enum string MISSING_THROW_MESSAGE = "An instance of `%s` is thrown but not documented in the `Throws` section";
|
enum string MISSING_THROW_MESSAGE = "An instance of `%s` is thrown but not documented in the `Throws` section";
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"properly_documented_public_functions";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, bool skipTests = false)
|
this(string fileName, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,8 @@ final class BackwardsRangeCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"backwards_range_check";
|
||||||
|
|
||||||
/// Key for this check in the report output
|
/// Key for this check in the report output
|
||||||
enum string KEY = "dscanner.bugs.backwards_slices";
|
enum string KEY = "dscanner.bugs.backwards_slices";
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ import std.range : empty, front, walkLength;
|
||||||
*/
|
*/
|
||||||
final class RedundantAttributesCheck : BaseAnalyzer
|
final class RedundantAttributesCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
|
mixin AnalyzerInfo!"redundant_attributes_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -17,6 +17,8 @@ final class RedundantParenCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"redundant_parens_check";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,7 @@ final class RedundantStorageClassCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
enum string REDUNDANT_VARIABLE_ATTRIBUTES = "Variable declaration for `%s` has redundant attributes (%-(`%s`%|, %)).";
|
enum string REDUNDANT_VARIABLE_ATTRIBUTES = "Variable declaration for `%s` has redundant attributes (%-(`%s`%|, %)).";
|
||||||
|
mixin AnalyzerInfo!"redundant_storage_classes";
|
||||||
|
|
||||||
this(string fileName, bool skipTests = false)
|
this(string fileName, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -95,41 +95,45 @@ private alias ASTAllocator = CAllocatorImpl!(
|
||||||
|
|
||||||
immutable string defaultErrorFormat = "{filepath}({line}:{column})[{type}]: {message}";
|
immutable string defaultErrorFormat = "{filepath}({line}:{column})[{type}]: {message}";
|
||||||
|
|
||||||
void messageFunctionFormat(string format, string fileName, size_t line, size_t column, string message, bool isError)
|
void messageFunctionFormat(string format, Message message, bool isError)
|
||||||
{
|
{
|
||||||
auto s = format;
|
auto s = format;
|
||||||
|
|
||||||
s = s.replace("{filepath}", fileName);
|
s = s.replace("{filepath}", message.fileName);
|
||||||
s = s.replace("{line}", to!string(line));
|
s = s.replace("{line}", to!string(message.line));
|
||||||
s = s.replace("{column}", to!string(column));
|
s = s.replace("{column}", to!string(message.column));
|
||||||
s = s.replace("{type}", isError ? "error" : "warn");
|
s = s.replace("{type}", isError ? "error" : "warn");
|
||||||
s = s.replace("{message}", message);
|
s = s.replace("{message}", message.message);
|
||||||
|
|
||||||
writefln("%s", s);
|
writefln("%s", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void messageFunction(string fileName, size_t line, size_t column, string message, bool isError)
|
void messageFunction(Message message, bool isError)
|
||||||
{
|
{
|
||||||
messageFunctionFormat(defaultErrorFormat, fileName, line, column, message, isError);
|
messageFunctionFormat(defaultErrorFormat, message, isError);
|
||||||
}
|
}
|
||||||
|
|
||||||
void messageFunctionJSON(string fileName, size_t line, size_t column, string message, bool)
|
void messageFunctionJSON(string fileName, size_t line, size_t column, string message, bool)
|
||||||
{
|
{
|
||||||
writeJSON("dscanner.syntax", fileName, line, column, message);
|
writeJSON(Message(fileName, line, column, "dscanner.syntax", message));
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeJSON(string key, string fileName, size_t line, size_t column, string message)
|
void writeJSON(Message message)
|
||||||
{
|
{
|
||||||
if (!first)
|
if (!first)
|
||||||
writeln(",");
|
writeln(",");
|
||||||
else
|
else
|
||||||
first = false;
|
first = false;
|
||||||
writeln(" {");
|
writeln(" {");
|
||||||
writeln(` "key": "`, key, `",`);
|
writeln(` "key": "`, message.key, `",`);
|
||||||
writeln(` "fileName": "`, fileName.replace("\\", "\\\\").replace(`"`, `\"`), `",`);
|
if (message.checkName !is null)
|
||||||
writeln(` "line": `, line, `,`);
|
{
|
||||||
writeln(` "column": `, column, `,`);
|
writeln(` "name": "`, message.checkName, `",`);
|
||||||
writeln(` "message": "`, message.replace("\\", "\\\\").replace(`"`, `\"`), `"`);
|
}
|
||||||
|
writeln(` "fileName": "`, message.fileName.replace("\\", "\\\\").replace(`"`, `\"`), `",`);
|
||||||
|
writeln(` "line": `, message.line, `,`);
|
||||||
|
writeln(` "column": `, message.column, `,`);
|
||||||
|
writeln(` "message": "`, message.message.replace("\\", "\\\\").replace(`"`, `\"`), `"`);
|
||||||
write(" }");
|
write(" }");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +164,7 @@ void generateReport(string[] fileNames, const StaticAnalysisConfig config,
|
||||||
MessageSet results = analyze(fileName, m, config, moduleCache, tokens, true);
|
MessageSet results = analyze(fileName, m, config, moduleCache, tokens, true);
|
||||||
foreach (result; results[])
|
foreach (result; results[])
|
||||||
{
|
{
|
||||||
writeJSON(result.key, result.fileName, result.line, result.column, result.message);
|
writeJSON(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeln();
|
writeln();
|
||||||
|
@ -206,7 +210,7 @@ bool analyze(string[] fileNames, const StaticAnalysisConfig config, string error
|
||||||
foreach (result; results[])
|
foreach (result; results[])
|
||||||
{
|
{
|
||||||
hasErrors = true;
|
hasErrors = true;
|
||||||
messageFunctionFormat(errorFormat, result.fileName, result.line, result.column, result.message, false);
|
messageFunctionFormat(errorFormat, result, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hasErrors;
|
return hasErrors;
|
||||||
|
@ -219,7 +223,7 @@ const(Module) parseModule(string fileName, ubyte[] code, RollbackAllocator* p,
|
||||||
import dscanner.stats : isLineOfCode;
|
import dscanner.stats : isLineOfCode;
|
||||||
|
|
||||||
auto writeMessages = delegate(string fileName, size_t line, size_t column, string message, bool isError){
|
auto writeMessages = delegate(string fileName, size_t line, size_t column, string message, bool isError){
|
||||||
return messageFunctionFormat(errorFormat, fileName, line, column, message, isError);
|
return messageFunctionFormat(errorFormat, Message(fileName, line, column, message), isError);
|
||||||
};
|
};
|
||||||
|
|
||||||
LexerConfig config;
|
LexerConfig config;
|
||||||
|
@ -239,8 +243,10 @@ The user can specify a comma-separated list of filters, everyone needs to start
|
||||||
either a '+' (inclusion) or '-' (exclusion).
|
either a '+' (inclusion) or '-' (exclusion).
|
||||||
If no includes are specified, all modules are included.
|
If no includes are specified, all modules are included.
|
||||||
*/
|
*/
|
||||||
bool shouldRun(string a)(string moduleName, const ref StaticAnalysisConfig config)
|
bool shouldRun(check : BaseAnalyzer)(string moduleName, const ref StaticAnalysisConfig config)
|
||||||
{
|
{
|
||||||
|
enum string a = check.name;
|
||||||
|
|
||||||
if (mixin("config." ~ a) == Check.disabled)
|
if (mixin("config." ~ a) == Check.disabled)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -279,7 +285,7 @@ unittest
|
||||||
config.asm_style_check = Check.enabled;
|
config.asm_style_check = Check.enabled;
|
||||||
// this is done automatically by inifiled
|
// this is done automatically by inifiled
|
||||||
config.filters.asm_style_check = filters.split(",");
|
config.filters.asm_style_check = filters.split(",");
|
||||||
return shouldRun!"asm_style_check"(moduleName, config);
|
return shouldRun!AsmStyleCheck(moduleName, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// test inclusion
|
// test inclusion
|
||||||
|
@ -337,213 +343,210 @@ MessageSet analyze(string fileName, const Module m, const StaticAnalysisConfig a
|
||||||
|
|
||||||
GC.disable;
|
GC.disable;
|
||||||
|
|
||||||
with(analysisConfig)
|
if (moduleName.shouldRun!AsmStyleCheck(analysisConfig))
|
||||||
if (moduleName.shouldRun!"asm_style_check"(analysisConfig))
|
|
||||||
checks ~= new AsmStyleCheck(fileName, moduleScope,
|
checks ~= new AsmStyleCheck(fileName, moduleScope,
|
||||||
asm_style_check == Check.skipTests && !ut);
|
analysisConfig.asm_style_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"backwards_range_check"(analysisConfig))
|
if (moduleName.shouldRun!BackwardsRangeCheck(analysisConfig))
|
||||||
checks ~= new BackwardsRangeCheck(fileName, moduleScope,
|
checks ~= new BackwardsRangeCheck(fileName, moduleScope,
|
||||||
analysisConfig.backwards_range_check == Check.skipTests && !ut);
|
analysisConfig.backwards_range_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"builtin_property_names_check"(analysisConfig))
|
if (moduleName.shouldRun!BuiltinPropertyNameCheck(analysisConfig))
|
||||||
checks ~= new BuiltinPropertyNameCheck(fileName, moduleScope,
|
checks ~= new BuiltinPropertyNameCheck(fileName, moduleScope,
|
||||||
analysisConfig.builtin_property_names_check == Check.skipTests && !ut);
|
analysisConfig.builtin_property_names_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"comma_expression_check"(analysisConfig))
|
if (moduleName.shouldRun!CommaExpressionCheck(analysisConfig))
|
||||||
checks ~= new CommaExpressionCheck(fileName, moduleScope,
|
checks ~= new CommaExpressionCheck(fileName, moduleScope,
|
||||||
analysisConfig.comma_expression_check == Check.skipTests && !ut);
|
analysisConfig.comma_expression_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"constructor_check"(analysisConfig))
|
if (moduleName.shouldRun!ConstructorCheck(analysisConfig))
|
||||||
checks ~= new ConstructorCheck(fileName, moduleScope,
|
checks ~= new ConstructorCheck(fileName, moduleScope,
|
||||||
analysisConfig.constructor_check == Check.skipTests && !ut);
|
analysisConfig.constructor_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"could_be_immutable_check"(analysisConfig))
|
if (moduleName.shouldRun!UnmodifiedFinder(analysisConfig))
|
||||||
checks ~= new UnmodifiedFinder(fileName, moduleScope,
|
checks ~= new UnmodifiedFinder(fileName, moduleScope,
|
||||||
analysisConfig.could_be_immutable_check == Check.skipTests && !ut);
|
analysisConfig.could_be_immutable_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"delete_check"(analysisConfig))
|
if (moduleName.shouldRun!DeleteCheck(analysisConfig))
|
||||||
checks ~= new DeleteCheck(fileName, moduleScope,
|
checks ~= new DeleteCheck(fileName, moduleScope,
|
||||||
analysisConfig.delete_check == Check.skipTests && !ut);
|
analysisConfig.delete_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"duplicate_attribute"(analysisConfig))
|
if (moduleName.shouldRun!DuplicateAttributeCheck(analysisConfig))
|
||||||
checks ~= new DuplicateAttributeCheck(fileName, moduleScope,
|
checks ~= new DuplicateAttributeCheck(fileName, moduleScope,
|
||||||
analysisConfig.duplicate_attribute == Check.skipTests && !ut);
|
analysisConfig.duplicate_attribute == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"enum_array_literal_check"(analysisConfig))
|
if (moduleName.shouldRun!EnumArrayLiteralCheck(analysisConfig))
|
||||||
checks ~= new EnumArrayLiteralCheck(fileName, moduleScope,
|
checks ~= new EnumArrayLiteralCheck(fileName, moduleScope,
|
||||||
analysisConfig.enum_array_literal_check == Check.skipTests && !ut);
|
analysisConfig.enum_array_literal_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"exception_check"(analysisConfig))
|
if (moduleName.shouldRun!PokemonExceptionCheck(analysisConfig))
|
||||||
checks ~= new PokemonExceptionCheck(fileName, moduleScope,
|
checks ~= new PokemonExceptionCheck(fileName, moduleScope,
|
||||||
analysisConfig.exception_check == Check.skipTests && !ut);
|
analysisConfig.exception_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"float_operator_check"(analysisConfig))
|
if (moduleName.shouldRun!FloatOperatorCheck(analysisConfig))
|
||||||
checks ~= new FloatOperatorCheck(fileName, moduleScope,
|
checks ~= new FloatOperatorCheck(fileName, moduleScope,
|
||||||
analysisConfig.float_operator_check == Check.skipTests && !ut);
|
analysisConfig.float_operator_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"function_attribute_check"(analysisConfig))
|
if (moduleName.shouldRun!FunctionAttributeCheck(analysisConfig))
|
||||||
checks ~= new FunctionAttributeCheck(fileName, moduleScope,
|
checks ~= new FunctionAttributeCheck(fileName, moduleScope,
|
||||||
analysisConfig.function_attribute_check == Check.skipTests && !ut);
|
analysisConfig.function_attribute_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"if_else_same_check"(analysisConfig))
|
if (moduleName.shouldRun!IfElseSameCheck(analysisConfig))
|
||||||
checks ~= new IfElseSameCheck(fileName, moduleScope,
|
checks ~= new IfElseSameCheck(fileName, moduleScope,
|
||||||
analysisConfig.if_else_same_check == Check.skipTests&& !ut);
|
analysisConfig.if_else_same_check == Check.skipTests&& !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"label_var_same_name_check"(analysisConfig))
|
if (moduleName.shouldRun!LabelVarNameCheck(analysisConfig))
|
||||||
checks ~= new LabelVarNameCheck(fileName, moduleScope,
|
checks ~= new LabelVarNameCheck(fileName, moduleScope,
|
||||||
analysisConfig.label_var_same_name_check == Check.skipTests && !ut);
|
analysisConfig.label_var_same_name_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"length_subtraction_check"(analysisConfig))
|
if (moduleName.shouldRun!LengthSubtractionCheck(analysisConfig))
|
||||||
checks ~= new LengthSubtractionCheck(fileName, moduleScope,
|
checks ~= new LengthSubtractionCheck(fileName, moduleScope,
|
||||||
analysisConfig.length_subtraction_check == Check.skipTests && !ut);
|
analysisConfig.length_subtraction_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"local_import_check"(analysisConfig))
|
if (moduleName.shouldRun!LocalImportCheck(analysisConfig))
|
||||||
checks ~= new LocalImportCheck(fileName, moduleScope,
|
checks ~= new LocalImportCheck(fileName, moduleScope,
|
||||||
analysisConfig.local_import_check == Check.skipTests && !ut);
|
analysisConfig.local_import_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"logical_precedence_check"(analysisConfig))
|
if (moduleName.shouldRun!LogicPrecedenceCheck(analysisConfig))
|
||||||
checks ~= new LogicPrecedenceCheck(fileName, moduleScope,
|
checks ~= new LogicPrecedenceCheck(fileName, moduleScope,
|
||||||
analysisConfig.logical_precedence_check == Check.skipTests && !ut);
|
analysisConfig.logical_precedence_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"mismatched_args_check"(analysisConfig))
|
if (moduleName.shouldRun!MismatchedArgumentCheck(analysisConfig))
|
||||||
checks ~= new MismatchedArgumentCheck(fileName, moduleScope,
|
checks ~= new MismatchedArgumentCheck(fileName, moduleScope,
|
||||||
analysisConfig.mismatched_args_check == Check.skipTests && !ut);
|
analysisConfig.mismatched_args_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"number_style_check"(analysisConfig))
|
if (moduleName.shouldRun!NumberStyleCheck(analysisConfig))
|
||||||
checks ~= new NumberStyleCheck(fileName, moduleScope,
|
checks ~= new NumberStyleCheck(fileName, moduleScope,
|
||||||
analysisConfig.number_style_check == Check.skipTests && !ut);
|
analysisConfig.number_style_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"object_const_check"(analysisConfig))
|
if (moduleName.shouldRun!ObjectConstCheck(analysisConfig))
|
||||||
checks ~= new ObjectConstCheck(fileName, moduleScope,
|
checks ~= new ObjectConstCheck(fileName, moduleScope,
|
||||||
analysisConfig.object_const_check == Check.skipTests && !ut);
|
analysisConfig.object_const_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"opequals_tohash_check"(analysisConfig))
|
if (moduleName.shouldRun!OpEqualsWithoutToHashCheck(analysisConfig))
|
||||||
checks ~= new OpEqualsWithoutToHashCheck(fileName, moduleScope,
|
checks ~= new OpEqualsWithoutToHashCheck(fileName, moduleScope,
|
||||||
analysisConfig.opequals_tohash_check == Check.skipTests && !ut);
|
analysisConfig.opequals_tohash_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"redundant_parens_check"(analysisConfig))
|
if (moduleName.shouldRun!RedundantParenCheck(analysisConfig))
|
||||||
checks ~= new RedundantParenCheck(fileName, moduleScope,
|
checks ~= new RedundantParenCheck(fileName, moduleScope,
|
||||||
analysisConfig.redundant_parens_check == Check.skipTests && !ut);
|
analysisConfig.redundant_parens_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"style_check"(analysisConfig))
|
if (moduleName.shouldRun!StyleChecker(analysisConfig))
|
||||||
checks ~= new StyleChecker(fileName, moduleScope,
|
checks ~= new StyleChecker(fileName, moduleScope,
|
||||||
analysisConfig.style_check == Check.skipTests && !ut);
|
analysisConfig.style_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"undocumented_declaration_check"(analysisConfig))
|
if (moduleName.shouldRun!UndocumentedDeclarationCheck(analysisConfig))
|
||||||
checks ~= new UndocumentedDeclarationCheck(fileName, moduleScope,
|
checks ~= new UndocumentedDeclarationCheck(fileName, moduleScope,
|
||||||
analysisConfig.undocumented_declaration_check == Check.skipTests && !ut);
|
analysisConfig.undocumented_declaration_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"unused_label_check"(analysisConfig))
|
if (moduleName.shouldRun!UnusedLabelCheck(analysisConfig))
|
||||||
checks ~= new UnusedLabelCheck(fileName, moduleScope,
|
checks ~= new UnusedLabelCheck(fileName, moduleScope,
|
||||||
analysisConfig.unused_label_check == Check.skipTests && !ut);
|
analysisConfig.unused_label_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"unused_variable_check"(analysisConfig))
|
if (moduleName.shouldRun!UnusedVariableCheck(analysisConfig))
|
||||||
checks ~= new UnusedVariableCheck(fileName, moduleScope,
|
checks ~= new UnusedVariableCheck(fileName, moduleScope,
|
||||||
analysisConfig.unused_variable_check == Check.skipTests && !ut);
|
analysisConfig.unused_variable_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"unused_parameter_check"(analysisConfig))
|
if (moduleName.shouldRun!UnusedParameterCheck(analysisConfig))
|
||||||
checks ~= new UnusedParameterCheck(fileName, moduleScope,
|
checks ~= new UnusedParameterCheck(fileName, moduleScope,
|
||||||
analysisConfig.unused_parameter_check == Check.skipTests && !ut);
|
analysisConfig.unused_parameter_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"long_line_check"(analysisConfig))
|
if (moduleName.shouldRun!LineLengthCheck(analysisConfig))
|
||||||
checks ~= new LineLengthCheck(fileName, tokens,
|
checks ~= new LineLengthCheck(fileName, tokens,
|
||||||
analysisConfig.long_line_check == Check.skipTests && !ut);
|
analysisConfig.long_line_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"auto_ref_assignment_check"(analysisConfig))
|
if (moduleName.shouldRun!AutoRefAssignmentCheck(analysisConfig))
|
||||||
checks ~= new AutoRefAssignmentCheck(fileName,
|
checks ~= new AutoRefAssignmentCheck(fileName,
|
||||||
analysisConfig.auto_ref_assignment_check == Check.skipTests && !ut);
|
analysisConfig.auto_ref_assignment_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"incorrect_infinite_range_check"(analysisConfig))
|
if (moduleName.shouldRun!IncorrectInfiniteRangeCheck(analysisConfig))
|
||||||
checks ~= new IncorrectInfiniteRangeCheck(fileName,
|
checks ~= new IncorrectInfiniteRangeCheck(fileName,
|
||||||
analysisConfig.incorrect_infinite_range_check == Check.skipTests && !ut);
|
analysisConfig.incorrect_infinite_range_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"useless_assert_check"(analysisConfig))
|
if (moduleName.shouldRun!UselessAssertCheck(analysisConfig))
|
||||||
checks ~= new UselessAssertCheck(fileName,
|
checks ~= new UselessAssertCheck(fileName,
|
||||||
analysisConfig.useless_assert_check == Check.skipTests && !ut);
|
analysisConfig.useless_assert_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"alias_syntax_check"(analysisConfig))
|
if (moduleName.shouldRun!AliasSyntaxCheck(analysisConfig))
|
||||||
checks ~= new AliasSyntaxCheck(fileName,
|
checks ~= new AliasSyntaxCheck(fileName,
|
||||||
analysisConfig.alias_syntax_check == Check.skipTests && !ut);
|
analysisConfig.alias_syntax_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"static_if_else_check"(analysisConfig))
|
if (moduleName.shouldRun!StaticIfElse(analysisConfig))
|
||||||
checks ~= new StaticIfElse(fileName,
|
checks ~= new StaticIfElse(fileName,
|
||||||
analysisConfig.static_if_else_check == Check.skipTests && !ut);
|
analysisConfig.static_if_else_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"lambda_return_check"(analysisConfig))
|
if (moduleName.shouldRun!LambdaReturnCheck(analysisConfig))
|
||||||
checks ~= new LambdaReturnCheck(fileName,
|
checks ~= new LambdaReturnCheck(fileName,
|
||||||
analysisConfig.lambda_return_check == Check.skipTests && !ut);
|
analysisConfig.lambda_return_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"auto_function_check"(analysisConfig))
|
if (moduleName.shouldRun!AutoFunctionChecker(analysisConfig))
|
||||||
checks ~= new AutoFunctionChecker(fileName,
|
checks ~= new AutoFunctionChecker(fileName,
|
||||||
analysisConfig.auto_function_check == Check.skipTests && !ut);
|
analysisConfig.auto_function_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"imports_sortedness"(analysisConfig))
|
if (moduleName.shouldRun!ImportSortednessCheck(analysisConfig))
|
||||||
checks ~= new ImportSortednessCheck(fileName,
|
checks ~= new ImportSortednessCheck(fileName,
|
||||||
analysisConfig.imports_sortedness == Check.skipTests && !ut);
|
analysisConfig.imports_sortedness == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"explicitly_annotated_unittests"(analysisConfig))
|
if (moduleName.shouldRun!ExplicitlyAnnotatedUnittestCheck(analysisConfig))
|
||||||
checks ~= new ExplicitlyAnnotatedUnittestCheck(fileName,
|
checks ~= new ExplicitlyAnnotatedUnittestCheck(fileName,
|
||||||
analysisConfig.explicitly_annotated_unittests == Check.skipTests && !ut);
|
analysisConfig.explicitly_annotated_unittests == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"properly_documented_public_functions"(analysisConfig))
|
if (moduleName.shouldRun!ProperlyDocumentedPublicFunctions(analysisConfig))
|
||||||
checks ~= new ProperlyDocumentedPublicFunctions(fileName,
|
checks ~= new ProperlyDocumentedPublicFunctions(fileName,
|
||||||
analysisConfig.properly_documented_public_functions == Check.skipTests && !ut);
|
analysisConfig.properly_documented_public_functions == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"final_attribute_check"(analysisConfig))
|
if (moduleName.shouldRun!FinalAttributeChecker(analysisConfig))
|
||||||
checks ~= new FinalAttributeChecker(fileName,
|
checks ~= new FinalAttributeChecker(fileName,
|
||||||
analysisConfig.final_attribute_check == Check.skipTests && !ut);
|
analysisConfig.final_attribute_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"vcall_in_ctor"(analysisConfig))
|
if (moduleName.shouldRun!VcallCtorChecker(analysisConfig))
|
||||||
checks ~= new VcallCtorChecker(fileName,
|
checks ~= new VcallCtorChecker(fileName,
|
||||||
analysisConfig.vcall_in_ctor == Check.skipTests && !ut);
|
analysisConfig.vcall_in_ctor == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"useless_initializer"(analysisConfig))
|
if (moduleName.shouldRun!UselessInitializerChecker(analysisConfig))
|
||||||
checks ~= new UselessInitializerChecker(fileName,
|
checks ~= new UselessInitializerChecker(fileName,
|
||||||
analysisConfig.useless_initializer == Check.skipTests && !ut);
|
analysisConfig.useless_initializer == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"allman_braces_check"(analysisConfig))
|
if (moduleName.shouldRun!AllManCheck(analysisConfig))
|
||||||
checks ~= new AllManCheck(fileName, tokens,
|
checks ~= new AllManCheck(fileName, tokens,
|
||||||
analysisConfig.allman_braces_check == Check.skipTests && !ut);
|
analysisConfig.allman_braces_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"redundant_attributes_check"(analysisConfig))
|
if (moduleName.shouldRun!RedundantAttributesCheck(analysisConfig))
|
||||||
checks ~= new RedundantAttributesCheck(fileName, moduleScope,
|
checks ~= new RedundantAttributesCheck(fileName, moduleScope,
|
||||||
analysisConfig.redundant_attributes_check == Check.skipTests && !ut);
|
analysisConfig.redundant_attributes_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"has_public_example"(analysisConfig))
|
if (moduleName.shouldRun!HasPublicExampleCheck(analysisConfig))
|
||||||
checks ~= new HasPublicExampleCheck(fileName, moduleScope,
|
checks ~= new HasPublicExampleCheck(fileName, moduleScope,
|
||||||
analysisConfig.has_public_example == Check.skipTests && !ut);
|
analysisConfig.has_public_example == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"assert_without_msg"(analysisConfig))
|
if (moduleName.shouldRun!AssertWithoutMessageCheck(analysisConfig))
|
||||||
checks ~= new AssertWithoutMessageCheck(fileName, moduleScope,
|
checks ~= new AssertWithoutMessageCheck(fileName, moduleScope,
|
||||||
analysisConfig.assert_without_msg == Check.skipTests && !ut);
|
analysisConfig.assert_without_msg == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"if_constraints_indent"(analysisConfig))
|
if (moduleName.shouldRun!IfConstraintsIndentCheck(analysisConfig))
|
||||||
checks ~= new IfConstraintsIndentCheck(fileName, tokens,
|
checks ~= new IfConstraintsIndentCheck(fileName, tokens,
|
||||||
analysisConfig.if_constraints_indent == Check.skipTests && !ut);
|
analysisConfig.if_constraints_indent == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"trust_too_much"(analysisConfig))
|
if (moduleName.shouldRun!TrustTooMuchCheck(analysisConfig))
|
||||||
checks ~= new TrustTooMuchCheck(fileName,
|
checks ~= new TrustTooMuchCheck(fileName,
|
||||||
analysisConfig.trust_too_much == Check.skipTests && !ut);
|
analysisConfig.trust_too_much == Check.skipTests && !ut);
|
||||||
|
|
||||||
if (moduleName.shouldRun!"redundant_storage_classes"(analysisConfig))
|
if (moduleName.shouldRun!RedundantStorageClassCheck(analysisConfig))
|
||||||
checks ~= new RedundantStorageClassCheck(fileName,
|
checks ~= new RedundantStorageClassCheck(fileName,
|
||||||
analysisConfig.redundant_storage_classes == Check.skipTests && !ut);
|
analysisConfig.redundant_storage_classes == Check.skipTests && !ut);
|
||||||
|
|
||||||
version (none)
|
version (none)
|
||||||
if (moduleName.shouldRun!"redundant_if_check"(analysisConfig))
|
if (moduleName.shouldRun!IfStatementCheck(analysisConfig))
|
||||||
checks ~= new IfStatementCheck(fileName, moduleScope,
|
checks ~= new IfStatementCheck(fileName, moduleScope,
|
||||||
analysisConfig.redundant_if_check == Check.skipTests && !ut);
|
analysisConfig.redundant_if_check == Check.skipTests && !ut);
|
||||||
|
|
||||||
|
MessageSet set = new MessageSet;
|
||||||
foreach (check; checks)
|
foreach (check; checks)
|
||||||
{
|
{
|
||||||
check.visit(m);
|
check.visit(m);
|
||||||
}
|
|
||||||
|
|
||||||
MessageSet set = new MessageSet;
|
|
||||||
foreach (check; checks)
|
|
||||||
foreach (message; check.messages)
|
foreach (message; check.messages)
|
||||||
set.insert(message);
|
set.insert(message);
|
||||||
|
}
|
||||||
|
|
||||||
GC.enable;
|
GC.enable;
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@ final class StaticIfElse : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"static_if_else_check";
|
||||||
|
|
||||||
this(string fileName, bool skipTests = false)
|
this(string fileName, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, null, skipTests);
|
super(fileName, null, skipTests);
|
||||||
|
|
|
@ -24,6 +24,7 @@ final class StyleChecker : BaseAnalyzer
|
||||||
enum string aggregateNameRegex = `^\p{Lu}[\w\d]*$`;
|
enum string aggregateNameRegex = `^\p{Lu}[\w\d]*$`;
|
||||||
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";
|
||||||
|
mixin AnalyzerInfo!"style_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,6 +28,8 @@ public:
|
||||||
|
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"trust_too_much";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, bool skipTests = false)
|
this(string fileName, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,8 @@ final class UndocumentedDeclarationCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"undocumented_declaration_check";
|
||||||
|
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(fileName, sc, skipTests);
|
super(fileName, sc, skipTests);
|
||||||
|
|
|
@ -18,6 +18,8 @@ final class UnmodifiedFinder : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"could_be_immutable_check";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,6 +18,8 @@ final class UnusedLabelCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"unused_label_check";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
this(string fileName, const(Scope)* sc, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,7 @@ module dscanner.analysis.unused_parameter;
|
||||||
|
|
||||||
import dparse.ast;
|
import dparse.ast;
|
||||||
import dparse.lexer;
|
import dparse.lexer;
|
||||||
|
import dscanner.analysis.base;
|
||||||
import dscanner.analysis.unused;
|
import dscanner.analysis.unused;
|
||||||
import dsymbol.scope_ : Scope;
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
|
@ -16,6 +17,8 @@ final class UnusedParameterCheck : UnusedIdentifierCheck
|
||||||
{
|
{
|
||||||
alias visit = UnusedIdentifierCheck.visit;
|
alias visit = UnusedIdentifierCheck.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"unused_parameter_check";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* fileName = the name of the file being analyzed
|
* fileName = the name of the file being analyzed
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
module dscanner.analysis.unused_variable;
|
module dscanner.analysis.unused_variable;
|
||||||
|
|
||||||
import dparse.ast;
|
import dparse.ast;
|
||||||
|
import dscanner.analysis.base;
|
||||||
import dscanner.analysis.unused;
|
import dscanner.analysis.unused;
|
||||||
import dsymbol.scope_ : Scope;
|
import dsymbol.scope_ : Scope;
|
||||||
import std.algorithm.iteration : map;
|
import std.algorithm.iteration : map;
|
||||||
|
@ -16,6 +17,8 @@ final class UnusedVariableCheck : UnusedIdentifierCheck
|
||||||
{
|
{
|
||||||
alias visit = UnusedIdentifierCheck.visit;
|
alias visit = UnusedIdentifierCheck.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"unused_variable_check";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* fileName = the name of the file being analyzed
|
* fileName = the name of the file being analyzed
|
||||||
|
|
|
@ -27,6 +27,8 @@ final class UselessAssertCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"useless_assert_check";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName, bool skipTests = false)
|
this(string fileName, bool skipTests = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,6 +29,8 @@ final class UselessInitializerChecker : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"useless_initializer";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
enum key = "dscanner.useless-initializer";
|
enum key = "dscanner.useless-initializer";
|
||||||
|
|
|
@ -20,6 +20,8 @@ final class VcallCtorChecker : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
mixin AnalyzerInfo!"vcall_in_ctor";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
enum string KEY = "dscanner.vcall_ctor";
|
enum string KEY = "dscanner.vcall_ctor";
|
||||||
|
|
Loading…
Reference in New Issue