diff --git a/.dscanner.ini b/.dscanner.ini index 5f3682c..d0ff8d7 100644 --- a/.dscanner.ini +++ b/.dscanner.ini @@ -1,5 +1,5 @@ ; Configure which static analysis checks are enabled -[analysis.config.StaticAnalysisConfig] +[dscanner.analysis.config.StaticAnalysisConfig] ; Check variable, class, struct, interface, union, and function names against t ; he Phobos style guide style_check="disabled" diff --git a/.gitignore b/.gitignore index 0f704a4..1d29087 100755 --- a/.gitignore +++ b/.gitignore @@ -15,8 +15,7 @@ .svn/ # D Scanner binaries -dscanner -dscanner.o +/bin # Static analysis reports dscanner-report.json diff --git a/README.md b/README.md index 3440568..ac5044e 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,7 @@ Note that the "--skipTests" option is the equivalent of changing each * Redundant visibility attributes * Public declarations without a documented unittest. By default disabled. * Asserts without an explanatory message. By default disabled. +* Indentation of if constraints #### Wishlist diff --git a/build.bat b/build.bat index 12d11b6..abe613a 100644 --- a/build.bat +++ b/build.bat @@ -17,8 +17,8 @@ set LIBDDOC= set STDXALLOCATOR= set STDXALLOCATORBLOCKS= -for %%x in (src\*.d) do set CORE=!CORE! %%x -for %%x in (src\analysis\*.d) do set ANALYSIS=!ANALYSIS! %%x +for %%x in (src\dscanner\*.d) do set CORE=!CORE! %%x +for %%x in (src\dscanner\analysis\*.d) do set ANALYSIS=!ANALYSIS! %%x for %%x in (libdparse\src\dparse\*.d) do set LIBDPARSE=!LIBDPARSE! %%x for %%x in (libdparse\src\std\experimental\*.d) do set LIBDPARSE=!LIBDPARSE! %%x for %%x in (libddoc\src\ddoc\*.d) do set LIBDDOC=!LIBDDOC! %%x diff --git a/src/analysis/package.d b/src/analysis/package.d deleted file mode 100644 index 225b82e..0000000 --- a/src/analysis/package.d +++ /dev/null @@ -1,6 +0,0 @@ -module analysis; - -public import analysis.style; -public import analysis.enumarrayliteral; -public import analysis.pokemon; -public import analysis.base; diff --git a/src/analysis/alias_syntax_check.d b/src/dscanner/analysis/alias_syntax_check.d similarity index 86% rename from src/analysis/alias_syntax_check.d rename to src/dscanner/analysis/alias_syntax_check.d index 54568d7..515fa34 100644 --- a/src/analysis/alias_syntax_check.d +++ b/src/dscanner/analysis/alias_syntax_check.d @@ -3,11 +3,11 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.alias_syntax_check; +module dscanner.analysis.alias_syntax_check; import dparse.ast; import dparse.lexer; -import analysis.base; +import dscanner.analysis.base; /** * Checks for uses of the old alias syntax. @@ -39,8 +39,8 @@ private: unittest { - import analysis.helpers : assertAnalyzerWarnings; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; import std.stdio : stderr; StaticAnalysisConfig sac = disabledConfig(); diff --git a/src/analysis/allman.d b/src/dscanner/analysis/allman.d similarity index 93% rename from src/analysis/allman.d rename to src/dscanner/analysis/allman.d index fb9c9ec..caf2636 100644 --- a/src/analysis/allman.d +++ b/src/dscanner/analysis/allman.d @@ -2,11 +2,11 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.allman; +module dscanner.analysis.allman; import dparse.lexer; import dparse.ast; -import analysis.base : BaseAnalyzer; +import dscanner.analysis.base : BaseAnalyzer; import dsymbol.scope_ : Scope; import std.algorithm; @@ -65,8 +65,8 @@ class AllManCheck : BaseAnalyzer unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; import std.format : format; import std.stdio : stderr; diff --git a/src/analysis/asm_style.d b/src/dscanner/analysis/asm_style.d similarity index 88% rename from src/analysis/asm_style.d rename to src/dscanner/analysis/asm_style.d index ab4a8c8..30dd495 100644 --- a/src/analysis/asm_style.d +++ b/src/dscanner/analysis/asm_style.d @@ -3,13 +3,13 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.asm_style; +module dscanner.analysis.asm_style; import std.stdio; import dparse.ast; import dparse.lexer; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_ : Scope; /** @@ -39,7 +39,7 @@ class AsmStyleCheck : BaseAnalyzer unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.asm_style_check = Check.enabled; diff --git a/src/analysis/assert_without_msg.d b/src/dscanner/analysis/assert_without_msg.d similarity index 94% rename from src/analysis/assert_without_msg.d rename to src/dscanner/analysis/assert_without_msg.d index 7e43e31..40c4863 100644 --- a/src/analysis/assert_without_msg.d +++ b/src/dscanner/analysis/assert_without_msg.d @@ -2,9 +2,9 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.assert_without_msg; +module dscanner.analysis.assert_without_msg; -import analysis.base : BaseAnalyzer; +import dscanner.analysis.base : BaseAnalyzer; import dsymbol.scope_ : Scope; import dparse.lexer; import dparse.ast; @@ -92,8 +92,8 @@ unittest { import std.stdio : stderr; import std.format : format; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; StaticAnalysisConfig sac = disabledConfig(); sac.assert_without_msg = Check.enabled; diff --git a/src/analysis/auto_function.d b/src/dscanner/analysis/auto_function.d similarity index 95% rename from src/analysis/auto_function.d rename to src/dscanner/analysis/auto_function.d index f41aabf..c1e63e9 100644 --- a/src/analysis/auto_function.d +++ b/src/dscanner/analysis/auto_function.d @@ -3,10 +3,10 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.auto_function; +module dscanner.analysis.auto_function; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dparse.ast; import dparse.lexer; @@ -157,8 +157,8 @@ unittest { import std.stdio : stderr; import std.format : format; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; StaticAnalysisConfig sac = disabledConfig(); sac.auto_function_check = Check.enabled; diff --git a/src/analysis/auto_ref_assignment.d b/src/dscanner/analysis/auto_ref_assignment.d similarity index 92% rename from src/analysis/auto_ref_assignment.d rename to src/dscanner/analysis/auto_ref_assignment.d index 76606f7..96f20c7 100644 --- a/src/analysis/auto_ref_assignment.d +++ b/src/dscanner/analysis/auto_ref_assignment.d @@ -3,11 +3,11 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.auto_ref_assignment; +module dscanner.analysis.auto_ref_assignment; import dparse.lexer; import dparse.ast; -import analysis.base; +import dscanner.analysis.base; /** * Checks for assignment to auto-ref function parameters. @@ -113,8 +113,8 @@ unittest { import std.stdio : stderr; import std.format : format; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; StaticAnalysisConfig sac = disabledConfig(); sac.auto_ref_assignment_check = Check.enabled; diff --git a/src/analysis/base.d b/src/dscanner/analysis/base.d similarity index 98% rename from src/analysis/base.d rename to src/dscanner/analysis/base.d index e0c9f80..01c8be3 100644 --- a/src/analysis/base.d +++ b/src/dscanner/analysis/base.d @@ -1,4 +1,4 @@ -module analysis.base; +module dscanner.analysis.base; import std.container; import std.string; diff --git a/src/analysis/builtin_property_names.d b/src/dscanner/analysis/builtin_property_names.d similarity index 93% rename from src/analysis/builtin_property_names.d rename to src/dscanner/analysis/builtin_property_names.d index ad72a7f..2c49636 100644 --- a/src/analysis/builtin_property_names.d +++ b/src/dscanner/analysis/builtin_property_names.d @@ -3,14 +3,14 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.builtin_property_names; +module dscanner.analysis.builtin_property_names; import std.stdio; import std.regex; import dparse.ast; import dparse.lexer; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_; import std.algorithm : map; @@ -102,7 +102,7 @@ private: unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.builtin_property_names_check = Check.enabled; diff --git a/src/analysis/comma_expression.d b/src/dscanner/analysis/comma_expression.d similarity index 94% rename from src/analysis/comma_expression.d rename to src/dscanner/analysis/comma_expression.d index 846440d..6bdbbfa 100644 --- a/src/analysis/comma_expression.d +++ b/src/dscanner/analysis/comma_expression.d @@ -3,11 +3,11 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.comma_expression; +module dscanner.analysis.comma_expression; import dparse.ast; import dparse.lexer; -import analysis.base; +import dscanner.analysis.base; import dsymbol.scope_; /** diff --git a/src/analysis/config.d b/src/dscanner/analysis/config.d similarity index 98% rename from src/analysis/config.d rename to src/dscanner/analysis/config.d index ebf811b..79e5c99 100644 --- a/src/analysis/config.d +++ b/src/dscanner/analysis/config.d @@ -3,7 +3,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.config; +module dscanner.analysis.config; import inifiled; @@ -192,6 +192,9 @@ struct StaticAnalysisConfig @INI("Check for asserts without an explanatory message") string assert_without_msg = Check.disabled; + @INI("Check indent of if constraints") + string if_constraints_indent = Check.disabled; + @INI("Module-specific filters") ModuleFilters filters; } diff --git a/src/analysis/constructors.d b/src/dscanner/analysis/constructors.d similarity index 93% rename from src/analysis/constructors.d rename to src/dscanner/analysis/constructors.d index ca3b759..961f553 100644 --- a/src/analysis/constructors.d +++ b/src/dscanner/analysis/constructors.d @@ -1,10 +1,10 @@ -module analysis.constructors; +module dscanner.analysis.constructors; import dparse.ast; import dparse.lexer; import std.stdio; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_ : Scope; class ConstructorCheck : BaseAnalyzer @@ -90,7 +90,7 @@ private: unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.constructor_check = Check.enabled; diff --git a/src/analysis/del.d b/src/dscanner/analysis/del.d similarity index 84% rename from src/analysis/del.d rename to src/dscanner/analysis/del.d index 2e66eb3..e73fdb5 100644 --- a/src/analysis/del.d +++ b/src/dscanner/analysis/del.d @@ -3,12 +3,12 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.del; +module dscanner.analysis.del; import std.stdio; import dparse.ast; import dparse.lexer; -import analysis.base; +import dscanner.analysis.base; import dsymbol.scope_; /** @@ -33,8 +33,8 @@ class DeleteCheck : BaseAnalyzer unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; StaticAnalysisConfig sac = disabledConfig(); sac.delete_check = Check.enabled; diff --git a/src/analysis/duplicate_attribute.d b/src/dscanner/analysis/duplicate_attribute.d similarity index 97% rename from src/analysis/duplicate_attribute.d rename to src/dscanner/analysis/duplicate_attribute.d index 887367b..8980c71 100644 --- a/src/analysis/duplicate_attribute.d +++ b/src/dscanner/analysis/duplicate_attribute.d @@ -3,14 +3,14 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.duplicate_attribute; +module dscanner.analysis.duplicate_attribute; import std.stdio; import std.string; import dparse.ast; import dparse.lexer; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_ : Scope; /** @@ -153,7 +153,7 @@ class DuplicateAttributeCheck : BaseAnalyzer unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.duplicate_attribute = Check.enabled; diff --git a/src/analysis/enumarrayliteral.d b/src/dscanner/analysis/enumarrayliteral.d similarity index 95% rename from src/analysis/enumarrayliteral.d rename to src/dscanner/analysis/enumarrayliteral.d index 99933fe..d63bad6 100644 --- a/src/analysis/enumarrayliteral.d +++ b/src/dscanner/analysis/enumarrayliteral.d @@ -3,11 +3,11 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.enumarrayliteral; +module dscanner.analysis.enumarrayliteral; import dparse.ast; import dparse.lexer; -import analysis.base; +import dscanner.analysis.base; import std.algorithm : canFind, map; import dsymbol.scope_ : Scope; diff --git a/src/analysis/explicitly_annotated_unittests.d b/src/dscanner/analysis/explicitly_annotated_unittests.d similarity index 89% rename from src/analysis/explicitly_annotated_unittests.d rename to src/dscanner/analysis/explicitly_annotated_unittests.d index 18009f3..af5d396 100644 --- a/src/analysis/explicitly_annotated_unittests.d +++ b/src/dscanner/analysis/explicitly_annotated_unittests.d @@ -2,11 +2,11 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.explicitly_annotated_unittests; +module dscanner.analysis.explicitly_annotated_unittests; import dparse.lexer; import dparse.ast; -import analysis.base : BaseAnalyzer; +import dscanner.analysis.base : BaseAnalyzer; import std.stdio; @@ -56,8 +56,8 @@ unittest { import std.stdio : stderr; import std.format : format; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; StaticAnalysisConfig sac = disabledConfig(); sac.explicitly_annotated_unittests = Check.enabled; diff --git a/src/analysis/final_attribute.d b/src/dscanner/analysis/final_attribute.d similarity index 97% rename from src/analysis/final_attribute.d rename to src/dscanner/analysis/final_attribute.d index 15de025..f9c9d9a 100644 --- a/src/analysis/final_attribute.d +++ b/src/dscanner/analysis/final_attribute.d @@ -3,10 +3,10 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.final_attribute; +module dscanner.analysis.final_attribute; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dparse.ast; import dparse.lexer; @@ -245,8 +245,8 @@ public: @system unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; import std.stdio : stderr; import std.format : format; diff --git a/src/analysis/fish.d b/src/dscanner/analysis/fish.d similarity index 91% rename from src/analysis/fish.d rename to src/dscanner/analysis/fish.d index 7abdd01..5414cfb 100644 --- a/src/analysis/fish.d +++ b/src/dscanner/analysis/fish.d @@ -3,13 +3,13 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.fish; +module dscanner.analysis.fish; import std.stdio; import dparse.ast; import dparse.lexer; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_ : Scope; /** @@ -42,7 +42,7 @@ class FloatOperatorCheck : BaseAnalyzer unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.float_operator_check = Check.enabled; diff --git a/src/analysis/function_attributes.d b/src/dscanner/analysis/function_attributes.d similarity index 97% rename from src/analysis/function_attributes.d rename to src/dscanner/analysis/function_attributes.d index 871ff4b..855f025 100644 --- a/src/analysis/function_attributes.d +++ b/src/dscanner/analysis/function_attributes.d @@ -3,9 +3,9 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.function_attributes; +module dscanner.analysis.function_attributes; -import analysis.base; +import dscanner.analysis.base; import dparse.ast; import dparse.lexer; import std.stdio; diff --git a/src/analysis/has_public_example.d b/src/dscanner/analysis/has_public_example.d similarity index 96% rename from src/analysis/has_public_example.d rename to src/dscanner/analysis/has_public_example.d index fe21b33..fa9c844 100644 --- a/src/analysis/has_public_example.d +++ b/src/dscanner/analysis/has_public_example.d @@ -2,9 +2,9 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.has_public_example; +module dscanner.analysis.has_public_example; -import analysis.base; +import dscanner.analysis.base; import dsymbol.scope_ : Scope; import dparse.ast; import dparse.lexer; @@ -166,8 +166,8 @@ unittest { import std.stdio : stderr; import std.format : format; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; StaticAnalysisConfig sac = disabledConfig(); sac.has_public_example = Check.enabled; diff --git a/src/analysis/helpers.d b/src/dscanner/analysis/helpers.d similarity index 93% rename from src/analysis/helpers.d rename to src/dscanner/analysis/helpers.d index f379118..98c817b 100644 --- a/src/analysis/helpers.d +++ b/src/dscanner/analysis/helpers.d @@ -3,7 +3,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.helpers; +module dscanner.analysis.helpers; import core.exception : AssertError; import std.string; @@ -13,9 +13,9 @@ import std.stdio; import dparse.ast; import dparse.rollback_allocator; import dsymbol.modulecache : ModuleCache; -import analysis.config; -import analysis.run; -import analysis.base; +import dscanner.analysis.config; +import dscanner.analysis.run; +import dscanner.analysis.base; import stdx.allocator.mallocator; import stdx.allocator; @@ -48,13 +48,13 @@ S after(S)(S value, S separator) if (isSomeString!S) void assertAnalyzerWarnings(string code, const StaticAnalysisConfig config, string file = __FILE__, size_t line = __LINE__) { - import analysis.run : parseModule; + import dscanner.analysis.run : parseModule; import dparse.lexer : StringCache, Token; StringCache cache = StringCache(StringCache.defaultBucketCount); RollbackAllocator r; const(Token)[] tokens; - const(Module) m = parseModule(file, cast(ubyte[]) code, &r, cache, false, tokens); + const(Module) m = parseModule(file, cast(ubyte[]) code, &r, defaultErrorFormat, cache, false, tokens); auto moduleCache = ModuleCache(new CAllocatorImpl!Mallocator); diff --git a/src/dscanner/analysis/if_constraints_indent.d b/src/dscanner/analysis/if_constraints_indent.d new file mode 100644 index 0000000..50eddcc --- /dev/null +++ b/src/dscanner/analysis/if_constraints_indent.d @@ -0,0 +1,233 @@ +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module dscanner.analysis.if_constraints_indent; + +import dparse.lexer; +import dparse.ast; +import dscanner.analysis.base : BaseAnalyzer, Message; +import dsymbol.scope_ : Scope; + +import std.algorithm.iteration : filter; +import std.range; + +/** +Checks whether all if constraints have the same indention as their declaration. +*/ +class IfConstraintsIndentCheck : BaseAnalyzer +{ + /// + this(string fileName, const(Token)[] tokens, bool skipTests = false) + { + super(fileName, null, skipTests); + + // libdparse columns start at 1 + foreach (t; tokens) + { + while (firstSymbolAtLine.length < t.line - 1) + firstSymbolAtLine ~= Pos(1); + + if (firstSymbolAtLine.length < t.line) + firstSymbolAtLine ~= Pos(t.column, t.type == tok!"if"); + } + } + + override void visit(const FunctionDeclaration decl) + { + if (decl.constraint !is null) + checkConstraintSpace(decl.constraint, decl.name); + } + + override void visit(const InterfaceDeclaration decl) + { + if (decl.constraint !is null) + checkConstraintSpace(decl.constraint, decl.name); + } + + + override void visit(const ClassDeclaration decl) + { + if (decl.constraint !is null) + checkConstraintSpace(decl.constraint, decl.name); + } + + override void visit(const TemplateDeclaration decl) + { + if (decl.constraint !is null) + checkConstraintSpace(decl.constraint, decl.name); + } + + override void visit(const UnionDeclaration decl) + { + if (decl.constraint !is null) + checkConstraintSpace(decl.constraint, decl.name); + } + + override void visit(const StructDeclaration decl) + { + if (decl.constraint !is null) + checkConstraintSpace(decl.constraint, decl.name); + } + + override void visit(const Constructor decl) + { + if (decl.constraint !is null) + checkConstraintSpace(decl.constraint, decl.line); + } + + alias visit = ASTVisitor.visit; + +private: + + enum string KEY = "dscanner.style.if_constraints_indent"; + enum string MESSAGE = "If constraints should have the same indentation as the function"; + + Pos[] firstSymbolAtLine; + static struct Pos + { + size_t column; + bool isIf; + } + + /** + Check indentation of constraints + */ + void checkConstraintSpace(const Constraint constraint, const Token token) + { + checkConstraintSpace(constraint, token.line); + } + + void checkConstraintSpace(const Constraint constraint, size_t line) + { + // dscanner lines start at 1 + auto pDecl = firstSymbolAtLine[line - 1]; + + // search for constraint if (might not be on the same line as the expression) + auto r = firstSymbolAtLine[line .. constraint.expression.line].retro.filter!(s => s.isIf); + + // no hit = constraint is on the same line + if (r.empty) + addErrorMessage(constraint.expression.line, constraint.expression.column, KEY, MESSAGE); + else if (pDecl.column != r.front.column) + addErrorMessage(constraint.expression.line, constraint.expression.column, KEY, MESSAGE); + } +} + +unittest +{ + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; + import std.format : format; + import std.stdio : stderr; + + StaticAnalysisConfig sac = disabledConfig(); + sac.if_constraints_indent = Check.enabled; + + assertAnalyzerWarnings(q{ +void foo(R)(R r) +if (R == int) +{} + +void foo(R)(R r) + if (R == int) // [warn]: %s +{} + }c.format( + IfConstraintsIndentCheck.MESSAGE, + ), sac); + + assertAnalyzerWarnings(q{ + void foo(R)(R r) + if (R == int) + {} + + void foo(R)(R r) +if (R == int) // [warn]: %s + {} + + void foo(R)(R r) + if (R == int) // [warn]: %s + {} + }c.format( + IfConstraintsIndentCheck.MESSAGE, + IfConstraintsIndentCheck.MESSAGE, + ), sac); + + assertAnalyzerWarnings(q{ + struct Foo(R) + if (R == int) + {} + + struct Foo(R) +if (R == int) // [warn]: %s + {} + + struct Foo(R) + if (R == int) // [warn]: %s + {} + }c.format( + IfConstraintsIndentCheck.MESSAGE, + IfConstraintsIndentCheck.MESSAGE, + ), sac); + + // test example from Phobos + assertAnalyzerWarnings(q{ +Num abs(Num)(Num x) @safe pure nothrow +if (is(typeof(Num.init >= 0)) && is(typeof(-Num.init)) && + !(is(Num* : const(ifloat*)) || is(Num* : const(idouble*)) + || is(Num* : const(ireal*)))) +{ + static if (isFloatingPoint!(Num)) + return fabs(x); + else + return x >= 0 ? x : -x; +} + }, sac); + + // weird constraint formatting + assertAnalyzerWarnings(q{ + struct Foo(R) + if + (R == int) + {} + + struct Foo(R) + if + (R == int) + {} + + struct Foo(R) +if + (R == int) // [warn]: %s + {} + + struct Foo(R) + if ( + R == int) + {} + + struct Foo(R) + if ( + R == int + ) + {} + + struct Foo(R) + if ( + R == int // [warn]: %s + ) {} + }c.format( + IfConstraintsIndentCheck.MESSAGE, + IfConstraintsIndentCheck.MESSAGE, + ), sac); + + // constraint on the same line + assertAnalyzerWarnings(q{ + struct CRC(uint N, ulong P) if (N == 32 || N == 64) // [warn]: %s + {} + }c.format( + IfConstraintsIndentCheck.MESSAGE, + ), sac); + + stderr.writeln("Unittest for IfConstraintsIndentCheck passed."); +} diff --git a/src/analysis/if_statements.d b/src/dscanner/analysis/if_statements.d similarity index 97% rename from src/analysis/if_statements.d rename to src/dscanner/analysis/if_statements.d index b1ad99f..4b47cd4 100644 --- a/src/analysis/if_statements.d +++ b/src/dscanner/analysis/if_statements.d @@ -2,12 +2,12 @@ // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.if_statements; +module dscanner.analysis.if_statements; import dparse.ast; import dparse.lexer; import dparse.formatter; -import analysis.base; +import dscanner.analysis.base; import dsymbol.scope_ : Scope; class IfStatementCheck : BaseAnalyzer diff --git a/src/analysis/ifelsesame.d b/src/dscanner/analysis/ifelsesame.d similarity index 94% rename from src/analysis/ifelsesame.d rename to src/dscanner/analysis/ifelsesame.d index 5a4bcef..f87fe36 100644 --- a/src/analysis/ifelsesame.d +++ b/src/dscanner/analysis/ifelsesame.d @@ -3,13 +3,13 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.ifelsesame; +module dscanner.analysis.ifelsesame; import std.stdio; import dparse.ast; import dparse.lexer; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_ : Scope; /** @@ -76,7 +76,7 @@ class IfElseSameCheck : BaseAnalyzer unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.if_else_same_check = Check.enabled; diff --git a/src/analysis/imports_sortedness.d b/src/dscanner/analysis/imports_sortedness.d similarity index 96% rename from src/analysis/imports_sortedness.d rename to src/dscanner/analysis/imports_sortedness.d index 0628f06..a889a35 100644 --- a/src/analysis/imports_sortedness.d +++ b/src/dscanner/analysis/imports_sortedness.d @@ -2,9 +2,9 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.imports_sortedness; +module dscanner.analysis.imports_sortedness; -import analysis.base : BaseAnalyzer; +import dscanner.analysis.base : BaseAnalyzer; import dparse.lexer; import dparse.ast; @@ -99,8 +99,8 @@ unittest { import std.stdio : stderr; import std.format : format; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; StaticAnalysisConfig sac = disabledConfig(); sac.imports_sortedness = Check.enabled; diff --git a/src/analysis/incorrect_infinite_range.d b/src/dscanner/analysis/incorrect_infinite_range.d similarity index 92% rename from src/analysis/incorrect_infinite_range.d rename to src/dscanner/analysis/incorrect_infinite_range.d index 6f41b3c..cca0025 100644 --- a/src/analysis/incorrect_infinite_range.d +++ b/src/dscanner/analysis/incorrect_infinite_range.d @@ -3,10 +3,10 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.incorrect_infinite_range; +module dscanner.analysis.incorrect_infinite_range; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dparse.ast; import dparse.lexer; @@ -89,7 +89,7 @@ private: unittest { import std.stdio : stderr; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; import std.format : format; StaticAnalysisConfig sac = disabledConfig(); diff --git a/src/analysis/label_var_same_name_check.d b/src/dscanner/analysis/label_var_same_name_check.d similarity index 96% rename from src/analysis/label_var_same_name_check.d rename to src/dscanner/analysis/label_var_same_name_check.d index 13151ff..1119c9d 100644 --- a/src/analysis/label_var_same_name_check.d +++ b/src/dscanner/analysis/label_var_same_name_check.d @@ -2,13 +2,13 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.label_var_same_name_check; +module dscanner.analysis.label_var_same_name_check; import dparse.ast; import dparse.lexer; import dsymbol.scope_ : Scope; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; /** * Checks for labels and variables that have the same name. @@ -167,7 +167,7 @@ private: unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; import std.stdio : stderr; StaticAnalysisConfig sac = disabledConfig(); diff --git a/src/analysis/lambda_return_check.d b/src/dscanner/analysis/lambda_return_check.d similarity index 91% rename from src/analysis/lambda_return_check.d rename to src/dscanner/analysis/lambda_return_check.d index e85d05b..569a7ad 100644 --- a/src/analysis/lambda_return_check.d +++ b/src/dscanner/analysis/lambda_return_check.d @@ -3,11 +3,11 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.lambda_return_check; +module dscanner.analysis.lambda_return_check; import dparse.ast; import dparse.lexer; -import analysis.base; +import dscanner.analysis.base; class LambdaReturnCheck : BaseAnalyzer { @@ -47,8 +47,8 @@ private: version(Windows) {/*because of newline in code*/} else unittest { - import analysis.helpers : assertAnalyzerWarnings; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; import std.stdio : stderr; StaticAnalysisConfig sac = disabledConfig(); diff --git a/src/analysis/length_subtraction.d b/src/dscanner/analysis/length_subtraction.d similarity index 90% rename from src/analysis/length_subtraction.d rename to src/dscanner/analysis/length_subtraction.d index 0d91a5b..e220373 100644 --- a/src/analysis/length_subtraction.d +++ b/src/dscanner/analysis/length_subtraction.d @@ -3,14 +3,14 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.length_subtraction; +module dscanner.analysis.length_subtraction; import std.stdio; import dparse.ast; import dparse.lexer; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_; /** @@ -58,7 +58,7 @@ class LengthSubtractionCheck : BaseAnalyzer unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.length_subtraction_check = Check.enabled; diff --git a/src/analysis/line_length.d b/src/dscanner/analysis/line_length.d similarity index 96% rename from src/analysis/line_length.d rename to src/dscanner/analysis/line_length.d index d411c71..bab42a8 100644 --- a/src/analysis/line_length.d +++ b/src/dscanner/analysis/line_length.d @@ -3,9 +3,9 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.line_length; +module dscanner.analysis.line_length; -import analysis.base : BaseAnalyzer; +import dscanner.analysis.base : BaseAnalyzer; import dparse.ast; import dparse.lexer; @@ -161,8 +161,8 @@ private: @system unittest { - import analysis.config : Check, StaticAnalysisConfig, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : Check, StaticAnalysisConfig, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; import std.stdio : stderr; StaticAnalysisConfig sac = disabledConfig(); diff --git a/src/analysis/local_imports.d b/src/dscanner/analysis/local_imports.d similarity index 92% rename from src/analysis/local_imports.d rename to src/dscanner/analysis/local_imports.d index 52bece3..cb08333 100644 --- a/src/analysis/local_imports.d +++ b/src/dscanner/analysis/local_imports.d @@ -3,13 +3,13 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.local_imports; +module dscanner.analysis.local_imports; import std.stdio; import dparse.ast; import dparse.lexer; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_; /** @@ -84,7 +84,7 @@ private: unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.local_import_check = Check.enabled; diff --git a/src/analysis/logic_precedence.d b/src/dscanner/analysis/logic_precedence.d similarity index 89% rename from src/analysis/logic_precedence.d rename to src/dscanner/analysis/logic_precedence.d index 7eafbdf..8eac0b7 100644 --- a/src/analysis/logic_precedence.d +++ b/src/dscanner/analysis/logic_precedence.d @@ -3,13 +3,13 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.logic_precedence; +module dscanner.analysis.logic_precedence; import std.stdio; import dparse.ast; import dparse.lexer; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_; /** @@ -48,7 +48,7 @@ class LogicPrecedenceCheck : BaseAnalyzer unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.logical_precedence_check = Check.enabled; diff --git a/src/analysis/mismatched_args.d b/src/dscanner/analysis/mismatched_args.d similarity index 98% rename from src/analysis/mismatched_args.d rename to src/dscanner/analysis/mismatched_args.d index e66f6af..e3e1b37 100644 --- a/src/analysis/mismatched_args.d +++ b/src/dscanner/analysis/mismatched_args.d @@ -1,6 +1,6 @@ -module analysis.mismatched_args; +module dscanner.analysis.mismatched_args; -import analysis.base : BaseAnalyzer; +import dscanner.analysis.base : BaseAnalyzer; import dsymbol.scope_; import dsymbol.symbol; import dparse.ast; diff --git a/src/analysis/numbers.d b/src/dscanner/analysis/numbers.d similarity index 90% rename from src/analysis/numbers.d rename to src/dscanner/analysis/numbers.d index 7c80dde..c20986c 100644 --- a/src/analysis/numbers.d +++ b/src/dscanner/analysis/numbers.d @@ -3,14 +3,14 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.numbers; +module dscanner.analysis.numbers; import std.stdio; import std.regex; import dparse.ast; import dparse.lexer; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_ : Scope; /** @@ -49,7 +49,7 @@ private: unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.number_style_check = Check.enabled; diff --git a/src/analysis/objectconst.d b/src/dscanner/analysis/objectconst.d similarity index 95% rename from src/analysis/objectconst.d rename to src/dscanner/analysis/objectconst.d index 64f4184..51cfcef 100644 --- a/src/analysis/objectconst.d +++ b/src/dscanner/analysis/objectconst.d @@ -3,14 +3,14 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.objectconst; +module dscanner.analysis.objectconst; import std.stdio; import std.regex; import dparse.ast; import dparse.lexer; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_ : Scope; /** @@ -89,7 +89,7 @@ class ObjectConstCheck : BaseAnalyzer unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.object_const_check = Check.enabled; diff --git a/src/analysis/opequals_without_tohash.d b/src/dscanner/analysis/opequals_without_tohash.d similarity index 94% rename from src/analysis/opequals_without_tohash.d rename to src/dscanner/analysis/opequals_without_tohash.d index f0e2fa2..13df894 100644 --- a/src/analysis/opequals_without_tohash.d +++ b/src/dscanner/analysis/opequals_without_tohash.d @@ -3,13 +3,13 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.opequals_without_tohash; +module dscanner.analysis.opequals_without_tohash; import std.stdio; import dparse.ast; import dparse.lexer; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_ : Scope; /** @@ -89,7 +89,7 @@ class OpEqualsWithoutToHashCheck : BaseAnalyzer unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.opequals_tohash_check = Check.enabled; diff --git a/src/dscanner/analysis/package.d b/src/dscanner/analysis/package.d new file mode 100644 index 0000000..ef48b61 --- /dev/null +++ b/src/dscanner/analysis/package.d @@ -0,0 +1,6 @@ +module dscanner.analysis; + +public import dscanner.analysis.style; +public import dscanner.analysis.enumarrayliteral; +public import dscanner.analysis.pokemon; +public import dscanner.analysis.base; diff --git a/src/analysis/pokemon.d b/src/dscanner/analysis/pokemon.d similarity index 93% rename from src/analysis/pokemon.d rename to src/dscanner/analysis/pokemon.d index 1f79d42..3bc5de3 100644 --- a/src/analysis/pokemon.d +++ b/src/dscanner/analysis/pokemon.d @@ -3,13 +3,13 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.pokemon; +module dscanner.analysis.pokemon; import std.stdio; import dparse.ast; import dparse.lexer; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_ : Scope; /** @@ -84,7 +84,7 @@ class PokemonExceptionCheck : BaseAnalyzer unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.exception_check = Check.enabled; diff --git a/src/analysis/properly_documented_public_functions.d b/src/dscanner/analysis/properly_documented_public_functions.d similarity index 98% rename from src/analysis/properly_documented_public_functions.d rename to src/dscanner/analysis/properly_documented_public_functions.d index 6eb8366..7772184 100644 --- a/src/analysis/properly_documented_public_functions.d +++ b/src/dscanner/analysis/properly_documented_public_functions.d @@ -2,11 +2,11 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.properly_documented_public_functions; +module dscanner.analysis.properly_documented_public_functions; import dparse.lexer; import dparse.ast; -import analysis.base : BaseAnalyzer; +import dscanner.analysis.base : BaseAnalyzer; import std.format : format; import std.range.primitives; @@ -286,8 +286,8 @@ version(unittest) { import std.stdio : stderr; import std.format : format; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; } // missing params diff --git a/src/analysis/range.d b/src/dscanner/analysis/range.d similarity index 95% rename from src/analysis/range.d rename to src/dscanner/analysis/range.d index 84ac157..20fc058 100644 --- a/src/analysis/range.d +++ b/src/dscanner/analysis/range.d @@ -3,13 +3,13 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.range; +module dscanner.analysis.range; import std.stdio; import dparse.ast; import dparse.lexer; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dsymbol.scope_ : Scope; /** @@ -158,7 +158,7 @@ private: unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.backwards_range_check = Check.enabled; diff --git a/src/analysis/redundant_attributes.d b/src/dscanner/analysis/redundant_attributes.d similarity index 96% rename from src/analysis/redundant_attributes.d rename to src/dscanner/analysis/redundant_attributes.d index bc3bf2b..7aca111 100644 --- a/src/analysis/redundant_attributes.d +++ b/src/dscanner/analysis/redundant_attributes.d @@ -2,13 +2,13 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.redundant_attributes; +module dscanner.analysis.redundant_attributes; import dparse.ast; import dparse.lexer; import dsymbol.scope_ : Scope; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import std.algorithm; import std.conv : to, text; @@ -178,7 +178,7 @@ private: version(unittest) { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; import std.stdio : stderr; } diff --git a/src/analysis/redundant_parens.d b/src/dscanner/analysis/redundant_parens.d similarity index 95% rename from src/analysis/redundant_parens.d rename to src/dscanner/analysis/redundant_parens.d index 871842e..c4af077 100644 --- a/src/analysis/redundant_parens.d +++ b/src/dscanner/analysis/redundant_parens.d @@ -3,11 +3,11 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.redundant_parens; +module dscanner.analysis.redundant_parens; import dparse.ast; import dparse.lexer; -import analysis.base; +import dscanner.analysis.base; import dsymbol.scope_ : Scope; /** diff --git a/src/analysis/run.d b/src/dscanner/analysis/run.d similarity index 81% rename from src/analysis/run.d rename to src/dscanner/analysis/run.d index b3f13d6..005b288 100644 --- a/src/analysis/run.d +++ b/src/dscanner/analysis/run.d @@ -3,7 +3,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.run; +module dscanner.analysis.run; import std.stdio; import std.array; @@ -23,54 +23,55 @@ import stdx.allocator.mallocator : Mallocator; import stdx.allocator.building_blocks.region : Region; import stdx.allocator.building_blocks.allocator_list : AllocatorList; -import analysis.config; -import analysis.base; -import analysis.style; -import analysis.enumarrayliteral; -import analysis.pokemon; -import analysis.del; -import analysis.fish; -import analysis.numbers; -import analysis.objectconst; -import analysis.range; -import analysis.ifelsesame; -import analysis.constructors; -import analysis.unused; -import analysis.unused_label; -import analysis.duplicate_attribute; -import analysis.opequals_without_tohash; -import analysis.length_subtraction; -import analysis.builtin_property_names; -import analysis.asm_style; -import analysis.logic_precedence; -import analysis.stats_collector; -import analysis.undocumented; -import analysis.comma_expression; -import analysis.function_attributes; -import analysis.local_imports; -import analysis.unmodified; -import analysis.if_statements; -import analysis.redundant_parens; -import analysis.mismatched_args; -import analysis.label_var_same_name_check; -import analysis.line_length; -import analysis.auto_ref_assignment; -import analysis.incorrect_infinite_range; -import analysis.useless_assert; -import analysis.alias_syntax_check; -import analysis.static_if_else; -import analysis.lambda_return_check; -import analysis.auto_function; -import analysis.imports_sortedness; -import analysis.explicitly_annotated_unittests; -import analysis.properly_documented_public_functions; -import analysis.final_attribute; -import analysis.vcall_in_ctor; -import analysis.useless_initializer; -import analysis.allman; -import analysis.redundant_attributes; -import analysis.has_public_example; -import analysis.assert_without_msg; +import dscanner.analysis.config; +import dscanner.analysis.base; +import dscanner.analysis.style; +import dscanner.analysis.enumarrayliteral; +import dscanner.analysis.pokemon; +import dscanner.analysis.del; +import dscanner.analysis.fish; +import dscanner.analysis.numbers; +import dscanner.analysis.objectconst; +import dscanner.analysis.range; +import dscanner.analysis.ifelsesame; +import dscanner.analysis.constructors; +import dscanner.analysis.unused; +import dscanner.analysis.unused_label; +import dscanner.analysis.duplicate_attribute; +import dscanner.analysis.opequals_without_tohash; +import dscanner.analysis.length_subtraction; +import dscanner.analysis.builtin_property_names; +import dscanner.analysis.asm_style; +import dscanner.analysis.logic_precedence; +import dscanner.analysis.stats_collector; +import dscanner.analysis.undocumented; +import dscanner.analysis.comma_expression; +import dscanner.analysis.function_attributes; +import dscanner.analysis.local_imports; +import dscanner.analysis.unmodified; +import dscanner.analysis.if_statements; +import dscanner.analysis.redundant_parens; +import dscanner.analysis.mismatched_args; +import dscanner.analysis.label_var_same_name_check; +import dscanner.analysis.line_length; +import dscanner.analysis.auto_ref_assignment; +import dscanner.analysis.incorrect_infinite_range; +import dscanner.analysis.useless_assert; +import dscanner.analysis.alias_syntax_check; +import dscanner.analysis.static_if_else; +import dscanner.analysis.lambda_return_check; +import dscanner.analysis.auto_function; +import dscanner.analysis.imports_sortedness; +import dscanner.analysis.explicitly_annotated_unittests; +import dscanner.analysis.properly_documented_public_functions; +import dscanner.analysis.final_attribute; +import dscanner.analysis.vcall_in_ctor; +import dscanner.analysis.useless_initializer; +import dscanner.analysis.allman; +import dscanner.analysis.redundant_attributes; +import dscanner.analysis.has_public_example; +import dscanner.analysis.assert_without_msg; +import dscanner.analysis.if_constraints_indent; import dsymbol.string_interning : internString; import dsymbol.scope_; @@ -80,16 +81,31 @@ import dsymbol.conversion.first; import dsymbol.conversion.second; import dsymbol.modulecache : ModuleCache; -import readers; +import dscanner.readers; bool first = true; private alias ASTAllocator = CAllocatorImpl!( AllocatorList!(n => Region!Mallocator(1024 * 128), Mallocator)); +immutable string defaultErrorFormat = "{filepath}({line}:{column})[{type}]: {message}"; + +void messageFunctionFormat(string format, string fileName, size_t line, size_t column, string 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("{type}", isError ? "error" : "warn"); + s = s.replace("{message}", message); + + writefln("%s", s); +} + void messageFunction(string fileName, size_t line, size_t column, string message, bool isError) { - writefln("%s(%d:%d)[%s]: %s", fileName, line, column, isError ? "error" : "warn", message); + messageFunctionFormat(defaultErrorFormat, fileName, line, column, message, isError); } void messageFunctionJSON(string fileName, size_t line, size_t column, string message, bool) @@ -112,10 +128,10 @@ void writeJSON(string key, string fileName, size_t line, size_t column, string m write(" }"); } -bool syntaxCheck(string[] fileNames, ref StringCache stringCache, ref ModuleCache moduleCache) +bool syntaxCheck(string[] fileNames, string errorFormat, ref StringCache stringCache, ref ModuleCache moduleCache) { StaticAnalysisConfig config = defaultStaticAnalysisConfig(); - return analyze(fileNames, config, stringCache, moduleCache, false); + return analyze(fileNames, config, errorFormat, stringCache, moduleCache, false); } void generateReport(string[] fileNames, const StaticAnalysisConfig config, @@ -134,7 +150,7 @@ void generateReport(string[] fileNames, const StaticAnalysisConfig config, continue; RollbackAllocator r; const(Token)[] tokens; - const Module m = parseModule(fileName, code, &r, cache, true, tokens, &lineOfCodeCount); + const Module m = parseModule(fileName, code, &r, defaultErrorFormat, cache, true, tokens, &lineOfCodeCount); stats.visit(m); MessageSet results = analyze(fileName, m, config, moduleCache, tokens, true); foreach (result; results[]) @@ -160,7 +176,7 @@ void generateReport(string[] fileNames, const StaticAnalysisConfig config, * * Returns: true if there were errors or if there were warnings and `staticAnalyze` was true. */ -bool analyze(string[] fileNames, const StaticAnalysisConfig config, +bool analyze(string[] fileNames, const StaticAnalysisConfig config, string errorFormat, ref StringCache cache, ref ModuleCache moduleCache, bool staticAnalyze = true) { bool hasErrors; @@ -174,7 +190,7 @@ bool analyze(string[] fileNames, const StaticAnalysisConfig config, uint errorCount; uint warningCount; const(Token)[] tokens; - const Module m = parseModule(fileName, code, &r, cache, false, tokens, + const Module m = parseModule(fileName, code, &r, errorFormat, cache, false, tokens, null, &errorCount, &warningCount); assert(m); if (errorCount > 0 || (staticAnalyze && warningCount > 0)) @@ -185,18 +201,21 @@ bool analyze(string[] fileNames, const StaticAnalysisConfig config, foreach (result; results[]) { hasErrors = true; - writefln("%s(%d:%d)[warn]: %s", result.fileName, result.line, - result.column, result.message); + messageFunctionFormat(errorFormat, result.fileName, result.line, result.column, result.message, false); } } return hasErrors; } const(Module) parseModule(string fileName, ubyte[] code, RollbackAllocator* p, - ref StringCache cache, bool report, ref const(Token)[] tokens, + string errorFormat, ref StringCache cache, bool report, ref const(Token)[] tokens, ulong* linesOfCode = null, uint* errorCount = null, uint* warningCount = null) { - import stats : isLineOfCode; + 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); + }; LexerConfig config; config.fileName = fileName; @@ -205,7 +224,7 @@ const(Module) parseModule(string fileName, ubyte[] code, RollbackAllocator* p, if (linesOfCode !is null) (*linesOfCode) += count!(a => isLineOfCode(a.type))(tokens); return dparse.parser.parseModule(tokens, fileName, p, - report ? toDelegate(&messageFunctionJSON) : toDelegate(&messageFunction), + report ? toDelegate(&messageFunctionJSON) : writeMessages, errorCount, warningCount); } @@ -488,6 +507,10 @@ MessageSet analyze(string fileName, const Module m, const StaticAnalysisConfig a checks ~= new AssertWithoutMessageCheck(fileName, moduleScope, analysisConfig.assert_without_msg == Check.skipTests && !ut); + if (moduleName.shouldRun!"if_constraints_indent"(analysisConfig)) + checks ~= new IfConstraintsIndentCheck(fileName, tokens, + analysisConfig.if_constraints_indent == Check.skipTests && !ut); + version (none) if (moduleName.shouldRun!"redundant_if_check"(analysisConfig)) checks ~= new IfStatementCheck(fileName, moduleScope, diff --git a/src/analysis/static_if_else.d b/src/dscanner/analysis/static_if_else.d similarity index 90% rename from src/analysis/static_if_else.d rename to src/dscanner/analysis/static_if_else.d index 03caee1..2b29b49 100644 --- a/src/analysis/static_if_else.d +++ b/src/dscanner/analysis/static_if_else.d @@ -3,11 +3,11 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.static_if_else; +module dscanner.analysis.static_if_else; import dparse.ast; import dparse.lexer; -import analysis.base; +import dscanner.analysis.base; /** * Checks for potentially mistaken static if / else if. @@ -65,8 +65,8 @@ class StaticIfElse : BaseAnalyzer unittest { - import analysis.helpers : assertAnalyzerWarnings; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; import std.stdio : stderr; StaticAnalysisConfig sac = disabledConfig(); diff --git a/src/analysis/stats_collector.d b/src/dscanner/analysis/stats_collector.d similarity index 94% rename from src/analysis/stats_collector.d rename to src/dscanner/analysis/stats_collector.d index 120e52e..5056849 100644 --- a/src/analysis/stats_collector.d +++ b/src/dscanner/analysis/stats_collector.d @@ -3,11 +3,11 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.stats_collector; +module dscanner.analysis.stats_collector; import dparse.ast; import dparse.lexer; -import analysis.base; +import dscanner.analysis.base; class StatsCollector : BaseAnalyzer { diff --git a/src/analysis/style.d b/src/dscanner/analysis/style.d similarity index 96% rename from src/analysis/style.d rename to src/dscanner/analysis/style.d index 3e76180..6ab0e9b 100644 --- a/src/analysis/style.d +++ b/src/dscanner/analysis/style.d @@ -3,7 +3,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.style; +module dscanner.analysis.style; import std.stdio; import dparse.ast; @@ -12,8 +12,8 @@ import std.regex; import std.array; import std.conv; import std.format; -import analysis.helpers; -import analysis.base; +import dscanner.analysis.helpers; +import dscanner.analysis.base; import dsymbol.scope_ : Scope; final class StyleChecker : BaseAnalyzer @@ -158,7 +158,7 @@ final class StyleChecker : BaseAnalyzer unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; StaticAnalysisConfig sac = disabledConfig(); sac.style_check = Check.enabled; diff --git a/src/analysis/undocumented.d b/src/dscanner/analysis/undocumented.d similarity index 97% rename from src/analysis/undocumented.d rename to src/dscanner/analysis/undocumented.d index 013e518..1438435 100644 --- a/src/analysis/undocumented.d +++ b/src/dscanner/analysis/undocumented.d @@ -3,9 +3,9 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.undocumented; +module dscanner.analysis.undocumented; -import analysis.base; +import dscanner.analysis.base; import dsymbol.scope_ : Scope; import dparse.ast; import dparse.lexer; @@ -299,8 +299,8 @@ unittest { import std.stdio : stderr; import std.format : format; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; StaticAnalysisConfig sac = disabledConfig(); sac.undocumented_declaration_check = Check.enabled; diff --git a/src/analysis/unmodified.d b/src/dscanner/analysis/unmodified.d similarity index 97% rename from src/analysis/unmodified.d rename to src/dscanner/analysis/unmodified.d index 5d0bb47..01a1c1f 100644 --- a/src/analysis/unmodified.d +++ b/src/dscanner/analysis/unmodified.d @@ -2,9 +2,9 @@ // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.unmodified; +module dscanner.analysis.unmodified; -import analysis.base; +import dscanner.analysis.base; import dsymbol.scope_ : Scope; import std.container; import dparse.ast; @@ -334,8 +334,8 @@ bool isValueTypeSimple(const Type type) pure nothrow @nogc @system unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; import std.stdio : stderr; import std.format : format; diff --git a/src/analysis/unused.d b/src/dscanner/analysis/unused.d similarity index 95% rename from src/analysis/unused.d rename to src/dscanner/analysis/unused.d index 83f0aa2..319639a 100644 --- a/src/analysis/unused.d +++ b/src/dscanner/analysis/unused.d @@ -2,11 +2,11 @@ // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.unused; +module dscanner.analysis.unused; import dparse.ast; import dparse.lexer; -import analysis.base; +import dscanner.analysis.base; import std.container; import std.regex : Regex, regex, matchAll; import dsymbol.scope_ : Scope; @@ -234,11 +234,16 @@ class UnusedVariableCheck : BaseAnalyzer { foreach (part; matchAll(primary.primary.text, re)) { - immutable size_t treeIndex = tree.length - 1; - auto uu = UnUsed(part.hit); - auto r = tree[treeIndex].equalRange(&uu); - if (!r.empty) - r.front.uncertain = true; + void checkTree(in size_t treeIndex) + { + auto uu = UnUsed(part.hit); + auto r = tree[treeIndex].equalRange(&uu); + if (!r.empty) + r.front.uncertain = true; + } + checkTree(tree.length - 1); + if (tree.length >= 2) + checkTree(tree.length - 2); } } } @@ -407,6 +412,8 @@ private: { if (!uu.isRef && tree.length > 1) { + if (uu.uncertain) + continue; immutable string certainty = uu.uncertain ? " might not be used." : " is never used."; immutable string errorMessage = (uu.isParameter ? "Parameter " : "Variable ") @@ -451,8 +458,8 @@ private: @system unittest { import std.stdio : stderr; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; StaticAnalysisConfig sac = disabledConfig(); sac.unused_variable_check = Check.enabled; @@ -526,6 +533,11 @@ private: auto cb2 = delegate(size_t a) {}; // [warn]: Parameter a is never used. cb2(3); } + + bool hasDittos(int decl) + { + mixin("decl++;"); + } }c, sac); stderr.writeln("Unittest for UnusedVariableCheck passed."); diff --git a/src/analysis/unused_label.d b/src/dscanner/analysis/unused_label.d similarity index 96% rename from src/analysis/unused_label.d rename to src/dscanner/analysis/unused_label.d index 7ade5fb..6cad9bc 100644 --- a/src/analysis/unused_label.d +++ b/src/dscanner/analysis/unused_label.d @@ -2,10 +2,10 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.unused_label; +module dscanner.analysis.unused_label; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dparse.ast; import dparse.lexer; import dsymbol.scope_ : Scope; @@ -168,7 +168,7 @@ private: unittest { - import analysis.config : Check, StaticAnalysisConfig, disabledConfig; + import dscanner.analysis.config : Check, StaticAnalysisConfig, disabledConfig; import std.stdio : stderr; StaticAnalysisConfig sac = disabledConfig(); diff --git a/src/analysis/useless_assert.d b/src/dscanner/analysis/useless_assert.d similarity index 93% rename from src/analysis/useless_assert.d rename to src/dscanner/analysis/useless_assert.d index ad61ada..8f173ea 100644 --- a/src/analysis/useless_assert.d +++ b/src/dscanner/analysis/useless_assert.d @@ -3,10 +3,10 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.useless_assert; +module dscanner.analysis.useless_assert; -import analysis.base; -import analysis.helpers; +import dscanner.analysis.base; +import dscanner.analysis.helpers; import dparse.ast; import dparse.lexer; @@ -103,7 +103,7 @@ private: unittest { import std.stdio : stderr; - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; import std.format : format; StaticAnalysisConfig sac = disabledConfig(); diff --git a/src/analysis/useless_initializer.d b/src/dscanner/analysis/useless_initializer.d similarity index 97% rename from src/analysis/useless_initializer.d rename to src/dscanner/analysis/useless_initializer.d index 181ae76..648d995 100644 --- a/src/analysis/useless_initializer.d +++ b/src/dscanner/analysis/useless_initializer.d @@ -2,9 +2,9 @@ // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module analysis.useless_initializer; +module dscanner.analysis.useless_initializer; -import analysis.base; +import dscanner.analysis.base; import containers.dynamicarray; import containers.hashmap; import dparse.ast; @@ -257,8 +257,8 @@ public: @system unittest { - import analysis.config : Check, disabledConfig, StaticAnalysisConfig; - import analysis.helpers: assertAnalyzerWarnings; + import dscanner.analysis.config : Check, disabledConfig, StaticAnalysisConfig; + import dscanner.analysis.helpers: assertAnalyzerWarnings; import std.stdio : stderr; StaticAnalysisConfig sac = disabledConfig; diff --git a/src/analysis/vcall_in_ctor.d b/src/dscanner/analysis/vcall_in_ctor.d similarity index 97% rename from src/analysis/vcall_in_ctor.d rename to src/dscanner/analysis/vcall_in_ctor.d index d2b2ede..753672f 100644 --- a/src/analysis/vcall_in_ctor.d +++ b/src/dscanner/analysis/vcall_in_ctor.d @@ -2,9 +2,9 @@ // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // -module analysis.vcall_in_ctor; +module dscanner.analysis.vcall_in_ctor; -import analysis.base; +import dscanner.analysis.base; import dparse.ast, dparse.lexer; import std.algorithm: among; import std.algorithm.iteration : filter; @@ -279,8 +279,8 @@ public: unittest { - import analysis.config : StaticAnalysisConfig, Check, disabledConfig; - import analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; + import dscanner.analysis.helpers : assertAnalyzerWarnings; import std.stdio : stderr; import std.format : format; diff --git a/src/astprinter.d b/src/dscanner/astprinter.d similarity index 99% rename from src/astprinter.d rename to src/dscanner/astprinter.d index b2cba22..296e1c0 100644 --- a/src/astprinter.d +++ b/src/dscanner/astprinter.d @@ -3,6 +3,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +module dscanner.astprinter; + import dparse.lexer; import dparse.ast; import dparse.formatter; diff --git a/src/ctags.d b/src/dscanner/ctags.d similarity index 99% rename from src/ctags.d rename to src/dscanner/ctags.d index 990e1cc..19bd324 100644 --- a/src/ctags.d +++ b/src/dscanner/ctags.d @@ -3,7 +3,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module ctags; +module dscanner.ctags; import dparse.parser; import dparse.lexer; diff --git a/src/dscanner_version.d b/src/dscanner/dscanner_version.d similarity index 93% rename from src/dscanner_version.d rename to src/dscanner/dscanner_version.d index 1cec8ad..66affd5 100644 --- a/src/dscanner_version.d +++ b/src/dscanner/dscanner_version.d @@ -3,7 +3,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module dscanner_version; +module dscanner.dscanner_version; /** * Human-readable version number diff --git a/src/etags.d b/src/dscanner/etags.d similarity index 99% rename from src/etags.d rename to src/dscanner/etags.d index 56b0ea9..0d8b2ff 100644 --- a/src/etags.d +++ b/src/dscanner/etags.d @@ -4,7 +4,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module etags; +module dscanner.etags; import dparse.parser; import dparse.lexer; diff --git a/src/highlighter.d b/src/dscanner/highlighter.d similarity index 98% rename from src/highlighter.d rename to src/dscanner/highlighter.d index 79ce661..86860cd 100644 --- a/src/highlighter.d +++ b/src/dscanner/highlighter.d @@ -3,7 +3,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module highlighter; +module dscanner.highlighter; import std.stdio; import std.array; diff --git a/src/imports.d b/src/dscanner/imports.d similarity index 98% rename from src/imports.d rename to src/dscanner/imports.d index 6389608..a46b660 100644 --- a/src/imports.d +++ b/src/dscanner/imports.d @@ -3,7 +3,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module imports; +module dscanner.imports; import dparse.ast; import dparse.lexer; @@ -12,7 +12,7 @@ import dparse.rollback_allocator; import std.stdio; import std.container.rbtree; import std.functional : toDelegate; -import readers; +import dscanner.readers; /** * AST visitor that collects modules imported to an R-B tree. diff --git a/src/main.d b/src/dscanner/main.d similarity index 85% rename from src/main.d rename to src/dscanner/main.d index 8f87c4a..2c9271b 100644 --- a/src/main.d +++ b/src/dscanner/main.d @@ -3,7 +3,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module main; +module dscanner.main; import std.algorithm; import std.array; @@ -20,18 +20,18 @@ import dparse.lexer; import dparse.parser; import dparse.rollback_allocator; -import highlighter; -import stats; -import ctags; -import etags; -import astprinter; -import imports; -import outliner; -import symbol_finder; -import analysis.run; -import analysis.config; -import dscanner_version; -import readers; +import dscanner.highlighter; +import dscanner.stats; +import dscanner.ctags; +import dscanner.etags; +import dscanner.astprinter; +import dscanner.imports; +import dscanner.outliner; +import dscanner.symbol_finder; +import dscanner.analysis.run; +import dscanner.analysis.config; +import dscanner.dscanner_version; +import dscanner.readers; import inifiled; @@ -67,6 +67,8 @@ else string[] importPaths; bool printVersion; bool explore; + string errorFormat; + bool patchConfig; try { @@ -94,7 +96,9 @@ else "version", &printVersion, "muffinButton", &muffin, "explore", &explore, - "skipTests", &skipTests); + "skipTests", &skipTests, + "errorFormat|f", &errorFormat, + "patchConfig", &patchConfig); //dfmt on } catch (ConvException e) @@ -141,6 +145,9 @@ else return 0; } + if (!errorFormat.length) + errorFormat = defaultErrorFormat; + const(string[]) absImportPaths = importPaths.map!(a => a.absolutePath() .buildNormalizedPath()).array(); @@ -188,7 +195,7 @@ else if (highlight) { auto tokens = byToken(bytes, config, &cache); - highlighter.highlight(tokens, args.length == 1 ? "stdin" : args[1]); + dscanner.highlighter.highlight(tokens, args.length == 1 ? "stdin" : args[1]); return 0; } else if (tokenDump) @@ -228,17 +235,21 @@ else StaticAnalysisConfig config = defaultStaticAnalysisConfig(); string s = configLocation is null ? getConfigurationLocation() : configLocation; if (s.exists()) + { + if (hasWrongIniFileSection(s, patchConfig)) + return 0; readINIFile(config, s); + } if (skipTests) config.enabled2SkipTests; if (report) generateReport(expandArgs(args), config, cache, moduleCache); else - return analyze(expandArgs(args), config, cache, moduleCache, true) ? 1 : 0; + return analyze(expandArgs(args), config, errorFormat, cache, moduleCache, true) ? 1 : 0; } else if (syntaxCheck) { - return .syntaxCheck(usingStdin ? ["stdin"] : expandArgs(args), cache, moduleCache) ? 1 : 0; + return .syntaxCheck(usingStdin ? ["stdin"] : expandArgs(args), errorFormat, cache, moduleCache) ? 1 : 0; } else { @@ -382,7 +393,10 @@ Options: Generates a default configuration file for the static analysis checks, --skipTests - Does not analyze in the unittests. Only works if --styleCheck.`, + Does not analyze in the unittests. Only works if --styleCheck., + + --patchConfig + Patches the configuration file passed as parameter for v0.5.0.`, programName); } @@ -458,3 +472,41 @@ string getConfigurationLocation() return getDefaultConfigurationLocation(); } + + +/// Patch the INI file to v0.5.0 format. +//TODO: remove this from v0.6.0 +bool hasWrongIniFileSection(string confiFilename, bool patch) +{ + import std.string : indexOf; + import std.array : replace; + + bool result; + + static immutable v1 = "analysis.config.StaticAnalysisConfig"; + static immutable v2 = "dscanner.analysis.config.StaticAnalysisConfig"; + + char[] c = cast(char[]) readFile(confiFilename); + try if (const ptrdiff_t i = c.indexOf(v1)) + { + if (!patch) + { + writeln("warning, the configuration file `", confiFilename, "` contains an outdated property"); + writeln("change manually [", v1, "] to [", v2, "]" ); + writeln("or restart D-Scanner with the `--patchConfig` option"); + result = true; + } + else + { + c = replace(c, v1, v2); + std.file.write(confiFilename, c); + writeln("the configuration file `", confiFilename, "` has been updated correctly"); + } + } + catch(Exception e) + { + stderr.writeln("error encountered when trying to verify the INI file compatibility"); + throw e; + } + return result; +} diff --git a/src/outliner.d b/src/dscanner/outliner.d similarity index 99% rename from src/outliner.d rename to src/dscanner/outliner.d index 8233b6d..3fc0def 100644 --- a/src/outliner.d +++ b/src/dscanner/outliner.d @@ -3,6 +3,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +module dscanner.outliner; + import dparse.lexer; import dparse.ast; import dparse.formatter; diff --git a/src/readers.d b/src/dscanner/readers.d similarity index 98% rename from src/readers.d rename to src/dscanner/readers.d index 1ea8767..931ed17 100644 --- a/src/readers.d +++ b/src/dscanner/readers.d @@ -1,4 +1,4 @@ -module readers; +module dscanner.readers; import std.array : appender, uninitializedArray; import std.stdio : stdin, stderr, File; diff --git a/src/stats.d b/src/dscanner/stats.d similarity index 97% rename from src/stats.d rename to src/dscanner/stats.d index 7247325..af014f4 100644 --- a/src/stats.d +++ b/src/dscanner/stats.d @@ -3,7 +3,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module stats; +module dscanner.stats; import std.stdio; import std.algorithm; diff --git a/src/symbol_finder.d b/src/dscanner/symbol_finder.d similarity index 99% rename from src/symbol_finder.d rename to src/dscanner/symbol_finder.d index e841355..16e2e86 100644 --- a/src/symbol_finder.d +++ b/src/dscanner/symbol_finder.d @@ -3,7 +3,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -module symbol_finder; +module dscanner.symbol_finder; import std.stdio : File; import dparse.lexer;