Fix #129
This commit is contained in:
parent
9f6688a306
commit
53cff7824e
|
@ -2,3 +2,6 @@
|
|||
path = libdparse
|
||||
url = https://github.com/Hackerpilot/libdparse.git
|
||||
branch = master
|
||||
[submodule "inifiled"]
|
||||
path = inifiled
|
||||
url = https://github.com/burner/inifiled.git
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright Brian Schott (Hackerpilot) 2014.
|
||||
// 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.config;
|
||||
|
||||
import inifiled;
|
||||
|
||||
StaticAnalysisConfig defaultStaticAnalysisConfig()
|
||||
{
|
||||
StaticAnalysisConfig config;
|
||||
foreach (mem; __traits(allMembers, StaticAnalysisConfig))
|
||||
mixin ("config." ~ mem ~ " = true;");
|
||||
return config;
|
||||
}
|
||||
|
||||
@INI("Configurue which static analysis checks are enabled")
|
||||
struct StaticAnalysisConfig
|
||||
{
|
||||
@INI("Check variable, class, struct, interface, union, and function names against the Phobos style guide")
|
||||
bool style_check;
|
||||
|
||||
@INI("Check for array literals that cause unnecessary allocation")
|
||||
bool enum_array_literal_check;
|
||||
|
||||
@INI("Check for poor exception handling practices")
|
||||
bool exception_check;
|
||||
|
||||
@INI("Check for use of the deprecated 'delete' keyword")
|
||||
bool delete_check;
|
||||
|
||||
@INI("Check for use of the deprecated floating point operators")
|
||||
bool float_operator_check;
|
||||
|
||||
@INI("Check number literals for readability")
|
||||
bool number_style_check;
|
||||
|
||||
@INI("Checks that opEquals, opCmp, toHash, and toString are either const, immutable, or inout.")
|
||||
bool object_const_check;
|
||||
|
||||
@INI("Checks for .. expressions where the left side is larger than the right.")
|
||||
bool backwards_range_check;
|
||||
|
||||
@INI("Checks for if statements whose 'then' block is the same as the 'else' block")
|
||||
bool if_else_same_check;
|
||||
|
||||
@INI("Checks for some problems with constructors")
|
||||
bool constructor_check;
|
||||
|
||||
@INI("Checks for unused variables and function parameters")
|
||||
bool unused_variable_check;
|
||||
|
||||
@INI("Checks for duplicate attributes")
|
||||
bool duplicate_attribute;
|
||||
|
||||
@INI("Checks that opEquals and toHash are both defined or neither are defined")
|
||||
bool opequals_tohash_check;
|
||||
}
|
|
@ -90,6 +90,9 @@ private:
|
|||
|
||||
unittest
|
||||
{
|
||||
import analysis.config;
|
||||
StaticAnalysisConfig sac;
|
||||
sac.constructor_check = true;
|
||||
assertAnalyzerWarnings(q{
|
||||
class Cat // [warn]: This class has a zero-argument constructor as well as a constructor with one default argument. This can be confusing.
|
||||
{
|
||||
|
@ -102,7 +105,7 @@ unittest
|
|||
this() {}
|
||||
this(string name = "doggie") {} // [warn]: This struct constructor can never be called with its default argument.
|
||||
}
|
||||
}c, analysis.run.AnalyzerCheck.constructor_check);
|
||||
}c, sac);
|
||||
|
||||
stderr.writeln("Unittest for ConstructorCheck passed.");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright Brian Schott (Sir Alaran) 2014.
|
||||
// Copyright Brian Schott (Hackerpilot) 2014.
|
||||
// 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)
|
||||
|
@ -32,6 +32,9 @@ class DeleteCheck : BaseAnalyzer
|
|||
|
||||
unittest
|
||||
{
|
||||
import analysis.config;
|
||||
StaticAnalysisConfig sac;
|
||||
sac.delete_check = true;
|
||||
assertAnalyzerWarnings(q{
|
||||
void testDelete()
|
||||
{
|
||||
|
@ -41,7 +44,7 @@ unittest
|
|||
auto a = new Class();
|
||||
delete a; // [warn]: Avoid using the 'delete' keyword.
|
||||
}
|
||||
}c, analysis.run.AnalyzerCheck.delete_check);
|
||||
}c, sac);
|
||||
|
||||
stderr.writeln("Unittest for DeleteCheck passed.");
|
||||
}
|
||||
|
|
|
@ -160,6 +160,9 @@ class DuplicateAttributeCheck : BaseAnalyzer
|
|||
|
||||
unittest
|
||||
{
|
||||
import analysis.config;
|
||||
StaticAnalysisConfig sac;
|
||||
sac.duplicate_attribute = true;
|
||||
assertAnalyzerWarnings(q{
|
||||
class ExampleAttributes
|
||||
{
|
||||
|
@ -222,7 +225,7 @@ unittest
|
|||
return false;
|
||||
}
|
||||
}
|
||||
}c, analysis.run.AnalyzerCheck.duplicate_attribute);
|
||||
}c, sac);
|
||||
|
||||
stderr.writeln("Unittest for DuplicateAttributeCheck passed.");
|
||||
}
|
||||
|
|
|
@ -42,6 +42,9 @@ class FloatOperatorCheck : BaseAnalyzer
|
|||
|
||||
unittest
|
||||
{
|
||||
import analysis.config;
|
||||
StaticAnalysisConfig sac;
|
||||
sac.float_operator_check = true;
|
||||
assertAnalyzerWarnings(q{
|
||||
void testFish()
|
||||
{
|
||||
|
@ -56,7 +59,7 @@ unittest
|
|||
a = z !< z; // [warn]: Avoid using the deprecated floating-point operators.
|
||||
a = z !<= z; // [warn]: Avoid using the deprecated floating-point operators.
|
||||
}
|
||||
}c, analysis.run.AnalyzerCheck.float_operator_check);
|
||||
}c, sac);
|
||||
|
||||
stderr.writeln("Unittest for FloatOperatorCheck passed.");
|
||||
}
|
||||
|
|
|
@ -10,10 +10,11 @@ import std.traits;
|
|||
import std.stdio;
|
||||
|
||||
import std.d.ast;
|
||||
import analysis.config;
|
||||
import analysis.run;
|
||||
|
||||
|
||||
S between(S)(S value, S before, S after)
|
||||
S between(S)(S value, S before, S after)
|
||||
if (isSomeString!S)
|
||||
{
|
||||
return value.after(before).before(after);
|
||||
|
@ -48,12 +49,12 @@ S after(S)(S value, S separator)
|
|||
* and make sure they match the warnings in the comments. Warnings are
|
||||
* marked like so: // [warn]: Failed to do somethings.
|
||||
*/
|
||||
void assertAnalyzerWarnings(string code, analysis.run.AnalyzerCheck analyzers, string file=__FILE__, size_t line=__LINE__)
|
||||
void assertAnalyzerWarnings(string code, StaticAnalysisConfig config, string file=__FILE__, size_t line=__LINE__)
|
||||
{
|
||||
import analysis.run;
|
||||
|
||||
// Run the code and get any warnings
|
||||
string[] rawWarnings = analyze("test", cast(ubyte[]) code, analyzers);
|
||||
string[] rawWarnings = analyze("test", cast(ubyte[]) code, config);
|
||||
string[] codeLines = code.split("\n");
|
||||
|
||||
// Get the warnings ordered by line
|
||||
|
|
|
@ -48,6 +48,9 @@ class IfElseSameCheck : BaseAnalyzer
|
|||
|
||||
unittest
|
||||
{
|
||||
import analysis.config;
|
||||
StaticAnalysisConfig sac;
|
||||
sac.if_else_same_check = true;
|
||||
assertAnalyzerWarnings(q{
|
||||
void testSizeT()
|
||||
{
|
||||
|
@ -62,7 +65,7 @@ unittest
|
|||
else
|
||||
person = "bobby"; // not same
|
||||
}
|
||||
}c, analysis.run.AnalyzerCheck.if_else_same_check);
|
||||
}c, sac);
|
||||
stderr.writeln("Unittest for IfElseSameCheck passed.");
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,9 @@ class NumberStyleCheck : BaseAnalyzer
|
|||
|
||||
unittest
|
||||
{
|
||||
import analysis.config;
|
||||
StaticAnalysisConfig sac;
|
||||
sac.number_style_check = true;
|
||||
assertAnalyzerWarnings(q{
|
||||
void testNumbers()
|
||||
{
|
||||
|
@ -54,7 +57,7 @@ unittest
|
|||
a = 100000; // [warn]: Use underscores to improve number constant readability.
|
||||
a = 1000000; // [warn]: Use underscores to improve number constant readability.
|
||||
}
|
||||
}c, analysis.run.AnalyzerCheck.number_style_check);
|
||||
}c, sac);
|
||||
|
||||
stderr.writeln("Unittest for NumberStyleCheck passed.");
|
||||
}
|
||||
|
|
|
@ -71,6 +71,9 @@ class ObjectConstCheck : BaseAnalyzer
|
|||
|
||||
unittest
|
||||
{
|
||||
import analysis.config;
|
||||
StaticAnalysisConfig sac;
|
||||
sac.object_const_check = true;
|
||||
assertAnalyzerWarnings(q{
|
||||
void testConsts()
|
||||
{
|
||||
|
@ -122,7 +125,7 @@ unittest
|
|||
}
|
||||
}
|
||||
}
|
||||
}c, analysis.run.AnalyzerCheck.object_const_check);
|
||||
}c, sac);
|
||||
|
||||
stderr.writeln("Unittest for ObjectConstCheck passed.");
|
||||
}
|
||||
|
|
|
@ -80,6 +80,9 @@ class OpEqualsWithoutToHashCheck : BaseAnalyzer
|
|||
|
||||
unittest
|
||||
{
|
||||
import analysis.config;
|
||||
StaticAnalysisConfig sac;
|
||||
sac.opequals_tohash_check = true;
|
||||
assertAnalyzerWarnings(q{
|
||||
// Success because it has opEquals and toHash
|
||||
class Chimp
|
||||
|
@ -130,7 +133,7 @@ unittest
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
}c, analysis.run.AnalyzerCheck.opequals_tohash_check);
|
||||
}c, sac);
|
||||
|
||||
stderr.writeln("Unittest for OpEqualsWithoutToHashCheck passed.");
|
||||
}
|
||||
|
|
|
@ -66,6 +66,9 @@ class PokemonExceptionCheck : BaseAnalyzer
|
|||
|
||||
unittest
|
||||
{
|
||||
import analysis.config;
|
||||
StaticAnalysisConfig sac;
|
||||
sac.exception_check = true;
|
||||
assertAnalyzerWarnings(q{
|
||||
void testCatch()
|
||||
{
|
||||
|
@ -93,7 +96,7 @@ unittest
|
|||
{
|
||||
}
|
||||
}
|
||||
}c, analysis.run.AnalyzerCheck.exception_check);
|
||||
}c, sac);
|
||||
|
||||
stderr.writeln("Unittest for PokemonExceptionCheck passed.");
|
||||
}
|
||||
|
|
|
@ -131,6 +131,9 @@ class BackwardsRangeCheck : BaseAnalyzer
|
|||
|
||||
unittest
|
||||
{
|
||||
import analysis.config;
|
||||
StaticAnalysisConfig sac;
|
||||
sac.backwards_range_check = true;
|
||||
assertAnalyzerWarnings(q{
|
||||
void testRange()
|
||||
{
|
||||
|
@ -142,7 +145,7 @@ unittest
|
|||
foreach (n; 1 .. 3) { } // ok
|
||||
foreach (n; 3 .. 1) { } // [warn]: 3 is larger than 1. Did you mean to use 'foreach_reverse( ... ; 1 .. 3)'?
|
||||
}
|
||||
}c, analysis.run.AnalyzerCheck.backwards_range_check);
|
||||
}c, sac);
|
||||
|
||||
stderr.writeln("Unittest for BackwardsRangeCheck passed.");
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import std.d.lexer;
|
|||
import std.d.parser;
|
||||
import std.d.ast;
|
||||
|
||||
import analysis.config;
|
||||
import analysis.base;
|
||||
import analysis.style;
|
||||
import analysis.enumarrayliteral;
|
||||
|
@ -25,25 +26,6 @@ import analysis.unused;
|
|||
import analysis.duplicate_attribute;
|
||||
import analysis.opequals_without_tohash;
|
||||
|
||||
enum AnalyzerCheck : uint
|
||||
{
|
||||
none = 0b00000000_00000000,
|
||||
style_check = 0b00000000_00000001,
|
||||
enum_array_literal_check = 0b00000000_00000010,
|
||||
exception_check = 0b00000000_00000100,
|
||||
delete_check = 0b00000000_00001000,
|
||||
float_operator_check = 0b00000000_00010000,
|
||||
number_style_check = 0b00000000_00100000,
|
||||
object_const_check = 0b00000000_01000000,
|
||||
backwards_range_check = 0b00000000_10000000,
|
||||
if_else_same_check = 0b00000001_00000000,
|
||||
constructor_check = 0b00000010_00000000,
|
||||
unused_variable_check = 0b00000100_00000000,
|
||||
duplicate_attribute = 0b00001000_00000000,
|
||||
opequals_tohash_check = 0b00010000_00000000,
|
||||
all = 0b11111111_11111111
|
||||
}
|
||||
|
||||
void messageFunction(string fileName, size_t line, size_t column, string message,
|
||||
bool isError)
|
||||
{
|
||||
|
@ -53,11 +35,12 @@ void messageFunction(string fileName, size_t line, size_t column, string message
|
|||
|
||||
void syntaxCheck(File output, string[] fileNames)
|
||||
{
|
||||
analyze(output, fileNames, AnalyzerCheck.all, false);
|
||||
StaticAnalysisConfig config = defaultStaticAnalysisConfig();
|
||||
analyze(output, fileNames, config, false);
|
||||
}
|
||||
|
||||
// For multiple files
|
||||
void analyze(File output, string[] fileNames, AnalyzerCheck analyzers, bool staticAnalyze = true)
|
||||
void analyze(File output, string[] fileNames, StaticAnalysisConfig config, bool staticAnalyze = true)
|
||||
{
|
||||
foreach (fileName; fileNames)
|
||||
{
|
||||
|
@ -66,14 +49,14 @@ void analyze(File output, string[] fileNames, AnalyzerCheck analyzers, bool stat
|
|||
auto code = uninitializedArray!(ubyte[])(to!size_t(f.size));
|
||||
f.rawRead(code);
|
||||
|
||||
string[] results = analyze(fileName, code, analyzers, staticAnalyze);
|
||||
string[] results = analyze(fileName, code, config, staticAnalyze);
|
||||
if (results.length > 0)
|
||||
output.writeln(results.join("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
// For a string
|
||||
string[] analyze(string fileName, ubyte[] code, AnalyzerCheck analyzers, bool staticAnalyze = true)
|
||||
string[] analyze(string fileName, ubyte[] code, StaticAnalysisConfig analysisConfig, bool staticAnalyze = true)
|
||||
{
|
||||
import std.parallelism;
|
||||
|
||||
|
@ -98,19 +81,19 @@ string[] analyze(string fileName, ubyte[] code, AnalyzerCheck analyzers, bool st
|
|||
|
||||
BaseAnalyzer[] checks;
|
||||
|
||||
if (analyzers & AnalyzerCheck.style_check) checks ~= new StyleChecker(fileName);
|
||||
if (analyzers & AnalyzerCheck.enum_array_literal_check) checks ~= new EnumArrayLiteralCheck(fileName);
|
||||
if (analyzers & AnalyzerCheck.exception_check) checks ~= new PokemonExceptionCheck(fileName);
|
||||
if (analyzers & AnalyzerCheck.delete_check) checks ~= new DeleteCheck(fileName);
|
||||
if (analyzers & AnalyzerCheck.float_operator_check) checks ~= new FloatOperatorCheck(fileName);
|
||||
if (analyzers & AnalyzerCheck.number_style_check) checks ~= new NumberStyleCheck(fileName);
|
||||
if (analyzers & AnalyzerCheck.object_const_check) checks ~= new ObjectConstCheck(fileName);
|
||||
if (analyzers & AnalyzerCheck.backwards_range_check) checks ~= new BackwardsRangeCheck(fileName);
|
||||
if (analyzers & AnalyzerCheck.if_else_same_check) checks ~= new IfElseSameCheck(fileName);
|
||||
if (analyzers & AnalyzerCheck.constructor_check) checks ~= new ConstructorCheck(fileName);
|
||||
if (analyzers & AnalyzerCheck.unused_variable_check) checks ~= new UnusedVariableCheck(fileName);
|
||||
if (analyzers & AnalyzerCheck.duplicate_attribute) checks ~= new DuplicateAttributeCheck(fileName);
|
||||
if (analyzers & AnalyzerCheck.opequals_tohash_check) checks ~= new OpEqualsWithoutToHashCheck(fileName);
|
||||
if (analysisConfig.style_check) checks ~= new StyleChecker(fileName);
|
||||
if (analysisConfig.enum_array_literal_check) checks ~= new EnumArrayLiteralCheck(fileName);
|
||||
if (analysisConfig.exception_check) checks ~= new PokemonExceptionCheck(fileName);
|
||||
if (analysisConfig.delete_check) checks ~= new DeleteCheck(fileName);
|
||||
if (analysisConfig.float_operator_check) checks ~= new FloatOperatorCheck(fileName);
|
||||
if (analysisConfig.number_style_check) checks ~= new NumberStyleCheck(fileName);
|
||||
if (analysisConfig.object_const_check) checks ~= new ObjectConstCheck(fileName);
|
||||
if (analysisConfig.backwards_range_check) checks ~= new BackwardsRangeCheck(fileName);
|
||||
if (analysisConfig.if_else_same_check) checks ~= new IfElseSameCheck(fileName);
|
||||
if (analysisConfig.constructor_check) checks ~= new ConstructorCheck(fileName);
|
||||
if (analysisConfig.unused_variable_check) checks ~= new UnusedVariableCheck(fileName);
|
||||
if (analysisConfig.duplicate_attribute) checks ~= new DuplicateAttributeCheck(fileName);
|
||||
if (analysisConfig.opequals_tohash_check) checks ~= new OpEqualsWithoutToHashCheck(fileName);
|
||||
|
||||
foreach (check; checks)
|
||||
{
|
||||
|
|
|
@ -93,6 +93,10 @@ class StyleChecker : BaseAnalyzer
|
|||
|
||||
unittest
|
||||
{
|
||||
import analysis.config;
|
||||
StaticAnalysisConfig sac;
|
||||
sac.style_check = true;
|
||||
|
||||
assertAnalyzerWarnings(q{
|
||||
module AMODULE; // [warn]: Module/package name 'AMODULE' does not match style guidelines.
|
||||
|
||||
|
@ -105,7 +109,7 @@ unittest
|
|||
interface puma {} // [warn]: Interface name 'puma' does not match style guidelines.
|
||||
struct dog {} // [warn]: Struct name 'dog' does not match style guidelines.
|
||||
enum racoon {} // [warn]: Enum name 'racoon' does not match style guidelines.
|
||||
}c, analysis.run.AnalyzerCheck.style_check);
|
||||
}c, sac);
|
||||
|
||||
stderr.writeln("Unittest for StyleChecker passed.");
|
||||
}
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
set DFLAGS=-version=DIP61 -O -release -inline
|
||||
set DFLAGS=-O -release -inline
|
||||
set CORE=
|
||||
set STD=
|
||||
set STDD=
|
||||
set ANALYSIS=
|
||||
set INIFILED=
|
||||
|
||||
for %%x in (*.d) do set CORE=!CORE! %%x
|
||||
for %%x in (std/*.d) do set STD=!STD! std/%%x
|
||||
for %%x in (std/d/*.d) do set STDD=!STDD! std/d/%%x
|
||||
for %%x in (analysis/*.d) do set ANALYSIS=!ANALYSIS! analysis/%%x
|
||||
for %%x in (inifiled/source/*.d) do set INIFILED=!INIFILED! inifiled/source/%%x
|
||||
|
||||
@echo on
|
||||
dmd %CORE% %STD% %STDD% %ANALYSIS% %DFLAGS% -ofdscanner.exe
|
||||
dmd %CORE% %STD% %STDD% %ANALYSIS% %INIFILED% %DFLAGS% -ofdscanner.exe
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 256db3c28db9e3824b7ed5f646964c19f37dd32d
|
|
@ -1 +1 @@
|
|||
Subproject commit d9387eb3b275295cd0263bdc273c4b0b63f29f98
|
||||
Subproject commit 4b95000c560b945ed8d426553c4d71849875cc92
|
95
main.d
95
main.d
|
@ -24,6 +24,9 @@ import astprinter;
|
|||
import imports;
|
||||
import outliner;
|
||||
import analysis.run;
|
||||
import analysis.config;
|
||||
|
||||
import inifiled;
|
||||
|
||||
int main(string[] args)
|
||||
{
|
||||
|
@ -52,6 +55,7 @@ int run(string[] args)
|
|||
bool outline;
|
||||
bool tokenDump;
|
||||
bool styleCheck;
|
||||
bool defaultConfig;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -60,7 +64,7 @@ int run(string[] args)
|
|||
"tokenCount|t", &tokenCount, "syntaxCheck|s", &syntaxCheck,
|
||||
"ast|xml", &ast, "imports|i", &imports, "outline|o", &outline,
|
||||
"tokenDump", &tokenDump, "styleCheck", &styleCheck,
|
||||
"muffinButton", &muffin);
|
||||
"defaultConfig", &defaultConfig, "muffinButton", &muffin);
|
||||
}
|
||||
catch (ConvException e)
|
||||
{
|
||||
|
@ -90,7 +94,7 @@ int run(string[] args)
|
|||
}
|
||||
|
||||
auto optionCount = count!"a"([sloc, highlight, ctags, tokenCount,
|
||||
syntaxCheck, ast, imports, outline, tokenDump, styleCheck]);
|
||||
syntaxCheck, ast, imports, outline, tokenDump, styleCheck, defaultConfig]);
|
||||
if (optionCount > 1)
|
||||
{
|
||||
stderr.writeln("Too many options specified");
|
||||
|
@ -103,8 +107,14 @@ int run(string[] args)
|
|||
}
|
||||
|
||||
StringCache cache = StringCache(StringCache.defaultBucketCount);
|
||||
|
||||
if (tokenDump || highlight)
|
||||
if (defaultConfig)
|
||||
{
|
||||
string s = getConfigurationLocation();
|
||||
StaticAnalysisConfig saConfig = defaultStaticAnalysisConfig();
|
||||
writeln("Writing default config file to ", s);
|
||||
writeINIFile(saConfig, s);
|
||||
}
|
||||
else if (tokenDump || highlight)
|
||||
{
|
||||
bool usingStdin = args.length == 1;
|
||||
ubyte[] bytes = usingStdin ? readStdin() : readFile(args[1]);
|
||||
|
@ -133,7 +143,11 @@ int run(string[] args)
|
|||
}
|
||||
else if (styleCheck)
|
||||
{
|
||||
stdout.analyze(expandArgs(args, recursive), AnalyzerCheck.all);
|
||||
StaticAnalysisConfig config = defaultStaticAnalysisConfig();
|
||||
string s = getConfigurationLocation();
|
||||
if (s.exists())
|
||||
readINIFile(config, s);
|
||||
stdout.analyze(expandArgs(args, recursive), config);
|
||||
}
|
||||
else if (syntaxCheck)
|
||||
{
|
||||
|
@ -171,7 +185,25 @@ int run(string[] args)
|
|||
writefln("total:\t%d", count);
|
||||
}
|
||||
}
|
||||
else if (imports || ast || outline)
|
||||
else if (imports)
|
||||
{
|
||||
string[] fileNames = usingStdin ? ["stdin"] : args[1 .. $];
|
||||
LexerConfig config;
|
||||
config.stringBehavior = StringBehavior.source;
|
||||
auto visitor = new ImportPrinter;
|
||||
foreach (name; fileNames)
|
||||
{
|
||||
config.fileName = name;
|
||||
auto tokens = getTokensForParser(
|
||||
usingStdin ? readStdin() : readFile(name),
|
||||
config, &cache);
|
||||
auto mod = parseModule(tokens, name, null, &doNothing);
|
||||
visitor.visit(mod);
|
||||
}
|
||||
foreach (imp; visitor.imports[])
|
||||
writeln(imp);
|
||||
}
|
||||
else if (ast || outline)
|
||||
{
|
||||
string fileName = usingStdin ? "stdin" : args[1];
|
||||
LexerConfig config;
|
||||
|
@ -187,14 +219,8 @@ int run(string[] args)
|
|||
// token.text !is null, token.index, token.line, token.column, token.type, token.comment);
|
||||
// }
|
||||
auto mod = parseModule(tokens, fileName, null, &doNothing);
|
||||
if (imports)
|
||||
{
|
||||
auto visitor = new ImportPrinter;
|
||||
visitor.visit(mod);
|
||||
foreach (imp; visitor.imports[])
|
||||
writeln(imp);
|
||||
}
|
||||
else if (ast)
|
||||
|
||||
if (ast)
|
||||
{
|
||||
auto printer = new XMLPrinter;
|
||||
printer.output = stdout;
|
||||
|
@ -294,7 +320,7 @@ options:
|
|||
|
||||
--styleCheck [sourceFiles]
|
||||
Lexes and parses sourceFiles, printing the line and column number of any
|
||||
style guideline violations to stdout.
|
||||
static analysis check failures stdout.
|
||||
|
||||
--ctags | -c sourceFile
|
||||
Generates ctags information from the given source code file. Note that
|
||||
|
@ -308,8 +334,45 @@ options:
|
|||
--recursive | -R | -r
|
||||
When used with --ctags, --tokenCount, or --sloc, dscanner will produce
|
||||
ctags output for all .d and .di files contained within the given
|
||||
directories and its sub-directories.`,
|
||||
directories and its sub-directories.
|
||||
|
||||
--defaultConfig
|
||||
Generates a default configuration file for the static analysis checks`,
|
||||
programName);
|
||||
}
|
||||
|
||||
void doNothing(string, size_t, size_t, string, bool) {}
|
||||
|
||||
enum CONFIG_FILE_NAME = "dscanner.ini";
|
||||
version(linux) version = useXDG;
|
||||
version(BSD) version = useXDG;
|
||||
version(FreeBSD) version = useXDG;
|
||||
version(OSX) version = useXDG;
|
||||
|
||||
/**
|
||||
* Locates the configuration file
|
||||
*/
|
||||
string getConfigurationLocation()
|
||||
{
|
||||
version (useXDG)
|
||||
{
|
||||
import std.process;
|
||||
string configDir = environment.get("XDG_CONFIG_HOME", null);
|
||||
if (configDir is null)
|
||||
{
|
||||
configDir = environment.get("HOME", null);
|
||||
if (configDir is null)
|
||||
throw new Exception("Both $XDG_CONFIG_HOME and $HOME are unset");
|
||||
configDir = buildPath(configDir, ".config", "dscanner", CONFIG_FILE_NAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
configDir = buildPath(configDir, "dscanner", CONFIG_FILE_NAME);
|
||||
}
|
||||
return configDir;
|
||||
}
|
||||
else version(Windows)
|
||||
{
|
||||
return CONFIG_FILE_NAME;
|
||||
}
|
||||
}
|
||||
|
|
5
makefile
5
makefile
|
@ -12,9 +12,10 @@ SRC = main.d\
|
|||
outliner.d\
|
||||
libdparse/src/std/*.d\
|
||||
libdparse/src/std/d/*.d\
|
||||
analysis/*.d
|
||||
analysis/*.d\
|
||||
inifiled/source/*.d
|
||||
INCLUDE_PATHS = -Ilibdparse/src
|
||||
VERSIONS = -version=DIP61
|
||||
VERSIONS =
|
||||
|
||||
all: dmdbuild
|
||||
|
||||
|
|
Loading…
Reference in New Issue