Starting work on 0.3.0

This commit is contained in:
Hackerpilot 2015-05-26 00:24:21 -07:00
parent 327e629867
commit a3c4a5384a
35 changed files with 212 additions and 99 deletions

6
.gitmodules vendored
View file

@ -5,3 +5,9 @@
[submodule "inifiled"]
path = inifiled
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

@ -0,0 +1 @@
Subproject commit d732a67e76f60fd037547c3ffe8776c6deda6bab

1
dsymbol Submodule

@ -0,0 +1 @@
Subproject commit ddf8c97753471388303d64a47bdade85cc4de003

@ -1 +1 @@
Subproject commit 32f6d638e38888e1bb11cf43e93fe2d11132a98f
Subproject commit 0dccfca0e2a132b3c862a62da1c323ccd24e622d

View file

@ -7,12 +7,21 @@ SRC = src/*.d\
src/analysis/*.d\
libdparse/src/std/*.d\
libdparse/src/std/d/*.d\
inifiled/source/*.d
INCLUDE_PATHS = -Ilibdparse/src
inifiled/source/*.d\
$(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 =
DEBUG_VERSIONS = -version=std_parser_verbose
DMD_FLAGS = -w -O -release -inline
#DMD_FLAGS = -w
#DMD_FLAGS = -w -O -release -inline
DMD_FLAGS = -w
all: dmdbuild
ldc: ldcbuild

View file

@ -10,6 +10,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_ : Scope;
/**
* Checks for confusing asm expressions.
@ -19,9 +20,9 @@ class AsmStyleCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const AsmBrExp brExp)

View file

@ -4,6 +4,7 @@ import std.container;
import std.string;
import std.d.ast;
import std.array;
import dsymbol.scope_ : Scope;
struct Message
{
@ -26,8 +27,9 @@ alias MessageSet = RedBlackTree!(Message, comparitor, true);
abstract class BaseAnalyzer : ASTVisitor
{
public:
this(string fileName)
this(string fileName, const Scope* sc)
{
this.sc = sc;
this.fileName = fileName;
_messages = new MessageSet;
}
@ -61,6 +63,8 @@ protected:
*/
string fileName;
const(Scope)* sc;
MessageSet _messages;
}

View file

@ -11,6 +11,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_;
/**
* The following code should be killed with fire:
@ -29,9 +30,9 @@ class BuiltinPropertyNameCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const FunctionDeclaration fd)

View file

@ -8,6 +8,7 @@ module analysis.comma_expression;
import std.d.ast;
import std.d.lexer;
import analysis.base;
import dsymbol.scope_;
/**
* Check for uses of the comma expression.
@ -16,9 +17,9 @@ class CommaExpressionCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const Expression ex)

View file

@ -5,15 +5,16 @@ import std.d.lexer;
import std.stdio;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_ : Scope;
class ConstructorCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const ClassDeclaration classDeclaration)

View file

@ -10,6 +10,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_;
/**
* Checks for use of the deprecated 'delete' keyword
@ -18,9 +19,9 @@ class DeleteCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const DeleteExpression d)

View file

@ -11,6 +11,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_ : Scope;
/**
@ -21,9 +22,9 @@ class DuplicateAttributeCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const Declaration node)

View file

@ -9,6 +9,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import std.algorithm : canFind;
import dsymbol.scope_ : Scope;
void doNothing(string, size_t, size_t, string, bool) {}
@ -16,9 +17,9 @@ class EnumArrayLiteralCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
bool looking = false;

View file

@ -10,6 +10,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_ : Scope;
/**
* 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";
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const RelExpression r)

View file

@ -5,11 +5,11 @@
module analysis.function_attributes;
import analysis.base;
import std.d.ast;
import std.d.lexer;
import analysis.base;
import std.stdio;
import dsymbol.scope_;
/**
* Prefer
@ -25,9 +25,9 @@ class FunctionAttributeCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const InterfaceDeclaration dec)

View file

@ -8,15 +8,14 @@ import std.d.ast;
import std.d.lexer;
import std.d.formatter;
import analysis.base;
import dsymbol.scope_ : Scope;
class IfStatementCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
import std.container.binaryheap : heapify;
super(fileName);
super(fileName, sc);
}
override void visit(const IfStatement ifStatement)

View file

@ -6,12 +6,11 @@
module analysis.ifelsesame;
import std.stdio;
import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_ : Scope;
/**
* Checks for duplicated code in conditional and logical expressions.
@ -25,9 +24,9 @@ class IfElseSameCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const IfStatement ifStatement)

View file

@ -11,6 +11,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_;
/**
@ -20,9 +21,9 @@ class LengthSubtractionCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const AddExpression addExpression)

View file

@ -10,6 +10,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_;
/**
* Checks for local imports that import all symbols.
@ -22,9 +23,9 @@ class LocalImportCheck : BaseAnalyzer
/**
* Construct with the given file name.
*/
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
mixin visitThing!StructBody;

View file

