mirror of
https://github.com/dlang-community/D-Scanner.git
synced 2025-04-26 05:10:03 +03:00
Starting work on 0.3.0
This commit is contained in:
parent
327e629867
commit
a3c4a5384a
35 changed files with 212 additions and 99 deletions
6
.gitmodules
vendored
6
.gitmodules
vendored
|
@ -5,3 +5,9 @@
|
||||||
[submodule "inifiled"]
|
[submodule "inifiled"]
|
||||||
path = inifiled
|
path = inifiled
|
||||||
url = https://github.com/burner/inifiled.git
|
url = https://github.com/burner/inifiled.git
|
||||||
|
[submodule "containers"]
|
||||||
|
path = containers
|
||||||
|
url = https://github.com/economicmodeling/containers.git
|
||||||
|
[submodule "dsymbol"]
|
||||||
|
path = dsymbol
|
||||||
|
url = https://github.com/Hackerpilot/dsymbol.git
|
||||||
|
|
1
containers
Submodule
1
containers
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit d732a67e76f60fd037547c3ffe8776c6deda6bab
|
1
dsymbol
Submodule
1
dsymbol
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit ddf8c97753471388303d64a47bdade85cc4de003
|
|
@ -1 +1 @@
|
||||||
Subproject commit 32f6d638e38888e1bb11cf43e93fe2d11132a98f
|
Subproject commit 0dccfca0e2a132b3c862a62da1c323ccd24e622d
|
17
makefile
17
makefile
|
@ -7,12 +7,21 @@ SRC = src/*.d\
|
||||||
src/analysis/*.d\
|
src/analysis/*.d\
|
||||||
libdparse/src/std/*.d\
|
libdparse/src/std/*.d\
|
||||||
libdparse/src/std/d/*.d\
|
libdparse/src/std/d/*.d\
|
||||||
inifiled/source/*.d
|
inifiled/source/*.d\
|
||||||
INCLUDE_PATHS = -Ilibdparse/src
|
$(shell find dsymbol/src -name "*.d")\
|
||||||
|
containers/src/containers/ttree.d\
|
||||||
|
containers/src/containers/unrolledlist.d\
|
||||||
|
containers/src/containers/hashset.d\
|
||||||
|
containers/src/containers/internal/hash.d\
|
||||||
|
containers/src/containers/internal/node.d\
|
||||||
|
containers/src/containers/internal/storage_type.d\
|
||||||
|
containers/src/memory/allocators.d\
|
||||||
|
containers/src/memory/appender.d
|
||||||
|
INCLUDE_PATHS = -Ilibdparse/src -Idsymbol/src -Icontainers/src
|
||||||
VERSIONS =
|
VERSIONS =
|
||||||
DEBUG_VERSIONS = -version=std_parser_verbose
|
DEBUG_VERSIONS = -version=std_parser_verbose
|
||||||
DMD_FLAGS = -w -O -release -inline
|
#DMD_FLAGS = -w -O -release -inline
|
||||||
#DMD_FLAGS = -w
|
DMD_FLAGS = -w
|
||||||
|
|
||||||
all: dmdbuild
|
all: dmdbuild
|
||||||
ldc: ldcbuild
|
ldc: ldcbuild
|
||||||
|
|
|
@ -10,6 +10,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for confusing asm expressions.
|
* Checks for confusing asm expressions.
|
||||||
|
@ -19,9 +20,9 @@ class AsmStyleCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const AsmBrExp brExp)
|
override void visit(const AsmBrExp brExp)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import std.container;
|
||||||
import std.string;
|
import std.string;
|
||||||
import std.d.ast;
|
import std.d.ast;
|
||||||
import std.array;
|
import std.array;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
struct Message
|
struct Message
|
||||||
{
|
{
|
||||||
|
@ -26,8 +27,9 @@ alias MessageSet = RedBlackTree!(Message, comparitor, true);
|
||||||
abstract class BaseAnalyzer : ASTVisitor
|
abstract class BaseAnalyzer : ASTVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
this(string fileName)
|
this(string fileName, const Scope* sc)
|
||||||
{
|
{
|
||||||
|
this.sc = sc;
|
||||||
this.fileName = fileName;
|
this.fileName = fileName;
|
||||||
_messages = new MessageSet;
|
_messages = new MessageSet;
|
||||||
}
|
}
|
||||||
|
@ -61,6 +63,8 @@ protected:
|
||||||
*/
|
*/
|
||||||
string fileName;
|
string fileName;
|
||||||
|
|
||||||
|
const(Scope)* sc;
|
||||||
|
|
||||||
MessageSet _messages;
|
MessageSet _messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The following code should be killed with fire:
|
* The following code should be killed with fire:
|
||||||
|
@ -29,9 +30,9 @@ class BuiltinPropertyNameCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const FunctionDeclaration fd)
|
override void visit(const FunctionDeclaration fd)
|
||||||
|
|
|
@ -8,6 +8,7 @@ module analysis.comma_expression;
|
||||||
import std.d.ast;
|
import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
|
import dsymbol.scope_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check for uses of the comma expression.
|
* Check for uses of the comma expression.
|
||||||
|
@ -16,9 +17,9 @@ class CommaExpressionCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const Expression ex)
|
override void visit(const Expression ex)
|
||||||
|
|
|
@ -5,15 +5,16 @@ import std.d.lexer;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
|
|
||||||
class ConstructorCheck : BaseAnalyzer
|
class ConstructorCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const ClassDeclaration classDeclaration)
|
override void visit(const ClassDeclaration classDeclaration)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for use of the deprecated 'delete' keyword
|
* Checks for use of the deprecated 'delete' keyword
|
||||||
|
@ -18,9 +19,9 @@ class DeleteCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const DeleteExpression d)
|
override void visit(const DeleteExpression d)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,9 +22,9 @@ class DuplicateAttributeCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const Declaration node)
|
override void visit(const Declaration node)
|
||||||
|
|
|
@ -9,6 +9,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import std.algorithm : canFind;
|
import std.algorithm : canFind;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
void doNothing(string, size_t, size_t, string, bool) {}
|
void doNothing(string, size_t, size_t, string, bool) {}
|
||||||
|
|
||||||
|
@ -16,9 +17,9 @@ class EnumArrayLiteralCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool looking = false;
|
bool looking = false;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for use of the deprecated floating point comparison operators.
|
* Checks for use of the deprecated floating point comparison operators.
|
||||||
|
@ -20,9 +21,9 @@ class FloatOperatorCheck : BaseAnalyzer
|
||||||
|
|
||||||
enum string KEY = "dscanner.deprecated.floating_point_operators";
|
enum string KEY = "dscanner.deprecated.floating_point_operators";
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const RelExpression r)
|
override void visit(const RelExpression r)
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
|
|
||||||
module analysis.function_attributes;
|
module analysis.function_attributes;
|
||||||
|
|
||||||
|
import analysis.base;
|
||||||
import std.d.ast;
|
import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
|
||||||
|
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
|
import dsymbol.scope_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prefer
|
* Prefer
|
||||||
|
@ -25,9 +25,9 @@ class FunctionAttributeCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const InterfaceDeclaration dec)
|
override void visit(const InterfaceDeclaration dec)
|
||||||
|
|
|
@ -8,15 +8,14 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import std.d.formatter;
|
import std.d.formatter;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
class IfStatementCheck : BaseAnalyzer
|
class IfStatementCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
import std.container.binaryheap : heapify;
|
super(fileName, sc);
|
||||||
|
|
||||||
super(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const IfStatement ifStatement)
|
override void visit(const IfStatement ifStatement)
|
||||||
|
|
|
@ -6,12 +6,11 @@
|
||||||
module analysis.ifelsesame;
|
module analysis.ifelsesame;
|
||||||
|
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
|
|
||||||
import std.d.ast;
|
import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for duplicated code in conditional and logical expressions.
|
* Checks for duplicated code in conditional and logical expressions.
|
||||||
|
@ -25,9 +24,9 @@ class IfElseSameCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const IfStatement ifStatement)
|
override void visit(const IfStatement ifStatement)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,9 +21,9 @@ class LengthSubtractionCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const AddExpression addExpression)
|
override void visit(const AddExpression addExpression)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for local imports that import all symbols.
|
* Checks for local imports that import all symbols.
|
||||||
|
@ -22,9 +23,9 @@ class LocalImportCheck : BaseAnalyzer
|
||||||
/**
|
/**
|
||||||
* Construct with the given file name.
|
* Construct with the given file name.
|
||||||
*/
|
*/
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
mixin visitThing!StructBody;
|
mixin visitThing!StructBody;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for code with confusing && and || operator precedence
|
* Checks for code with confusing && and || operator precedence
|
||||||
|
@ -24,9 +25,9 @@ class LogicPrecedenceCheck : BaseAnalyzer
|
||||||
|
|
||||||
enum string KEY = "dscanner.confusing.logical_precedence";
|
enum string KEY = "dscanner.confusing.logical_precedence";
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const OrOrExpression orOr)
|
override void visit(const OrOrExpression orOr)
|
||||||
|
|
56
src/analysis/mismatched_args.d
Normal file
56
src/analysis/mismatched_args.d
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
module analysis.mismatched_args;
|
||||||
|
|
||||||
|
struct ArgMismatch
|
||||||
|
{
|
||||||
|
size_t argIndex;
|
||||||
|
size_t paramIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgMismatch[] compareArgsToParams(const string[] params, const string[] args) pure
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(args.length == params.length);
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
ArgMismatch[] retVal;
|
||||||
|
foreach (i, arg; args)
|
||||||
|
{
|
||||||
|
if (arg is null || arg == params[i])
|
||||||
|
continue;
|
||||||
|
foreach (j, param; params)
|
||||||
|
if (param == arg)
|
||||||
|
retVal ~= ArgMismatch(i, j);
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
string createWarningFromMismatch(ref const ArgMismatch mismatch, const string commonName) pure
|
||||||
|
{
|
||||||
|
import std.format : format;
|
||||||
|
|
||||||
|
return "Argument %d is named '%s', but this is the name of parameter %d".format(
|
||||||
|
mismatch.argIndex + 1, commonName, mismatch.paramIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
{
|
||||||
|
string[] args = ["a", "b", "c"];
|
||||||
|
string[] params = ["a", "b", "c"];
|
||||||
|
immutable res = compareArgsToParams(params, args);
|
||||||
|
assert(res == []);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
string[] args = ["a", "c", "b"];
|
||||||
|
string[] params = ["a", "b", "c"];
|
||||||
|
immutable res = compareArgsToParams(params, args);
|
||||||
|
assert(res == [ArgMismatch(1, 2), ArgMismatch(2, 1)]);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
string[] args = ["a", "c", "b"];
|
||||||
|
string[] params = ["alpha", "bravo", "c"];
|
||||||
|
immutable res = compareArgsToParams(params, args);
|
||||||
|
assert(res == [ArgMismatch(1, 2)]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for long and hard-to-read number literals
|
* Checks for long and hard-to-read number literals
|
||||||
|
@ -23,9 +24,9 @@ public:
|
||||||
/**
|
/**
|
||||||
* Constructs the style checker with the given file name.
|
* Constructs the style checker with the given file name.
|
||||||
*/
|
*/
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const Token t)
|
override void visit(const Token t)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks that opEquals, opCmp, toHash, and toString are either const,
|
* Checks that opEquals, opCmp, toHash, and toString are either const,
|
||||||
|
@ -20,9 +21,9 @@ class ObjectConstCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
mixin visitTemplate!ClassDeclaration;
|
mixin visitTemplate!ClassDeclaration;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for when a class/struct has the method opEquals without toHash, or
|
* Checks for when a class/struct has the method opEquals without toHash, or
|
||||||
|
@ -19,9 +20,9 @@ class OpEqualsWithoutToHashCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const ClassDeclaration node)
|
override void visit(const ClassDeclaration node)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,9 +31,9 @@ class PokemonExceptionCheck : BaseAnalyzer
|
||||||
|
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const LastCatch lc)
|
override void visit(const LastCatch lc)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for .. expressions where the left side is larger than the right. This
|
* Checks for .. expressions where the left side is larger than the right. This
|
||||||
|
@ -26,9 +27,9 @@ class BackwardsRangeCheck : BaseAnalyzer
|
||||||
* Params:
|
* Params:
|
||||||
* fileName = the name of the file being analyzed
|
* fileName = the name of the file being analyzed
|
||||||
*/
|
*/
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const ForeachStatement foreachStatement)
|
override void visit(const ForeachStatement foreachStatement)
|
||||||
|
@ -56,7 +57,7 @@ class BackwardsRangeCheck : BaseAnalyzer
|
||||||
|
|
||||||
override void visit(const AddExpression add)
|
override void visit(const AddExpression add)
|
||||||
{
|
{
|
||||||
auto s = state;
|
immutable s = state;
|
||||||
state = State.ignore;
|
state = State.ignore;
|
||||||
add.accept(this);
|
add.accept(this);
|
||||||
state = s;
|
state = s;
|
||||||
|
|
|
@ -8,14 +8,15 @@ module analysis.redundant_parens;
|
||||||
import std.d.ast;
|
import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
class RedundantParenCheck : BaseAnalyzer
|
class RedundantParenCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const IfStatement statement)
|
override void visit(const IfStatement statement)
|
||||||
|
|
|
@ -14,6 +14,8 @@ import std.array;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import std.d.parser;
|
import std.d.parser;
|
||||||
import std.d.ast;
|
import std.d.ast;
|
||||||
|
import std.allocator : CAllocatorImpl;
|
||||||
|
import std.typecons:scoped;
|
||||||
|
|
||||||
import analysis.config;
|
import analysis.config;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
|
@ -44,6 +46,11 @@ import analysis.unmodified;
|
||||||
import analysis.if_statements;
|
import analysis.if_statements;
|
||||||
import analysis.redundant_parens;
|
import analysis.redundant_parens;
|
||||||
|
|
||||||
|
import memory.allocators:BlockAllocator;
|
||||||
|
|
||||||
|
import dsymbol.scope_;
|
||||||
|
import dsymbol.conversion;
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
void messageFunction(string fileName, size_t line, size_t column, string message,
|
void messageFunction(string fileName, size_t line, size_t column, string message,
|
||||||
|
@ -166,33 +173,36 @@ MessageSet analyze(string fileName, const Module m,
|
||||||
if (!staticAnalyze)
|
if (!staticAnalyze)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
auto allocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024 * 16)))();
|
||||||
|
const(Scope)* moduleScope = generateAutocompleteTrees(m, allocator);
|
||||||
|
|
||||||
BaseAnalyzer[] checks;
|
BaseAnalyzer[] checks;
|
||||||
|
|
||||||
if (analysisConfig.style_check) checks ~= new StyleChecker(fileName);
|
if (analysisConfig.style_check) checks ~= new StyleChecker(fileName, moduleScope);
|
||||||
if (analysisConfig.enum_array_literal_check) checks ~= new EnumArrayLiteralCheck(fileName);
|
if (analysisConfig.enum_array_literal_check) checks ~= new EnumArrayLiteralCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.exception_check) checks ~= new PokemonExceptionCheck(fileName);
|
if (analysisConfig.exception_check) checks ~= new PokemonExceptionCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.delete_check) checks ~= new DeleteCheck(fileName);
|
if (analysisConfig.delete_check) checks ~= new DeleteCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.float_operator_check) checks ~= new FloatOperatorCheck(fileName);
|
if (analysisConfig.float_operator_check) checks ~= new FloatOperatorCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.number_style_check) checks ~= new NumberStyleCheck(fileName);
|
if (analysisConfig.number_style_check) checks ~= new NumberStyleCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.object_const_check) checks ~= new ObjectConstCheck(fileName);
|
if (analysisConfig.object_const_check) checks ~= new ObjectConstCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.backwards_range_check) checks ~= new BackwardsRangeCheck(fileName);
|
if (analysisConfig.backwards_range_check) checks ~= new BackwardsRangeCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.if_else_same_check) checks ~= new IfElseSameCheck(fileName);
|
if (analysisConfig.if_else_same_check) checks ~= new IfElseSameCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.constructor_check) checks ~= new ConstructorCheck(fileName);
|
if (analysisConfig.constructor_check) checks ~= new ConstructorCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.unused_label_check) checks ~= new UnusedLabelCheck(fileName);
|
if (analysisConfig.unused_label_check) checks ~= new UnusedLabelCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.unused_variable_check) checks ~= new UnusedVariableCheck(fileName);
|
if (analysisConfig.unused_variable_check) checks ~= new UnusedVariableCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.duplicate_attribute) checks ~= new DuplicateAttributeCheck(fileName);
|
if (analysisConfig.duplicate_attribute) checks ~= new DuplicateAttributeCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.opequals_tohash_check) checks ~= new OpEqualsWithoutToHashCheck(fileName);
|
if (analysisConfig.opequals_tohash_check) checks ~= new OpEqualsWithoutToHashCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.length_subtraction_check) checks ~= new LengthSubtractionCheck(fileName);
|
if (analysisConfig.length_subtraction_check) checks ~= new LengthSubtractionCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.builtin_property_names_check) checks ~= new BuiltinPropertyNameCheck(fileName);
|
if (analysisConfig.builtin_property_names_check) checks ~= new BuiltinPropertyNameCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.asm_style_check) checks ~= new AsmStyleCheck(fileName);
|
if (analysisConfig.asm_style_check) checks ~= new AsmStyleCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.logical_precedence_check) checks ~= new LogicPrecedenceCheck(fileName);
|
if (analysisConfig.logical_precedence_check) checks ~= new LogicPrecedenceCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.undocumented_declaration_check) checks ~= new UndocumentedDeclarationCheck(fileName);
|
if (analysisConfig.undocumented_declaration_check) checks ~= new UndocumentedDeclarationCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.function_attribute_check) checks ~= new FunctionAttributeCheck(fileName);
|
if (analysisConfig.function_attribute_check) checks ~= new FunctionAttributeCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.comma_expression_check) checks ~= new CommaExpressionCheck(fileName);
|
if (analysisConfig.comma_expression_check) checks ~= new CommaExpressionCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.local_import_check) checks ~= new LocalImportCheck(fileName);
|
if (analysisConfig.local_import_check) checks ~= new LocalImportCheck(fileName, moduleScope);
|
||||||
if (analysisConfig.could_be_immutable_check) checks ~= new UnmodifiedFinder(fileName);
|
if (analysisConfig.could_be_immutable_check) checks ~= new UnmodifiedFinder(fileName, moduleScope);
|
||||||
if (analysisConfig.redundant_parens_check) checks ~= new RedundantParenCheck(fileName);
|
if (analysisConfig.redundant_parens_check) checks ~= new RedundantParenCheck(fileName, moduleScope);
|
||||||
version(none) if (analysisConfig.redundant_if_check) checks ~= new IfStatementCheck(fileName);
|
version(none) if (analysisConfig.redundant_if_check) checks ~= new IfStatementCheck(fileName, moduleScope);
|
||||||
|
|
||||||
foreach (check; checks)
|
foreach (check; checks)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,7 +15,7 @@ class StatsCollector : BaseAnalyzer
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const Statement statement)
|
override void visit(const Statement statement)
|
||||||
|
|
|
@ -13,8 +13,8 @@ import std.array;
|
||||||
import std.conv;
|
import std.conv;
|
||||||
import std.format;
|
import std.format;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
class StyleChecker : BaseAnalyzer
|
class StyleChecker : BaseAnalyzer
|
||||||
{
|
{
|
||||||
|
@ -25,9 +25,9 @@ class StyleChecker : BaseAnalyzer
|
||||||
enum string moduleNameRegex = `^[\p{Ll}_\d]+$`;
|
enum string moduleNameRegex = `^[\p{Ll}_\d]+$`;
|
||||||
enum string KEY = "dscanner.style.phobos_naming_convention";
|
enum string KEY = "dscanner.style.phobos_naming_convention";
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const ModuleDeclaration dec)
|
override void visit(const ModuleDeclaration dec)
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
|
|
||||||
module analysis.undocumented;
|
module analysis.undocumented;
|
||||||
|
|
||||||
|
import analysis.base;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
import std.d.ast;
|
import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
|
||||||
|
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,9 +19,9 @@ class UndocumentedDeclarationCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const Module mod)
|
override void visit(const Module mod)
|
||||||
|
|
|
@ -4,10 +4,11 @@
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
module analysis.unmodified;
|
module analysis.unmodified;
|
||||||
|
|
||||||
|
import analysis.base;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
import std.container;
|
import std.container;
|
||||||
import std.d.ast;
|
import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for variables that could have been declared const or immutable
|
* Checks for variables that could have been declared const or immutable
|
||||||
|
@ -17,9 +18,9 @@ class UnmodifiedFinder:BaseAnalyzer
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
///
|
///
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const Module mod)
|
override void visit(const Module mod)
|
||||||
|
@ -41,7 +42,7 @@ class UnmodifiedFinder:BaseAnalyzer
|
||||||
override void visit(const StructBody structBody)
|
override void visit(const StructBody structBody)
|
||||||
{
|
{
|
||||||
pushScope();
|
pushScope();
|
||||||
auto oldBlockStatementDepth = blockStatementDepth;
|
immutable oldBlockStatementDepth = blockStatementDepth;
|
||||||
blockStatementDepth = 0;
|
blockStatementDepth = 0;
|
||||||
structBody.accept(this);
|
structBody.accept(this);
|
||||||
blockStatementDepth = oldBlockStatementDepth;
|
blockStatementDepth = oldBlockStatementDepth;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import std.container;
|
import std.container;
|
||||||
import std.regex : Regex, regex, matchAll;
|
import std.regex : Regex, regex, matchAll;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for unused variables.
|
* Checks for unused variables.
|
||||||
|
@ -22,9 +23,9 @@ class UnusedVariableCheck : BaseAnalyzer
|
||||||
* Params:
|
* Params:
|
||||||
* fileName = the name of the file being analyzed
|
* fileName = the name of the file being analyzed
|
||||||
*/
|
*/
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
re = regex("[\\p{Alphabetic}_][\\w_]*");
|
re = regex("[\\p{Alphabetic}_][\\w_]*");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,14 +9,15 @@ import std.d.ast;
|
||||||
import std.d.lexer;
|
import std.d.lexer;
|
||||||
import analysis.base;
|
import analysis.base;
|
||||||
import analysis.helpers;
|
import analysis.helpers;
|
||||||
|
import dsymbol.scope_ : Scope;
|
||||||
|
|
||||||
class UnusedLabelCheck : BaseAnalyzer
|
class UnusedLabelCheck : BaseAnalyzer
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
this(string fileName)
|
this(string fileName, const(Scope)* sc)
|
||||||
{
|
{
|
||||||
super(fileName);
|
super(fileName, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct Label
|
static struct Label
|
||||||
|
|
18
src/main.d
18
src/main.d
|
@ -1,4 +1,4 @@
|
||||||
// Copyright Brian Schott (Hackerpilot) 2012.
|
// Copyright Brian Schott (Hackerpilot) 2012-2015.
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
@ -31,6 +31,8 @@ import dscanner_version;
|
||||||
|
|
||||||
import inifiled;
|
import inifiled;
|
||||||
|
|
||||||
|
import dsymbol.modulecache;
|
||||||
|
|
||||||
int main(string[] args)
|
int main(string[] args)
|
||||||
{
|
{
|
||||||
version (unittest)
|
version (unittest)
|
||||||
|
@ -65,6 +67,7 @@ int run(string[] args)
|
||||||
string configLocation;
|
string configLocation;
|
||||||
bool printVersion;
|
bool printVersion;
|
||||||
bool explore;
|
bool explore;
|
||||||
|
string[] importPaths;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -75,7 +78,7 @@ int run(string[] args)
|
||||||
"ast|xml", &ast, "imports|i", &imports, "outline|o", &outline,
|
"ast|xml", &ast, "imports|i", &imports, "outline|o", &outline,
|
||||||
"tokenDump", &tokenDump, "styleCheck|S", &styleCheck,
|
"tokenDump", &tokenDump, "styleCheck|S", &styleCheck,
|
||||||
"defaultConfig", &defaultConfig, "declaration|d", &symbolName,
|
"defaultConfig", &defaultConfig, "declaration|d", &symbolName,
|
||||||
"config", &configLocation, "report", &report,
|
"config", &configLocation, "report", &report, "I", &importPaths,
|
||||||
"version", &printVersion, "muffinButton", &muffin, "explore", &explore);
|
"version", &printVersion, "muffinButton", &muffin, "explore", &explore);
|
||||||
}
|
}
|
||||||
catch (ConvException e)
|
catch (ConvException e)
|
||||||
|
@ -121,7 +124,13 @@ int run(string[] args)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto optionCount = count!"a"([sloc, highlight, ctags, tokenCount,
|
const(string[]) absImportPaths = importPaths.map!(
|
||||||
|
a => a.absolutePath().buildNormalizedPath()).array();
|
||||||
|
|
||||||
|
if (absImportPaths.length)
|
||||||
|
ModuleCache.addImportPaths(absImportPaths);
|
||||||
|
|
||||||
|
immutable optionCount = count!"a"([sloc, highlight, ctags, tokenCount,
|
||||||
syntaxCheck, ast, imports, outline, tokenDump, styleCheck, defaultConfig,
|
syntaxCheck, ast, imports, outline, tokenDump, styleCheck, defaultConfig,
|
||||||
report, symbolName !is null, etags, etagsAll]);
|
report, symbolName !is null, etags, etagsAll]);
|
||||||
if (optionCount > 1)
|
if (optionCount > 1)
|
||||||
|
@ -274,7 +283,6 @@ int run(string[] args)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string[] expandArgs(string[] args)
|
string[] expandArgs(string[] args)
|
||||||
{
|
{
|
||||||
// isFile can throw if it's a broken symlink.
|
// isFile can throw if it's a broken symlink.
|
||||||
|
@ -289,7 +297,7 @@ string[] expandArgs(string[] args)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] rVal;
|
string[] rVal;
|
||||||
if (args.length == 1)
|
if (args.length == 1)
|
||||||
args ~= ".";
|
args ~= ".";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue