Merge branch 'master' of https://github.com/Hackerpilot/Dscanner
This commit is contained in:
commit
ba70f0e9dd
|
@ -1 +1 @@
|
|||
Subproject commit 32f6d638e38888e1bb11cf43e93fe2d11132a98f
|
||||
Subproject commit bd7c1c2dbb08bf160c4b646e0aede2af1ef6e0e4
|
|
@ -92,4 +92,7 @@ struct StaticAnalysisConfig
|
|||
|
||||
@INI("Checks for redundant parenthesis")
|
||||
bool redundant_parens_check;
|
||||
|
||||
@INI("Checks for labels with the same name as variables")
|
||||
bool label_var_same_name_check;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
// 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.label_var_same_name_check;
|
||||
|
||||
import std.d.ast;
|
||||
import std.d.lexer;
|
||||
|
||||
import analysis.base;
|
||||
import analysis.helpers;
|
||||
|
||||
/**
|
||||
* Checks for labels and variables that have the same name.
|
||||
*/
|
||||
class LabelVarNameCheck : BaseAnalyzer
|
||||
{
|
||||
this(string fileName)
|
||||
{
|
||||
super(fileName);
|
||||
}
|
||||
|
||||
override void visit(const Module mod)
|
||||
{
|
||||
pushScope();
|
||||
mod.accept(this);
|
||||
popScope();
|
||||
}
|
||||
|
||||
override void visit(const BlockStatement block)
|
||||
{
|
||||
pushScope();
|
||||
block.accept(this);
|
||||
popScope();
|
||||
}
|
||||
|
||||
override void visit(const StructBody structBody)
|
||||
{
|
||||
pushScope();
|
||||
structBody.accept(this);
|
||||
popScope();
|
||||
}
|
||||
|
||||
override void visit(const VariableDeclaration var)
|
||||
{
|
||||
foreach (dec; var.declarators)
|
||||
duplicateCheck(dec.name, false);
|
||||
}
|
||||
|
||||
override void visit(const LabeledStatement labeledStatement)
|
||||
{
|
||||
duplicateCheck(labeledStatement.identifier, true);
|
||||
if (labeledStatement.declarationOrStatement !is null)
|
||||
labeledStatement.declarationOrStatement.accept(this);
|
||||
}
|
||||
|
||||
alias visit = BaseAnalyzer.visit;
|
||||
|
||||
private:
|
||||
|
||||
Thing[string][] stack;
|
||||
|
||||
void duplicateCheck(const Token name, bool fromLabel)
|
||||
{
|
||||
import std.conv : to;
|
||||
const(Thing)* thing = name.text in currentScope;
|
||||
if (thing is null)
|
||||
currentScope[name.text] = Thing(name.text, name.line, name.column, false);
|
||||
else
|
||||
{
|
||||
immutable thisKind = fromLabel ? "Label" : "Variable";
|
||||
immutable otherKind = thing.isVar ? "variable" : "label";
|
||||
addErrorMessage(name.line, name.column, "dscanner.suspicious.label_var_same_name",
|
||||
thisKind ~ " \"" ~ name.text ~ "\" has the same name as a "
|
||||
~ otherKind ~ " defined on line " ~ to!string(thing.line) ~ ".");
|
||||
}
|
||||
}
|
||||
|
||||
static struct Thing
|
||||
{
|
||||
string name;
|
||||
size_t line;
|
||||
size_t column;
|
||||
bool isVar;
|
||||
}
|
||||
|
||||
ref currentScope() @property
|
||||
{
|
||||
return stack[$-1];
|
||||
}
|
||||
|
||||
void pushScope()
|
||||
{
|
||||
stack.length++;
|
||||
}
|
||||
|
||||
void popScope()
|
||||
{
|
||||
stack.length--;
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
import analysis.config : StaticAnalysisConfig;
|
||||
import std.stdio : stderr;
|
||||
|
||||
StaticAnalysisConfig sac;
|
||||
sac.label_var_same_name_check = true;
|
||||
assertAnalyzerWarnings(q{
|
||||
unittest
|
||||
{
|
||||
blah:
|
||||
int blah; // [warn]: Variable "blah" has the same name as a label defined on line 4.
|
||||
}
|
||||
int blah;
|
||||
}c, sac);
|
||||
stderr.writeln("Unittest for LabelVarNameCheck passed.");
|
||||
}
|
|
@ -43,6 +43,7 @@ import analysis.local_imports;
|
|||
import analysis.unmodified;
|
||||
import analysis.if_statements;
|
||||
import analysis.redundant_parens;
|
||||
import analysis.label_var_same_name_check;
|
||||
|
||||
bool first = true;
|
||||
|
||||
|
@ -115,8 +116,11 @@ void generateReport(string[] fileNames, const StaticAnalysisConfig config)
|
|||
writeln("}");
|
||||
}
|
||||
|
||||
/// For multiple files
|
||||
/// Returns: true if there were errors
|
||||
/**
|
||||
* For multiple files
|
||||
*
|
||||
* Returns: true if there were errors or if there were warnings and `staticAnalyze` was true.
|
||||
*/
|
||||
bool analyze(string[] fileNames, const StaticAnalysisConfig config, bool staticAnalyze = true)
|
||||
{
|
||||
bool hasErrors = false;
|
||||
|
@ -129,10 +133,11 @@ bool analyze(string[] fileNames, const StaticAnalysisConfig config, bool staticA
|
|||
ParseAllocator p = new ParseAllocator;
|
||||
StringCache cache = StringCache(StringCache.defaultBucketCount);
|
||||
uint errorCount = 0;
|
||||
uint warningCount = 0;
|
||||
const Module m = parseModule(fileName, code, p, cache, false, null,
|
||||
&errorCount, null);
|
||||
&errorCount, &warningCount);
|
||||
assert (m);
|
||||
if (errorCount > 0)
|
||||
if (errorCount > 0 || (staticAnalyze && warningCount > 0))
|
||||
hasErrors = true;
|
||||
MessageSet results = analyze(fileName, m, config, staticAnalyze);
|
||||
if (results is null)
|
||||
|
@ -192,6 +197,7 @@ MessageSet analyze(string fileName, const Module m,
|
|||
if (analysisConfig.local_import_check) checks ~= new LocalImportCheck(fileName);
|
||||
if (analysisConfig.could_be_immutable_check) checks ~= new UnmodifiedFinder(fileName);
|
||||
if (analysisConfig.redundant_parens_check) checks ~= new RedundantParenCheck(fileName);
|
||||
if (analysisConfig.label_var_same_name_check) checks ~= new LabelVarNameCheck(fileName);
|
||||
version(none) if (analysisConfig.redundant_if_check) checks ~= new IfStatementCheck(fileName);
|
||||
|
||||
foreach (check; checks)
|
||||
|
|
|
@ -9,6 +9,7 @@ import std.d.ast;
|
|||
import std.d.lexer;
|
||||
import analysis.base;
|
||||
|
||||
import std.regex : ctRegex, matchAll;
|
||||
import std.stdio;
|
||||
|
||||
/**
|
||||
|
@ -38,13 +39,19 @@ class UndocumentedDeclarationCheck : BaseAnalyzer
|
|||
if (isProtection(attr.attribute.type))
|
||||
set(attr.attribute.type);
|
||||
else if (attr.attribute == tok!"override")
|
||||
{
|
||||
setOverride(true);
|
||||
}
|
||||
else if (attr.deprecated_ !is null)
|
||||
setDeprecated(true);
|
||||
else if (attr.atAttribute !is null && attr.atAttribute.identifier.text == "disable")
|
||||
setDisabled(true);
|
||||
}
|
||||
|
||||
immutable bool shouldPop = dec.attributeDeclaration is null;
|
||||
immutable bool prevOverride = getOverride();
|
||||
immutable bool prevDisabled = getDisabled();
|
||||
immutable bool prevDeprecated = getDeprecated();
|
||||
bool dis = false;
|
||||
bool dep = false;
|
||||
bool ovr = false;
|
||||
bool pushed = false;
|
||||
foreach (attribute; dec.attributes)
|
||||
|
@ -61,14 +68,26 @@ class UndocumentedDeclarationCheck : BaseAnalyzer
|
|||
}
|
||||
else if (attribute.attribute == tok!"override")
|
||||
ovr = true;
|
||||
else if (attribute.deprecated_ !is null)
|
||||
dep = true;
|
||||
else if (attribute.atAttribute !is null && attribute.atAttribute.identifier.text == "disable")
|
||||
dis = true;
|
||||
}
|
||||
if (ovr)
|
||||
setOverride(true);
|
||||
if (dis)
|
||||
setDisabled(true);
|
||||
if (dep)
|
||||
setDeprecated(true);
|
||||
dec.accept(this);
|
||||
if (shouldPop && pushed)
|
||||
pop();
|
||||
if (ovr)
|
||||
setOverride(prevOverride);
|
||||
if (dis)
|
||||
setDisabled(prevDisabled);
|
||||
if (dep)
|
||||
setDeprecated(prevDeprecated);
|
||||
}
|
||||
|
||||
override void visit(const VariableDeclaration variable)
|
||||
|
@ -92,7 +111,7 @@ class UndocumentedDeclarationCheck : BaseAnalyzer
|
|||
override void visit(const ConditionalDeclaration cond)
|
||||
{
|
||||
const VersionCondition ver = cond.compileCondition.versionCondition;
|
||||
if (ver is null || ver.token != tok!"unittest" && ver.token.text != "none")
|
||||
if ((ver is null || ver.token != tok!"unittest") && ver.token.text != "none")
|
||||
cond.accept(this);
|
||||
else if (cond.falseDeclaration !is null)
|
||||
visit(cond.falseDeclaration);
|
||||
|
@ -100,6 +119,7 @@ class UndocumentedDeclarationCheck : BaseAnalyzer
|
|||
|
||||
override void visit(const FunctionBody fb) {}
|
||||
override void visit(const Unittest u) {}
|
||||
override void visit(const TraitsExpression t) {}
|
||||
|
||||
mixin V!ClassDeclaration;
|
||||
mixin V!InterfaceDeclaration;
|
||||
|
@ -156,8 +176,7 @@ private:
|
|||
|
||||
static bool isGetterOrSetter(string name)
|
||||
{
|
||||
import std.algorithm:startsWith;
|
||||
return name.startsWith("get") || name.startsWith("set");
|
||||
return !matchAll(name, getSetRe).empty;
|
||||
}
|
||||
|
||||
static bool isProperty(const FunctionDeclaration dec)
|
||||
|
@ -190,9 +209,30 @@ private:
|
|||
stack[$ - 1].isOverride = o;
|
||||
}
|
||||
|
||||
bool getDisabled()
|
||||
{
|
||||
return stack[$ - 1].isDisabled;
|
||||
}
|
||||
|
||||
void setDisabled(bool d = true)
|
||||
{
|
||||
stack[$ - 1].isDisabled = d;
|
||||
}
|
||||
|
||||
bool getDeprecated()
|
||||
{
|
||||
return stack[$ - 1].isDeprecated;
|
||||
}
|
||||
|
||||
void setDeprecated(bool d = true)
|
||||
{
|
||||
stack[$ - 1].isDeprecated = d;
|
||||
}
|
||||
|
||||
bool currentIsInteresting()
|
||||
{
|
||||
return stack[$ - 1].protection == tok!"public" && !(stack[$ - 1].isOverride);
|
||||
return stack[$ - 1].protection == tok!"public" && !stack[$ - 1].isOverride
|
||||
&& !stack[$ - 1].isDisabled && !stack[$ - 1].isDeprecated;
|
||||
}
|
||||
|
||||
void set(IdType p)
|
||||
|
@ -219,6 +259,8 @@ private:
|
|||
{
|
||||
IdType protection;
|
||||
bool isOverride;
|
||||
bool isDeprecated;
|
||||
bool isDisabled;
|
||||
}
|
||||
|
||||
ProtectionInfo[] stack;
|
||||
|
@ -232,3 +274,5 @@ private immutable string[] ignoredFunctionNames = [
|
|||
"toHash",
|
||||
"main"
|
||||
];
|
||||
|
||||
private enum getSetRe = ctRegex!`^(?:get|set)(?:\p{Lu}|_).*`;
|
||||
|
|
|
@ -153,6 +153,11 @@ class UnmodifiedFinder:BaseAnalyzer
|
|||
foreachStatement.declarationOrStatement.accept(this);
|
||||
}
|
||||
|
||||
override void visit(const TraitsExpression)
|
||||
{
|
||||
// Issue #266. Ignore everything inside of __traits expressions.
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template PartsMightModify(T)
|
||||
|
|
|
@ -277,7 +277,6 @@ class UnusedVariableCheck : BaseAnalyzer
|
|||
import std.array : array;
|
||||
if (parameter.name != tok!"")
|
||||
{
|
||||
// stderr.writeln("Adding parameter ", parameter.name.text);
|
||||
immutable bool isRef = canFind(parameter.parameterAttributes, cast(IdType) tok!"ref")
|
||||
|| canFind(parameter.parameterAttributes, cast(IdType) tok!"in")
|
||||
|| canFind(parameter.parameterAttributes, cast(IdType) tok!"out");
|
||||
|
@ -317,6 +316,11 @@ class UnusedVariableCheck : BaseAnalyzer
|
|||
variableUsed(primary.identifierChain.identifiers[0].text);
|
||||
}
|
||||
|
||||
override void visit(const TraitsExpression)
|
||||
{
|
||||
// Issue #266. Ignore everything inside of __traits expressions.
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
mixin template PartsUseVariables(NodeType)
|
||||
|
@ -334,13 +338,11 @@ private:
|
|||
{
|
||||
if (inAggregateScope)
|
||||
return;
|
||||
// stderr.writeln("Adding ", name, " ", isParameter, " ", isRef);
|
||||
tree[$ - 1].insert(new UnUsed(name, line, column, isParameter, isRef));
|
||||
}
|
||||
|
||||
void variableUsed(string name)
|
||||
{
|
||||
// writeln("Marking ", name, " used");
|
||||
size_t treeIndex = tree.length - 1;
|
||||
auto uu = UnUsed(name);
|
||||
while (true)
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
module analysis.unused_label;
|
||||
|
||||
import std.stdio;
|
||||
import std.d.ast;
|
||||
import std.d.lexer;
|
||||
import analysis.base;
|
||||
|
@ -19,39 +18,11 @@ class UnusedLabelCheck : BaseAnalyzer
|
|||
super(fileName);
|
||||
}
|
||||
|
||||
static struct Label
|
||||
override void visit(const Module mod)
|
||||
{
|
||||
string name;
|
||||
size_t line;
|
||||
size_t column;
|
||||
bool used;
|
||||
}
|
||||
|
||||
Label[string][] stack;
|
||||
|
||||
auto ref current() @property
|
||||
{
|
||||
return stack[$-1];
|
||||
}
|
||||
|
||||
void pushScope()
|
||||
{
|
||||
stack.length++;
|
||||
}
|
||||
|
||||
void popScope()
|
||||
{
|
||||
foreach (label; current.byValue())
|
||||
{
|
||||
assert(label.line != size_t.max && label.column != size_t.max);
|
||||
if (!label.used)
|
||||
{
|
||||
addErrorMessage(label.line, label.column,
|
||||
"dscanner.suspicious.unused_label",
|
||||
"Label \"" ~ label.name ~ "\" is not used.");
|
||||
}
|
||||
}
|
||||
stack.length--;
|
||||
pushScope();
|
||||
mod.accept(this);
|
||||
popScope();
|
||||
}
|
||||
|
||||
override void visit(const FunctionBody functionBody)
|
||||
|
@ -99,15 +70,6 @@ class UnusedLabelCheck : BaseAnalyzer
|
|||
labeledStatement.declarationOrStatement.accept(this);
|
||||
}
|
||||
|
||||
void labelUsed(string name)
|
||||
{
|
||||
Label* entry = name in current;
|
||||
if (entry is null)
|
||||
current[name] = Label(name, size_t.max, size_t.max, true);
|
||||
else
|
||||
entry.used = true;
|
||||
}
|
||||
|
||||
override void visit(const ContinueStatement contStatement)
|
||||
{
|
||||
if (contStatement.label.text.length)
|
||||
|
@ -123,11 +85,58 @@ class UnusedLabelCheck : BaseAnalyzer
|
|||
if (gotoStatement.label.text.length)
|
||||
labelUsed(gotoStatement.label.text);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static struct Label
|
||||
{
|
||||
string name;
|
||||
size_t line;
|
||||
size_t column;
|
||||
bool used;
|
||||
}
|
||||
|
||||
Label[string][] stack;
|
||||
|
||||
auto ref current() @property
|
||||
{
|
||||
return stack[$-1];
|
||||
}
|
||||
|
||||
void pushScope()
|
||||
{
|
||||
stack.length++;
|
||||
}
|
||||
|
||||
void popScope()
|
||||
{
|
||||
foreach (label; current.byValue())
|
||||
{
|
||||
assert(label.line != size_t.max && label.column != size_t.max);
|
||||
if (!label.used)
|
||||
{
|
||||
addErrorMessage(label.line, label.column,
|
||||
"dscanner.suspicious.unused_label",
|
||||
"Label \"" ~ label.name ~ "\" is not used.");
|
||||
}
|
||||
}
|
||||
stack.length--;
|
||||
}
|
||||
|
||||
void labelUsed(string name)
|
||||
{
|
||||
Label* entry = name in current;
|
||||
if (entry is null)
|
||||
current[name] = Label(name, size_t.max, size_t.max, true);
|
||||
else
|
||||
entry.used = true;
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
import analysis.config : StaticAnalysisConfig;
|
||||
import std.stdio : stderr;
|
||||
|
||||
StaticAnalysisConfig sac;
|
||||
sac.unused_label_check = true;
|
||||
|
|
64
src/ctags.d
64
src/ctags.d
|
@ -53,8 +53,8 @@ class CTagsPrinter : ASTVisitor
|
|||
{
|
||||
override void visit(const ClassDeclaration dec)
|
||||
{
|
||||
tagLines ~= "%s\t%s\t%d;\"\tc%s\n".format(dec.name.text, fileName, dec.name.line, context);
|
||||
auto c = context;
|
||||
tagLines ~= "%s\t%s\t%d;\"\tc\tline:%d%s\n".format(dec.name.text, fileName, dec.name.line, dec.name.line, context);
|
||||
const c = context;
|
||||
context = "\tclass:" ~ dec.name.text;
|
||||
dec.accept(this);
|
||||
context = c;
|
||||
|
@ -62,8 +62,8 @@ class CTagsPrinter : ASTVisitor
|
|||
|
||||
override void visit(const StructDeclaration dec)
|
||||
{
|
||||
tagLines ~= "%s\t%s\t%d;\"\ts%s\n".format(dec.name.text, fileName, dec.name.line, context);
|
||||
auto c = context;
|
||||
tagLines ~= "%s\t%s\t%d;\"\ts\tline:%d%s\n".format(dec.name.text, fileName, dec.name.line, dec.name.line, context);
|
||||
const c = context;
|
||||
context = "\tstruct:" ~ dec.name.text;
|
||||
dec.accept(this);
|
||||
context = c;
|
||||
|
@ -71,8 +71,8 @@ class CTagsPrinter : ASTVisitor
|
|||
|
||||
override void visit(const InterfaceDeclaration dec)
|
||||
{
|
||||
tagLines ~= "%s\t%s\t%d;\"\ti%s\n".format(dec.name.text, fileName, dec.name.line, context);
|
||||
auto c = context;
|
||||
tagLines ~= "%s\t%s\t%d;\"\ti\tline:%d%s\n".format(dec.name.text, fileName, dec.name.line, dec.name.line, context);
|
||||
const c = context;
|
||||
context = "\tclass:" ~ dec.name.text;
|
||||
dec.accept(this);
|
||||
context = c;
|
||||
|
@ -80,8 +80,8 @@ class CTagsPrinter : ASTVisitor
|
|||
|
||||
override void visit(const TemplateDeclaration dec)
|
||||
{
|
||||
tagLines ~= "%s\t%s\t%d;\"\tT%s\n".format(dec.name.text, fileName, dec.name.line, context);
|
||||
auto c = context;
|
||||
tagLines ~= "%s\t%s\t%d;\"\tT\tline:%d%s\n".format(dec.name.text, fileName, dec.name.line, dec.name.line, context);
|
||||
const c = context;
|
||||
context = "\ttemplate:" ~ dec.name.text;
|
||||
dec.accept(this);
|
||||
context = c;
|
||||
|
@ -89,9 +89,9 @@ class CTagsPrinter : ASTVisitor
|
|||
|
||||
override void visit(const FunctionDeclaration dec)
|
||||
{
|
||||
tagLines ~= "%s\t%s\t%d;\"\tf\tarity:%d%s\n".format(dec.name.text, fileName,
|
||||
dec.name.line, dec.parameters.parameters.length, context);
|
||||
auto c = context;
|
||||
tagLines ~= "%s\t%s\t%d;\"\tf\tarity:%d\tline:%d%s\n".format(dec.name.text, fileName,
|
||||
dec.name.line, dec.parameters.parameters.length, dec.name.line, context);
|
||||
const c = context;
|
||||
context = "\tfunction:" ~ dec.name.text;
|
||||
dec.accept(this);
|
||||
context = c;
|
||||
|
@ -99,9 +99,9 @@ class CTagsPrinter : ASTVisitor
|
|||
|
||||
override void visit(const Constructor dec)
|
||||
{
|
||||
tagLines ~= "this\t%s\t%d;\"\tf\tarity:%d%s\n".format(fileName,
|
||||
dec.line, dec.parameters.parameters.length, context);
|
||||
auto c = context;
|
||||
tagLines ~= "this\t%s\t%d;\"\tf\tarity:%d\tline:%d%s\n".format(fileName,
|
||||
dec.line, dec.parameters.parameters.length, dec.line, context);
|
||||
const c = context;
|
||||
context = "\tfunction: this";
|
||||
dec.accept(this);
|
||||
context = c;
|
||||
|
@ -109,9 +109,9 @@ class CTagsPrinter : ASTVisitor
|
|||
|
||||
override void visit(const Destructor dec)
|
||||
{
|
||||
tagLines ~= "~this\t%s\t%d;\"\tf%s\n".format(fileName, dec.line,
|
||||
context);
|
||||
auto c = context;
|
||||
tagLines ~= "~this\t%s\t%d;\"\tf\tline:%d%s\n".format(fileName, dec.line,
|
||||
dec.line, context);
|
||||
const c = context;
|
||||
context = "\tfunction: this";
|
||||
dec.accept(this);
|
||||
context = c;
|
||||
|
@ -119,9 +119,9 @@ class CTagsPrinter : ASTVisitor
|
|||
|
||||
override void visit(const EnumDeclaration dec)
|
||||
{
|
||||
tagLines ~= "%s\t%s\t%d;\"\tg%s\n".format(dec.name.text, fileName,
|
||||
dec.name.line, context);
|
||||
auto c = context;
|
||||
tagLines ~= "%s\t%s\t%d;\"\tg\tline:%d%s\n".format(dec.name.text, fileName,
|
||||
dec.name.line, dec.name.line, context);
|
||||
const c = context;
|
||||
context = "\tenum:" ~ dec.name.text;
|
||||
dec.accept(this);
|
||||
context = c;
|
||||
|
@ -134,9 +134,9 @@ class CTagsPrinter : ASTVisitor
|
|||
dec.accept(this);
|
||||
return;
|
||||
}
|
||||
tagLines ~= "%s\t%s\t%d;\"\tu%s\n".format(dec.name.text, fileName,
|
||||
dec.name.line, context);
|
||||
auto c = context;
|
||||
tagLines ~= "%s\t%s\t%d;\"\tu\tline:%d%s\n".format(dec.name.text, fileName,
|
||||
dec.name.line, dec.name.line, context);
|
||||
const c = context;
|
||||
context = "\tunion:" ~ dec.name.text;
|
||||
dec.accept(this);
|
||||
context = c;
|
||||
|
@ -144,22 +144,22 @@ class CTagsPrinter : ASTVisitor
|
|||
|
||||
override void visit(const AnonymousEnumMember mem)
|
||||
{
|
||||
tagLines ~= "%s\t%s\t%d;\"\te%s\n".format(mem.name.text, fileName,
|
||||
mem.name.line, context);
|
||||
tagLines ~= "%s\t%s\t%d;\"\te\tline:%d%s\n".format(mem.name.text, fileName,
|
||||
mem.name.line, mem.name.line, context);
|
||||
}
|
||||
|
||||
override void visit(const EnumMember mem)
|
||||
{
|
||||
tagLines ~= "%s\t%s\t%d;\"\te%s\n".format(mem.name.text, fileName,
|
||||
mem.name.line, context);
|
||||
tagLines ~= "%s\t%s\t%d;\"\te\tline:%d%s\n".format(mem.name.text, fileName,
|
||||
mem.name.line, mem.name.line, context);
|
||||
}
|
||||
|
||||
override void visit(const VariableDeclaration dec)
|
||||
{
|
||||
foreach (d; dec.declarators)
|
||||
{
|
||||
tagLines ~= "%s\t%s\t%d;\"\tv%s\n".format(d.name.text, fileName,
|
||||
d.name.line, context);
|
||||
tagLines ~= "%s\t%s\t%d;\"\tv\tline:%d%s\n".format(d.name.text, fileName,
|
||||
d.name.line, d.name.line, context);
|
||||
}
|
||||
dec.accept(this);
|
||||
}
|
||||
|
@ -168,15 +168,15 @@ class CTagsPrinter : ASTVisitor
|
|||
{
|
||||
foreach (i; dec.identifiers)
|
||||
{
|
||||
tagLines ~= "%s\t%s\t%d;\"\tv%s\n".format(i.text, fileName,
|
||||
i.line, context);
|
||||
tagLines ~= "%s\t%s\t%d;\"\tv\tline:%d%s\n".format(i.text, fileName,
|
||||
i.line, i.line, context);
|
||||
}
|
||||
dec.accept(this);
|
||||
}
|
||||
|
||||
override void visit(const Invariant dec)
|
||||
{
|
||||
tagLines ~= "invariant\t%s\t%d;\"\tv%s\n".format(fileName, dec.line, context);
|
||||
tagLines ~= "invariant\t%s\t%d;\"\tv\tline:%d%s\n".format(fileName, dec.line, dec.line, context);
|
||||
}
|
||||
|
||||
alias visit = ASTVisitor.visit;
|
||||
|
|
|
@ -8,7 +8,7 @@ module dscanner_version;
|
|||
/**
|
||||
* Human-readable version number
|
||||
*/
|
||||
enum DSCANNER_VERSION = "v0.2.0-dev";
|
||||
enum DSCANNER_VERSION = "v0.2.0-beta1";
|
||||
|
||||
version (Windows) {}
|
||||
else
|
||||
|
|
26
src/main.d
26
src/main.d
|
@ -34,17 +34,8 @@ import inifiled;
|
|||
int main(string[] args)
|
||||
{
|
||||
version (unittest)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return run(args);
|
||||
}
|
||||
}
|
||||
|
||||
int run(string[] args)
|
||||
{
|
||||
bool sloc;
|
||||
bool highlight;
|
||||
bool ctags;
|
||||
|
@ -191,11 +182,11 @@ int run(string[] args)
|
|||
if (report)
|
||||
generateReport(expandArgs(args), config);
|
||||
else
|
||||
analyze(expandArgs(args), config, true);
|
||||
return analyze(expandArgs(args), config, true) ? 1 : 0;
|
||||
}
|
||||
else if (syntaxCheck)
|
||||
{
|
||||
return .syntaxCheck(expandArgs(args));
|
||||
return .syntaxCheck(expandArgs(args)) ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -274,6 +265,7 @@ int run(string[] args)
|
|||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
string[] expandArgs(string[] args)
|
||||
{
|
||||
|
@ -289,7 +281,7 @@ string[] expandArgs(string[] args)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string[] rVal;
|
||||
if (args.length == 1)
|
||||
args ~= ".";
|
||||
|
@ -368,11 +360,13 @@ options:
|
|||
--syntaxCheck | -s [sourceFile]
|
||||
Lexes and parses sourceFile, printing the line and column number of any
|
||||
syntax errors to stdout. One error or warning is printed per line.
|
||||
If no files are specified, input is read from stdin.
|
||||
If no files are specified, input is read from stdin. %1$s will exit with
|
||||
a status code of zero if no errors are found, 1 otherwise.
|
||||
|
||||
--styleCheck | -S [sourceFiles]
|
||||
Lexes and parses sourceFiles, printing the line and column number of any
|
||||
static analysis check failures stdout.
|
||||
static analysis check failures stdout. %1$s will exit with a status code
|
||||
of zero if no warnings or errors are found, 1 otherwise.
|
||||
|
||||
--ctags | -c sourceFile
|
||||
Generates ctags information from the given source code file. Note that
|
||||
|
@ -397,7 +391,9 @@ options:
|
|||
current working directory if none are specified.
|
||||
|
||||
--report [sourceFiles sourceDirectories]
|
||||
Generate a static analysis report in JSON format. Implies --styleCheck.
|
||||
Generate a static analysis report in JSON format. Implies --styleCheck,
|
||||
however the exit code will still be zero if errors or warnings are
|
||||
found.
|
||||
|
||||
--config configFile
|
||||
Use the given configuration file instead of the default located in
|
||||
|
|
Loading…
Reference in New Issue