@ -10,6 +10,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_;
/**
* Checks for code with confusing && and || operator precedence
@ -24,9 +25,9 @@ class LogicPrecedenceCheck : BaseAnalyzer
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)

View 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)]);
}
}

View file

@ -11,6 +11,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_ : Scope;
/**
* Checks for long and hard-to-read number literals
@ -23,9 +24,9 @@ public:
/**
* 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)

View file

@ -11,6 +11,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_ : Scope;
/**
* Checks that opEquals, opCmp, toHash, and toString are either const,
@ -20,9 +21,9 @@ class ObjectConstCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
mixin visitTemplate!ClassDeclaration;

View file

@ -10,6 +10,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_ : Scope;
/**
* Checks for when a class/struct has the method opEquals without toHash, or
@ -19,9 +20,9 @@ class OpEqualsWithoutToHashCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const ClassDeclaration node)

View file

@ -10,6 +10,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_ : Scope;
/**
@ -30,9 +31,9 @@ class PokemonExceptionCheck : BaseAnalyzer
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const LastCatch lc)

View file

@ -10,6 +10,7 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_ : Scope;
/**
* Checks for .. expressions where the left side is larger than the right. This
@ -26,9 +27,9 @@ class BackwardsRangeCheck : BaseAnalyzer
* Params:
* 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)
@ -56,7 +57,7 @@ class BackwardsRangeCheck : BaseAnalyzer
override void visit(const AddExpression add)
{
auto s = state;
immutable s = state;
state = State.ignore;
add.accept(this);
state = s;

View file

@ -8,14 +8,15 @@ module analysis.redundant_parens;
import std.d.ast;
import std.d.lexer;
import analysis.base;
import dsymbol.scope_ : Scope;
class RedundantParenCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const IfStatement statement)

View file

@ -14,6 +14,8 @@ import std.array;
import std.d.lexer;
import std.d.parser;
import std.d.ast;
import std.allocator : CAllocatorImpl;
import std.typecons:scoped;
import analysis.config;
import analysis.base;
@ -44,6 +46,11 @@ import analysis.unmodified;
import analysis.if_statements;
import analysis.redundant_parens;
import memory.allocators:BlockAllocator;
import dsymbol.scope_;
import dsymbol.conversion;
bool first = true;
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)
return null;
auto allocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024 * 16)))();
const(Scope)* moduleScope = generateAutocompleteTrees(m, allocator);
BaseAnalyzer[] checks;
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_label_check) checks ~= new UnusedLabelCheck(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);
if (analysisConfig.length_subtraction_check) checks ~= new LengthSubtractionCheck(fileName);
if (analysisConfig.builtin_property_names_check) checks ~= new BuiltinPropertyNameCheck(fileName);
if (analysisConfig.asm_style_check) checks ~= new AsmStyleCheck(fileName);
if (analysisConfig.logical_precedence_check) checks ~= new LogicPrecedenceCheck(fileName);
if (analysisConfig.undocumented_declaration_check) checks ~= new UndocumentedDeclarationCheck(fileName);
if (analysisConfig.function_attribute_check) checks ~= new FunctionAttributeCheck(fileName);
if (analysisConfig.comma_expression_check) checks ~= new CommaExpressionCheck(fileName);
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);
version(none) if (analysisConfig.redundant_if_check) checks ~= new IfStatementCheck(fileName);
if (analysisConfig.style_check) checks ~= new StyleChecker(fileName, moduleScope);
if (analysisConfig.enum_array_literal_check) checks ~= new EnumArrayLiteralCheck(fileName, moduleScope);
if (analysisConfig.exception_check) checks ~= new PokemonExceptionCheck(fileName, moduleScope);
if (analysisConfig.delete_check) checks ~= new DeleteCheck(fileName, moduleScope);
if (analysisConfig.float_operator_check) checks ~= new FloatOperatorCheck(fileName, moduleScope);
if (analysisConfig.number_style_check) checks ~= new NumberStyleCheck(fileName, moduleScope);
if (analysisConfig.object_const_check) checks ~= new ObjectConstCheck(fileName, moduleScope);
if (analysisConfig.backwards_range_check) checks ~= new BackwardsRangeCheck(fileName, moduleScope);
if (analysisConfig.if_else_same_check) checks ~= new IfElseSameCheck(fileName, moduleScope);
if (analysisConfig.constructor_check) checks ~= new ConstructorCheck(fileName, moduleScope);
if (analysisConfig.unused_label_check) checks ~= new UnusedLabelCheck(fileName, moduleScope);
if (analysisConfig.unused_variable_check) checks ~= new UnusedVariableCheck(fileName, moduleScope);
if (analysisConfig.duplicate_attribute) checks ~= new DuplicateAttributeCheck(fileName, moduleScope);
if (analysisConfig.opequals_tohash_check) checks ~= new OpEqualsWithoutToHashCheck(fileName, moduleScope);
if (analysisConfig.length_subtraction_check) checks ~= new LengthSubtractionCheck(fileName, moduleScope);
if (analysisConfig.builtin_property_names_check) checks ~= new BuiltinPropertyNameCheck(fileName, moduleScope);
if (analysisConfig.asm_style_check) checks ~= new AsmStyleCheck(fileName, moduleScope);
if (analysisConfig.logical_precedence_check) checks ~= new LogicPrecedenceCheck(fileName, moduleScope);
if (analysisConfig.undocumented_declaration_check) checks ~= new UndocumentedDeclarationCheck(fileName, moduleScope);
if (analysisConfig.function_attribute_check) checks ~= new FunctionAttributeCheck(fileName, moduleScope);
if (analysisConfig.comma_expression_check) checks ~= new CommaExpressionCheck(fileName, moduleScope);
if (analysisConfig.local_import_check) checks ~= new LocalImportCheck(fileName, moduleScope);
if (analysisConfig.could_be_immutable_check) checks ~= new UnmodifiedFinder(fileName, moduleScope);
if (analysisConfig.redundant_parens_check) checks ~= new RedundantParenCheck(fileName, moduleScope);
version(none) if (analysisConfig.redundant_if_check) checks ~= new IfStatementCheck(fileName, moduleScope);
foreach (check; checks)
{

View file

@ -15,7 +15,7 @@ class StatsCollector : BaseAnalyzer
this(string fileName)
{
super(fileName);
super(fileName, null);
}
override void visit(const Statement statement)

View file

@ -13,8 +13,8 @@ import std.array;
import std.conv;
import std.format;
import analysis.helpers;
import analysis.base;
import dsymbol.scope_ : Scope;
class StyleChecker : BaseAnalyzer
{
@ -25,9 +25,9 @@ class StyleChecker : BaseAnalyzer
enum string moduleNameRegex = `^[\p{Ll}_\d]+$`;
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)

View file

@ -5,10 +5,10 @@
module analysis.undocumented;
import analysis.base;
import dsymbol.scope_ : Scope;
import std.d.ast;
import std.d.lexer;
import analysis.base;
import std.stdio;
/**
@ -19,9 +19,9 @@ class UndocumentedDeclarationCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const Module mod)

View file

@ -4,10 +4,11 @@
// http://www.boost.org/LICENSE_1_0.txt)
module analysis.unmodified;
import analysis.base;
import dsymbol.scope_ : Scope;
import std.container;
import std.d.ast;
import std.d.lexer;
import analysis.base;
/**
* Checks for variables that could have been declared const or immutable
@ -17,9 +18,9 @@ class UnmodifiedFinder:BaseAnalyzer
alias visit = BaseAnalyzer.visit;
///
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
override void visit(const Module mod)
@ -41,7 +42,7 @@ class UnmodifiedFinder:BaseAnalyzer
override void visit(const StructBody structBody)
{
pushScope();
auto oldBlockStatementDepth = blockStatementDepth;
immutable oldBlockStatementDepth = blockStatementDepth;
blockStatementDepth = 0;
structBody.accept(this);
blockStatementDepth = oldBlockStatementDepth;

View file

@ -10,6 +10,7 @@ import std.d.lexer;
import analysis.base;
import std.container;
import std.regex : Regex, regex, matchAll;
import dsymbol.scope_ : Scope;
/**
* Checks for unused variables.
@ -22,9 +23,9 @@ class UnusedVariableCheck : BaseAnalyzer
* Params:
* 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_]*");
}

View file

@ -9,14 +9,15 @@ import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
import dsymbol.scope_ : Scope;
class UnusedLabelCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
this(string fileName, const(Scope)* sc)
{
super(fileName);
super(fileName, sc);
}
static struct Label

View file

@ -1,4 +1,4 @@
// Copyright Brian Schott (Hackerpilot) 2012.
// Copyright Brian Schott (Hackerpilot) 2012-2015.
// 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)
@ -31,6 +31,8 @@ import dscanner_version;
import inifiled;
import dsymbol.modulecache;
int main(string[] args)
{
version (unittest)
@ -65,6 +67,7 @@ int run(string[] args)
string configLocation;
bool printVersion;
bool explore;
string[] importPaths;
try
{
@ -75,7 +78,7 @@ int run(string[] args)
"ast|xml", &ast, "imports|i", &imports, "outline|o", &outline,
"tokenDump", &tokenDump, "styleCheck|S", &styleCheck,
"defaultConfig", &defaultConfig, "declaration|d", &symbolName,
"config", &configLocation, "report", &report,
"config", &configLocation, "report", &report, "I", &importPaths,
"version", &printVersion, "muffinButton", &muffin, "explore", &explore);
}
catch (ConvException e)
@ -121,7 +124,13 @@ int run(string[] args)
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,
report, symbolName !is null, etags, etagsAll]);
if (optionCount > 1)
@ -274,7 +283,6 @@ int run(string[] args)
return 0;
}
string[] expandArgs(string[] args)
{
// isFile can throw if it's a broken symlink.
@ -289,7 +297,7 @@ string[] expandArgs(string[] args)
return false;
}
}
string[] rVal;
if (args.length == 1)
args ~= ".";