116 lines
3.5 KiB
D
116 lines
3.5 KiB
D
module analysis.run;
|
|
|
|
import std.stdio;
|
|
import std.array;
|
|
import std.conv;
|
|
import std.algorithm;
|
|
import std.range;
|
|
import std.array;
|
|
import std.d.lexer;
|
|
import std.d.parser;
|
|
import std.d.ast;
|
|
|
|
import analysis.config;
|
|
import analysis.base;
|
|
import analysis.style;
|
|
import analysis.enumarrayliteral;
|
|
import analysis.pokemon;
|
|
import analysis.del;
|
|
import analysis.fish;
|
|
import analysis.numbers;
|
|
import analysis.objectconst;
|
|
import analysis.range;
|
|
import analysis.ifelsesame;
|
|
import analysis.constructors;
|
|
import analysis.unused;
|
|
import analysis.duplicate_attribute;
|
|
import analysis.opequals_without_tohash;
|
|
|
|
void messageFunction(string fileName, size_t line, size_t column, string message,
|
|
bool isError)
|
|
{
|
|
writefln("%s(%d:%d)[%s]: %s", fileName, line, column,
|
|
isError ? "error" : "warn", message);
|
|
}
|
|
|
|
void syntaxCheck(File output, string[] fileNames)
|
|
{
|
|
StaticAnalysisConfig config = defaultStaticAnalysisConfig();
|
|
analyze(output, fileNames, config, false);
|
|
}
|
|
|
|
// For multiple files
|
|
void analyze(File output, string[] fileNames, StaticAnalysisConfig config, bool staticAnalyze = true)
|
|
{
|
|
foreach (fileName; fileNames)
|
|
{
|
|
File f = File(fileName);
|
|
if (f.size == 0) continue;
|
|
auto code = uninitializedArray!(ubyte[])(to!size_t(f.size));
|
|
f.rawRead(code);
|
|
|
|
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, StaticAnalysisConfig analysisConfig, bool staticAnalyze = true)
|
|
{
|
|
import std.parallelism;
|
|
|
|
auto lexer = byToken(code);
|
|
LexerConfig config;
|
|
config.fileName = fileName;
|
|
config.stringBehavior = StringBehavior.source;
|
|
StringCache cache = StringCache(StringCache.defaultBucketCount);
|
|
const(Token)[] tokens = getTokensForParser(code, config, &cache);
|
|
|
|
foreach (message; lexer.messages)
|
|
{
|
|
messageFunction(fileName, message.line, message.column, message.message,
|
|
message.isError);
|
|
}
|
|
|
|
ParseAllocator p = new ParseAllocator;
|
|
Module m = parseModule(tokens, fileName, p, &messageFunction);
|
|
|
|
if (!staticAnalyze)
|
|
return null;
|
|
|
|
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_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)
|
|
{
|
|
check.visit(m);
|
|
}
|
|
|
|
MessageSet set = new MessageSet;
|
|
foreach (check; checks)
|
|
foreach (message; check.messages)
|
|
set.insert(message);
|
|
|
|
string[] results;
|
|
foreach (message; set[])
|
|
results ~= "%s(%d:%d)[warn]: %s".format(message.fileName, message.line,
|
|
message.column, message.message);
|
|
p.deallocateAll();
|
|
return results;
|
|
}
|
|
|