Track check name for error messages (#769)

* Track check name for error messages

* Assert BaseAnalyzer.getName() is implemented
This commit is contained in:
Eugene Wissner 2019-07-09 12:16:25 +02:00 committed by Basile-z
parent 94d102a5f6
commit 3b9d608866
51 changed files with 195 additions and 83 deletions

View File

@ -16,6 +16,8 @@ final class AliasSyntaxCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"alias_syntax_check";
this(string fileName, bool skipTests = false)
{
super(fileName, null, skipTests);

View File

@ -6,7 +6,7 @@ module dscanner.analysis.allman;
import dparse.lexer;
import dparse.ast;
import dscanner.analysis.base : BaseAnalyzer;
import dscanner.analysis.base;
import dsymbol.scope_ : Scope;
import std.algorithm;
@ -27,6 +27,8 @@ if (param < 0)
*/
final class AllManCheck : BaseAnalyzer
{
mixin AnalyzerInfo!"allman_braces_check";
///
this(string fileName, const(Token)[] tokens, bool skipTests = false)
{

View File

@ -20,6 +20,8 @@ final class AsmStyleCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"asm_style_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -4,7 +4,7 @@
module dscanner.analysis.assert_without_msg;
import dscanner.analysis.base : BaseAnalyzer;
import dscanner.analysis.base;
import dscanner.utils : safeAccess;
import dsymbol.scope_ : Scope;
import dparse.lexer;
@ -20,6 +20,7 @@ final class AssertWithoutMessageCheck : BaseAnalyzer
{
enum string KEY = "dscanner.style.assert_without_msg";
enum string MESSAGE = "An assert should have an explanatory message";
mixin AnalyzerInfo!"assert_without_msg";
///
this(string fileName, const(Scope)* sc, bool skipTests = false)

View File

@ -36,6 +36,8 @@ public:
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"auto_function_check";
///
this(string fileName, bool skipTests = false)
{

View File

@ -14,6 +14,8 @@ import dscanner.analysis.base;
*/
final class AutoRefAssignmentCheck : BaseAnalyzer
{
mixin AnalyzerInfo!"auto_ref_assignment_check";
///
this(string fileName, bool skipTests = false)
{

View File

@ -18,12 +18,24 @@ struct Message
string key;
/// Warning message
string message;
/// Check name
string checkName;
}
enum comparitor = q{ a.line < b.line || (a.line == b.line && a.column < b.column) };
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
{
public:
@ -35,6 +47,11 @@ public:
_messages = new MessageSet;
}
protected string getName()
{
assert(0);
}
Message[] messages()
{
return _messages[].array;
@ -71,7 +88,7 @@ protected:
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()));
}
/**

View File

@ -31,6 +31,8 @@ final class BuiltinPropertyNameCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"builtin_property_names_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -17,6 +17,8 @@ final class CommaExpressionCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"comma_expression_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -11,6 +11,8 @@ final class ConstructorCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"constructor_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -18,6 +18,8 @@ final class DeleteCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"delete_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -21,6 +21,8 @@ final class DuplicateAttributeCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"duplicate_attribute";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -19,6 +19,8 @@ final class EnumArrayLiteralCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"enum_array_literal_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -6,7 +6,7 @@ module dscanner.analysis.explicitly_annotated_unittests;
import dparse.lexer;
import dparse.ast;
import dscanner.analysis.base : BaseAnalyzer;
import dscanner.analysis.base;
import std.stdio;
@ -17,6 +17,7 @@ final class ExplicitlyAnnotatedUnittestCheck : BaseAnalyzer
{
enum string KEY = "dscanner.style.explicitly_annotated_unittest";
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)

View File

@ -66,6 +66,8 @@ public:
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"final_attribute_check";
enum pushPopPrivate = q{
const bool wasPrivate = _private;
_private = false;

View File

@ -20,6 +20,7 @@ final class FloatOperatorCheck : BaseAnalyzer
alias visit = BaseAnalyzer.visit;
enum string KEY = "dscanner.deprecated.floating_point_operators";
mixin AnalyzerInfo!"float_operator_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{

View File

@ -25,6 +25,8 @@ final class FunctionAttributeCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"function_attribute_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -20,6 +20,8 @@ final class HasPublicExampleCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"has_public_example";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -6,7 +6,7 @@ module dscanner.analysis.if_constraints_indent;
import dparse.lexer;
import dparse.ast;
import dscanner.analysis.base : BaseAnalyzer, Message;
import dscanner.analysis.base;
import dsymbol.scope_ : Scope;
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
{
mixin AnalyzerInfo!"if_constraints_indent";
///
this(string fileName, const(Token)[] tokens, bool skipTests = false)
{

View File

@ -13,6 +13,8 @@ import dsymbol.scope_ : Scope;
final class IfStatementCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"redundant_if_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -24,6 +24,8 @@ final class IfElseSameCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"if_else_same_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -4,7 +4,7 @@
module dscanner.analysis.imports_sortedness;
import dscanner.analysis.base : BaseAnalyzer;
import dscanner.analysis.base;
import dparse.lexer;
import dparse.ast;
@ -17,6 +17,7 @@ final class ImportSortednessCheck : BaseAnalyzer
{
enum string KEY = "dscanner.style.imports_sortedness";
enum string MESSAGE = "The imports are not sorted in alphabetical order";
mixin AnalyzerInfo!"imports_sortedness";
///
this(string fileName, bool skipTests = false)

View File

@ -17,6 +17,8 @@ final class IncorrectInfiniteRangeCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"incorrect_infinite_range_check";
///
this(string fileName, bool skipTests = false)
{

View File

@ -15,6 +15,8 @@ import dscanner.analysis.helpers;
*/
final class LabelVarNameCheck : BaseAnalyzer
{
mixin AnalyzerInfo!"label_var_same_name_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -14,6 +14,8 @@ final class LambdaReturnCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"lambda_return_check";
this(string fileName, bool skipTests = false)
{
super(fileName, null, skipTests);

View File

@ -20,6 +20,8 @@ final class LengthSubtractionCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"length_subtraction_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -5,7 +5,7 @@
module dscanner.analysis.line_length;
import dscanner.analysis.base : BaseAnalyzer;
import dscanner.analysis.base;
import dparse.ast;
import dparse.lexer;
@ -17,6 +17,8 @@ import std.typecons : tuple, Tuple;
*/
final class LineLengthCheck : BaseAnalyzer
{
mixin AnalyzerInfo!"long_line_check";
///
this(string fileName, const(Token)[] tokens, bool skipTests = false)
{

View File

@ -20,6 +20,8 @@ final class LocalImportCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"local_import_check";
/**
* Construct with the given file name.
*/

View File

@ -24,6 +24,7 @@ final class LogicPrecedenceCheck : BaseAnalyzer
alias visit = BaseAnalyzer.visit;
enum string KEY = "dscanner.confusing.logical_precedence";
mixin AnalyzerInfo!"logical_precedence_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{

View File

@ -1,6 +1,6 @@
module dscanner.analysis.mismatched_args;
import dscanner.analysis.base : BaseAnalyzer;
import dscanner.analysis.base;
import dscanner.utils : safeAccess;
import dsymbol.scope_;
import dsymbol.symbol;
@ -11,6 +11,8 @@ import dsymbol.builtin.names;
/// Checks for mismatched argument and parameter names
final class MismatchedArgumentCheck : BaseAnalyzer
{
mixin AnalyzerInfo!"mismatched_args_check";
///
this(string fileName, const(Scope)* sc, bool skipTests = false)
{

View File

@ -21,6 +21,8 @@ final class NumberStyleCheck : BaseAnalyzer
public:
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"number_style_check";
/**
* Constructs the style checker with the given file name.
*/

View File

@ -21,6 +21,8 @@ final class ObjectConstCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"object_const_check";
///
this(string fileName, const(Scope)* sc, bool skipTests = false)
{

View File

@ -20,6 +20,8 @@ final class OpEqualsWithoutToHashCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"opequals_tohash_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -27,6 +27,7 @@ final class PokemonExceptionCheck : BaseAnalyzer
{
enum MESSAGE = "Catching Error or Throwable is almost always a bad idea.";
enum string KEY = "dscanner.suspicious.catch_em_all";
mixin AnalyzerInfo!"exception_check";
alias visit = BaseAnalyzer.visit;

View File

@ -7,7 +7,7 @@ module dscanner.analysis.properly_documented_public_functions;
import dparse.lexer;
import dparse.ast;
import dparse.formatter : astFmt = format;
import dscanner.analysis.base : BaseAnalyzer;
import dscanner.analysis.base;
import dscanner.utils : safeAccess;
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_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)
{

View File

@ -20,6 +20,8 @@ final class BackwardsRangeCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"backwards_range_check";
/// Key for this check in the report output
enum string KEY = "dscanner.bugs.backwards_slices";

View File

@ -19,6 +19,8 @@ import std.range : empty, front, walkLength;
*/
final class RedundantAttributesCheck : BaseAnalyzer
{
mixin AnalyzerInfo!"redundant_attributes_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -17,6 +17,8 @@ final class RedundantParenCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"redundant_parens_check";
///
this(string fileName, const(Scope)* sc, bool skipTests = false)
{

View File

@ -20,6 +20,7 @@ final class RedundantStorageClassCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
enum string REDUNDANT_VARIABLE_ATTRIBUTES = "Variable declaration for `%s` has redundant attributes (%-(`%s`%|, %)).";
mixin AnalyzerInfo!"redundant_storage_classes";
this(string fileName, bool skipTests = false)
{

View File

@ -95,41 +95,45 @@ private alias ASTAllocator = CAllocatorImpl!(
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;
s = s.replace("{filepath}", fileName);
s = s.replace("{line}", to!string(line));
s = s.replace("{column}", to!string(column));
s = s.replace("{filepath}", message.fileName);
s = s.replace("{line}", to!string(message.line));
s = s.replace("{column}", to!string(message.column));
s = s.replace("{type}", isError ? "error" : "warn");
s = s.replace("{message}", message);
s = s.replace("{message}", message.message);
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)
{
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)
writeln(",");
else
first = false;
writeln(" {");
writeln(` "key": "`, key, `",`);
writeln(` "fileName": "`, fileName.replace("\\", "\\\\").replace(`"`, `\"`), `",`);
writeln(` "line": `, line, `,`);
writeln(` "column": `, column, `,`);
writeln(` "message": "`, message.replace("\\", "\\\\").replace(`"`, `\"`), `"`);
writeln(` "key": "`, message.key, `",`);
if (message.checkName !is null)
{
writeln(` "name": "`, message.checkName, `",`);
}
writeln(` "fileName": "`, message.fileName.replace("\\", "\\\\").replace(`"`, `\"`), `",`);
writeln(` "line": `, message.line, `,`);
writeln(` "column": `, message.column, `,`);
writeln(` "message": "`, message.message.replace("\\", "\\\\").replace(`"`, `\"`), `"`);
write(" }");
}
@ -160,7 +164,7 @@ void generateReport(string[] fileNames, const StaticAnalysisConfig config,
MessageSet results = analyze(fileName, m, config, moduleCache, tokens, true);
foreach (result; results[])
{
writeJSON(result.key, result.fileName, result.line, result.column, result.message);
writeJSON(result);
}
}
writeln();
@ -206,7 +210,7 @@ bool analyze(string[] fileNames, const StaticAnalysisConfig config, string error
foreach (result; results[])
{
hasErrors = true;
messageFunctionFormat(errorFormat, result.fileName, result.line, result.column, result.message, false);
messageFunctionFormat(errorFormat, result, false);
}
}
return hasErrors;
@ -219,7 +223,7 @@ const(Module) parseModule(string fileName, ubyte[] code, RollbackAllocator* p,
import dscanner.stats : isLineOfCode;
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;
@ -239,8 +243,10 @@ The user can specify a comma-separated list of filters, everyone needs to start
either a '+' (inclusion) or '-' (exclusion).
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)
return false;
@ -279,7 +285,7 @@ unittest
config.asm_style_check = Check.enabled;
// this is done automatically by inifiled
config.filters.asm_style_check = filters.split(",");
return shouldRun!"asm_style_check"(moduleName, config);
return shouldRun!AsmStyleCheck(moduleName, config);
}
// test inclusion
@ -337,213 +343,210 @@ MessageSet analyze(string fileName, const Module m, const StaticAnalysisConfig a
GC.disable;
with(analysisConfig)
if (moduleName.shouldRun!"asm_style_check"(analysisConfig))
if (moduleName.shouldRun!AsmStyleCheck(analysisConfig))
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,
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,
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,
analysisConfig.comma_expression_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"constructor_check"(analysisConfig))
if (moduleName.shouldRun!ConstructorCheck(analysisConfig))
checks ~= new ConstructorCheck(fileName, moduleScope,
analysisConfig.constructor_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"could_be_immutable_check"(analysisConfig))
if (moduleName.shouldRun!UnmodifiedFinder(analysisConfig))
checks ~= new UnmodifiedFinder(fileName, moduleScope,
analysisConfig.could_be_immutable_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"delete_check"(analysisConfig))
if (moduleName.shouldRun!DeleteCheck(analysisConfig))
checks ~= new DeleteCheck(fileName, moduleScope,
analysisConfig.delete_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"duplicate_attribute"(analysisConfig))
if (moduleName.shouldRun!DuplicateAttributeCheck(analysisConfig))
checks ~= new DuplicateAttributeCheck(fileName, moduleScope,
analysisConfig.duplicate_attribute == Check.skipTests && !ut);
if (moduleName.shouldRun!"enum_array_literal_check"(analysisConfig))
if (moduleName.shouldRun!EnumArrayLiteralCheck(analysisConfig))
checks ~= new EnumArrayLiteralCheck(fileName, moduleScope,
analysisConfig.enum_array_literal_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"exception_check"(analysisConfig))
if (moduleName.shouldRun!PokemonExceptionCheck(analysisConfig))
checks ~= new PokemonExceptionCheck(fileName, moduleScope,
analysisConfig.exception_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"float_operator_check"(analysisConfig))
if (moduleName.shouldRun!FloatOperatorCheck(analysisConfig))
checks ~= new FloatOperatorCheck(fileName, moduleScope,
analysisConfig.float_operator_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"function_attribute_check"(analysisConfig))
if (moduleName.shouldRun!FunctionAttributeCheck(analysisConfig))
checks ~= new FunctionAttributeCheck(fileName, moduleScope,
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,
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,
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,
analysisConfig.length_subtraction_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"local_import_check"(analysisConfig))
if (moduleName.shouldRun!LocalImportCheck(analysisConfig))
checks ~= new LocalImportCheck(fileName, moduleScope,
analysisConfig.local_import_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"logical_precedence_check"(analysisConfig))
if (moduleName.shouldRun!LogicPrecedenceCheck(analysisConfig))
checks ~= new LogicPrecedenceCheck(fileName, moduleScope,
analysisConfig.logical_precedence_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"mismatched_args_check"(analysisConfig))
if (moduleName.shouldRun!MismatchedArgumentCheck(analysisConfig))
checks ~= new MismatchedArgumentCheck(fileName, moduleScope,
analysisConfig.mismatched_args_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"number_style_check"(analysisConfig))
if (moduleName.shouldRun!NumberStyleCheck(analysisConfig))
checks ~= new NumberStyleCheck(fileName, moduleScope,
analysisConfig.number_style_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"object_const_check"(analysisConfig))
if (moduleName.shouldRun!ObjectConstCheck(analysisConfig))
checks ~= new ObjectConstCheck(fileName, moduleScope,
analysisConfig.object_const_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"opequals_tohash_check"(analysisConfig))
if (moduleName.shouldRun!OpEqualsWithoutToHashCheck(analysisConfig))
checks ~= new OpEqualsWithoutToHashCheck(fileName, moduleScope,
analysisConfig.opequals_tohash_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"redundant_parens_check"(analysisConfig))
if (moduleName.shouldRun!RedundantParenCheck(analysisConfig))
checks ~= new RedundantParenCheck(fileName, moduleScope,
analysisConfig.redundant_parens_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"style_check"(analysisConfig))
if (moduleName.shouldRun!StyleChecker(analysisConfig))
checks ~= new StyleChecker(fileName, moduleScope,
analysisConfig.style_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"undocumented_declaration_check"(analysisConfig))
if (moduleName.shouldRun!UndocumentedDeclarationCheck(analysisConfig))
checks ~= new UndocumentedDeclarationCheck(fileName, moduleScope,
analysisConfig.undocumented_declaration_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"unused_label_check"(analysisConfig))
if (moduleName.shouldRun!UnusedLabelCheck(analysisConfig))
checks ~= new UnusedLabelCheck(fileName, moduleScope,
analysisConfig.unused_label_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"unused_variable_check"(analysisConfig))
if (moduleName.shouldRun!UnusedVariableCheck(analysisConfig))
checks ~= new UnusedVariableCheck(fileName, moduleScope,
analysisConfig.unused_variable_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"unused_parameter_check"(analysisConfig))
if (moduleName.shouldRun!UnusedParameterCheck(analysisConfig))
checks ~= new UnusedParameterCheck(fileName, moduleScope,
analysisConfig.unused_parameter_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"long_line_check"(analysisConfig))
if (moduleName.shouldRun!LineLengthCheck(analysisConfig))
checks ~= new LineLengthCheck(fileName, tokens,
analysisConfig.long_line_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"auto_ref_assignment_check"(analysisConfig))
if (moduleName.shouldRun!AutoRefAssignmentCheck(analysisConfig))
checks ~= new AutoRefAssignmentCheck(fileName,
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,
analysisConfig.incorrect_infinite_range_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"useless_assert_check"(analysisConfig))
if (moduleName.shouldRun!UselessAssertCheck(analysisConfig))
checks ~= new UselessAssertCheck(fileName,
analysisConfig.useless_assert_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"alias_syntax_check"(analysisConfig))
if (moduleName.shouldRun!AliasSyntaxCheck(analysisConfig))
checks ~= new AliasSyntaxCheck(fileName,
analysisConfig.alias_syntax_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"static_if_else_check"(analysisConfig))
if (moduleName.shouldRun!StaticIfElse(analysisConfig))
checks ~= new StaticIfElse(fileName,
analysisConfig.static_if_else_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"lambda_return_check"(analysisConfig))
if (moduleName.shouldRun!LambdaReturnCheck(analysisConfig))
checks ~= new LambdaReturnCheck(fileName,
analysisConfig.lambda_return_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"auto_function_check"(analysisConfig))
if (moduleName.shouldRun!AutoFunctionChecker(analysisConfig))
checks ~= new AutoFunctionChecker(fileName,
analysisConfig.auto_function_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"imports_sortedness"(analysisConfig))
if (moduleName.shouldRun!ImportSortednessCheck(analysisConfig))
checks ~= new ImportSortednessCheck(fileName,
analysisConfig.imports_sortedness == Check.skipTests && !ut);
if (moduleName.shouldRun!"explicitly_annotated_unittests"(analysisConfig))
if (moduleName.shouldRun!ExplicitlyAnnotatedUnittestCheck(analysisConfig))
checks ~= new ExplicitlyAnnotatedUnittestCheck(fileName,
analysisConfig.explicitly_annotated_unittests == Check.skipTests && !ut);
if (moduleName.shouldRun!"properly_documented_public_functions"(analysisConfig))
if (moduleName.shouldRun!ProperlyDocumentedPublicFunctions(analysisConfig))
checks ~= new ProperlyDocumentedPublicFunctions(fileName,
analysisConfig.properly_documented_public_functions == Check.skipTests && !ut);
if (moduleName.shouldRun!"final_attribute_check"(analysisConfig))
if (moduleName.shouldRun!FinalAttributeChecker(analysisConfig))
checks ~= new FinalAttributeChecker(fileName,
analysisConfig.final_attribute_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"vcall_in_ctor"(analysisConfig))
if (moduleName.shouldRun!VcallCtorChecker(analysisConfig))
checks ~= new VcallCtorChecker(fileName,
analysisConfig.vcall_in_ctor == Check.skipTests && !ut);
if (moduleName.shouldRun!"useless_initializer"(analysisConfig))
if (moduleName.shouldRun!UselessInitializerChecker(analysisConfig))
checks ~= new UselessInitializerChecker(fileName,
analysisConfig.useless_initializer == Check.skipTests && !ut);
if (moduleName.shouldRun!"allman_braces_check"(analysisConfig))
if (moduleName.shouldRun!AllManCheck(analysisConfig))
checks ~= new AllManCheck(fileName, tokens,
analysisConfig.allman_braces_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"redundant_attributes_check"(analysisConfig))
if (moduleName.shouldRun!RedundantAttributesCheck(analysisConfig))
checks ~= new RedundantAttributesCheck(fileName, moduleScope,
analysisConfig.redundant_attributes_check == Check.skipTests && !ut);
if (moduleName.shouldRun!"has_public_example"(analysisConfig))
if (moduleName.shouldRun!HasPublicExampleCheck(analysisConfig))
checks ~= new HasPublicExampleCheck(fileName, moduleScope,
analysisConfig.has_public_example == Check.skipTests && !ut);
if (moduleName.shouldRun!"assert_without_msg"(analysisConfig))
if (moduleName.shouldRun!AssertWithoutMessageCheck(analysisConfig))
checks ~= new AssertWithoutMessageCheck(fileName, moduleScope,
analysisConfig.assert_without_msg == Check.skipTests && !ut);
if (moduleName.shouldRun!"if_constraints_indent"(analysisConfig))
if (moduleName.shouldRun!IfConstraintsIndentCheck(analysisConfig))
checks ~= new IfConstraintsIndentCheck(fileName, tokens,
analysisConfig.if_constraints_indent == Check.skipTests && !ut);
if (moduleName.shouldRun!"trust_too_much"(analysisConfig))
if (moduleName.shouldRun!TrustTooMuchCheck(analysisConfig))
checks ~= new TrustTooMuchCheck(fileName,
analysisConfig.trust_too_much == Check.skipTests && !ut);
if (moduleName.shouldRun!"redundant_storage_classes"(analysisConfig))
if (moduleName.shouldRun!RedundantStorageClassCheck(analysisConfig))
checks ~= new RedundantStorageClassCheck(fileName,
analysisConfig.redundant_storage_classes == Check.skipTests && !ut);
version (none)
if (moduleName.shouldRun!"redundant_if_check"(analysisConfig))
if (moduleName.shouldRun!IfStatementCheck(analysisConfig))
checks ~= new IfStatementCheck(fileName, moduleScope,
analysisConfig.redundant_if_check == Check.skipTests && !ut);
MessageSet set = new MessageSet;
foreach (check; checks)
{
check.visit(m);
}
MessageSet set = new MessageSet;
foreach (check; checks)
foreach (message; check.messages)
set.insert(message);
}
GC.enable;

View File

@ -26,6 +26,8 @@ final class StaticIfElse : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"static_if_else_check";
this(string fileName, bool skipTests = false)
{
super(fileName, null, skipTests);

View File

@ -24,6 +24,7 @@ final class StyleChecker : BaseAnalyzer
enum string aggregateNameRegex = `^\p{Lu}[\w\d]*$`;
enum string moduleNameRegex = `^[\p{Ll}_\d]+$`;
enum string KEY = "dscanner.style.phobos_naming_convention";
mixin AnalyzerInfo!"style_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{

View File

@ -28,6 +28,8 @@ public:
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"trust_too_much";
///
this(string fileName, bool skipTests = false)
{

View File

@ -21,6 +21,8 @@ final class UndocumentedDeclarationCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"undocumented_declaration_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);

View File

@ -18,6 +18,8 @@ final class UnmodifiedFinder : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"could_be_immutable_check";
///
this(string fileName, const(Scope)* sc, bool skipTests = false)
{

View File

@ -18,6 +18,8 @@ final class UnusedLabelCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"unused_label_check";
///
this(string fileName, const(Scope)* sc, bool skipTests = false)
{

View File

@ -6,6 +6,7 @@ module dscanner.analysis.unused_parameter;
import dparse.ast;
import dparse.lexer;
import dscanner.analysis.base;
import dscanner.analysis.unused;
import dsymbol.scope_ : Scope;
@ -16,6 +17,8 @@ final class UnusedParameterCheck : UnusedIdentifierCheck
{
alias visit = UnusedIdentifierCheck.visit;
mixin AnalyzerInfo!"unused_parameter_check";
/**
* Params:
* fileName = the name of the file being analyzed

View File

@ -5,6 +5,7 @@
module dscanner.analysis.unused_variable;
import dparse.ast;
import dscanner.analysis.base;
import dscanner.analysis.unused;
import dsymbol.scope_ : Scope;
import std.algorithm.iteration : map;
@ -16,6 +17,8 @@ final class UnusedVariableCheck : UnusedIdentifierCheck
{
alias visit = UnusedIdentifierCheck.visit;
mixin AnalyzerInfo!"unused_variable_check";
/**
* Params:
* fileName = the name of the file being analyzed

View File

@ -27,6 +27,8 @@ final class UselessAssertCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"useless_assert_check";
///
this(string fileName, bool skipTests = false)
{

View File

@ -29,6 +29,8 @@ final class UselessInitializerChecker : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"useless_initializer";
private:
enum key = "dscanner.useless-initializer";

View File

@ -20,6 +20,8 @@ final class VcallCtorChecker : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"vcall_in_ctor";
private:
enum string KEY = "dscanner.vcall_ctor";