Use DMD in NumberStyleCheck (#88)
* Replace libdparse with DMD in NumberStyleCheck * Fix re-lexing for windows (CRLF terminators) files * Improve unit test
This commit is contained in:
parent
860ddf1994
commit
8b7612d76a
|
|
@ -5,60 +5,83 @@
|
||||||
|
|
||||||
module dscanner.analysis.numbers;
|
module dscanner.analysis.numbers;
|
||||||
|
|
||||||
import std.stdio;
|
|
||||||
import std.regex;
|
|
||||||
import dparse.ast;
|
|
||||||
import dparse.lexer;
|
|
||||||
import dscanner.analysis.base;
|
import dscanner.analysis.base;
|
||||||
import dscanner.analysis.helpers;
|
import dmd.tokens : TOK;
|
||||||
import dsymbol.scope_ : Scope;
|
import std.conv;
|
||||||
|
import std.regex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for long and hard-to-read number literals
|
* Checks for long and hard-to-read number literals
|
||||||
*/
|
*/
|
||||||
final class NumberStyleCheck : BaseAnalyzer
|
extern (C++) class NumberStyleCheck(AST) : BaseAnalyzerDmd
|
||||||
{
|
{
|
||||||
public:
|
alias visit = BaseAnalyzerDmd.visit;
|
||||||
alias visit = BaseAnalyzer.visit;
|
|
||||||
|
|
||||||
mixin AnalyzerInfo!"number_style_check";
|
mixin AnalyzerInfo!"number_style_check";
|
||||||
|
|
||||||
/**
|
private enum KEY = "dscanner.style.number_literals";
|
||||||
* Constructs the style checker with the given file name.
|
private enum string MSG = "Use underscores to improve number constant readability.";
|
||||||
*/
|
|
||||||
this(BaseAnalyzerArguments args)
|
private auto badBinaryRegex = ctRegex!(`^0b[01]{9,}`);
|
||||||
|
private auto badDecimalRegex = ctRegex!(`^\d{5,}`);
|
||||||
|
|
||||||
|
extern (D) this(string fileName, bool skipTests = false)
|
||||||
{
|
{
|
||||||
super(args);
|
super(fileName, skipTests);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const Token t)
|
override void visit(AST.IntegerExp intExpr)
|
||||||
{
|
{
|
||||||
import std.algorithm : startsWith;
|
import dscanner.utils : readFile;
|
||||||
|
import dmd.errorsink : ErrorSinkNull;
|
||||||
|
import dmd.globals : global;
|
||||||
|
import dmd.lexer : Lexer;
|
||||||
|
|
||||||
if (isNumberLiteral(t.type) && !t.text.startsWith("0x")
|
auto bytes = readFile(fileName) ~ '\0';
|
||||||
&& ((t.text.startsWith("0b") && !t.text.matchFirst(badBinaryRegex)
|
bytes = bytes[intExpr.loc.fileOffset .. $];
|
||||||
.empty) || !t.text.matchFirst(badDecimalRegex).empty))
|
|
||||||
|
__gshared ErrorSinkNull errorSinkNull;
|
||||||
|
if (!errorSinkNull)
|
||||||
|
errorSinkNull = new ErrorSinkNull;
|
||||||
|
|
||||||
|
scope lexer = new Lexer(null, cast(char*) bytes, 0, bytes.length, 0, 0, errorSinkNull, &global.compileEnv);
|
||||||
|
auto tokenValue = lexer.nextToken();
|
||||||
|
bool isInt = false;
|
||||||
|
|
||||||
|
while (tokenValue != TOK.semicolon && tokenValue != TOK.endOfFile)
|
||||||
{
|
{
|
||||||
addErrorMessage(t, KEY,
|
if (isIntegerLiteral(tokenValue))
|
||||||
"Use underscores to improve number constant readability.");
|
{
|
||||||
|
isInt = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenValue = lexer.nextToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isInt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto tokenText = to!string(lexer.token.ptr);
|
||||||
|
|
||||||
|
if (!matchFirst(tokenText, badDecimalRegex).empty || !matchFirst(tokenText, badBinaryRegex).empty)
|
||||||
|
addErrorMessage(intExpr.loc.linnum, intExpr.loc.charnum, KEY, MSG);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private bool isIntegerLiteral(TOK token)
|
||||||
|
{
|
||||||
enum string KEY = "dscanner.style.number_literals";
|
return token >= TOK.int32Literal && token <= TOK.uns128Literal;
|
||||||
|
}
|
||||||
auto badBinaryRegex = ctRegex!(`^0b[01]{9,}`);
|
|
||||||
auto badDecimalRegex = ctRegex!(`^\d{5,}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
|
import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
|
||||||
|
import dscanner.analysis.helpers : assertAnalyzerWarningsDMD;
|
||||||
|
import std.stdio : stderr;
|
||||||
|
|
||||||
StaticAnalysisConfig sac = disabledConfig();
|
StaticAnalysisConfig sac = disabledConfig();
|
||||||
sac.number_style_check = Check.enabled;
|
sac.number_style_check = Check.enabled;
|
||||||
assertAnalyzerWarnings(q{
|
assertAnalyzerWarningsDMD(q{
|
||||||
void testNumbers()
|
void testNumbers()
|
||||||
{
|
{
|
||||||
int a;
|
int a;
|
||||||
|
|
@ -66,12 +89,12 @@ unittest
|
||||||
a = 10; // ok
|
a = 10; // ok
|
||||||
a = 100; // ok
|
a = 100; // ok
|
||||||
a = 1000; // ok
|
a = 1000; // ok
|
||||||
a = 10000; /+
|
a = 10_00; // ok
|
||||||
^^^^^ [warn]: Use underscores to improve number constant readability. +/
|
a = 10_000; // ok
|
||||||
a = 100000; /+
|
a = 100_000; // ok
|
||||||
^^^^^^ [warn]: Use underscores to improve number constant readability. +/
|
a = 10000; // [warn]: Use underscores to improve number constant readability.
|
||||||
a = 1000000; /+
|
a = 100000; // [warn]: Use underscores to improve number constant readability.
|
||||||
^^^^^^^ [warn]: Use underscores to improve number constant readability. +/
|
a = 1000000; // [warn]: Use underscores to improve number constant readability.
|
||||||
}
|
}
|
||||||
}c, sac);
|
}c, sac);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -855,10 +855,6 @@ private BaseAnalyzer[] getAnalyzersForModuleAndConfig(string fileName,
|
||||||
checks ~= new MismatchedArgumentCheck(args.setSkipTests(
|
checks ~= new MismatchedArgumentCheck(args.setSkipTests(
|
||||||
analysisConfig.mismatched_args_check == Check.skipTests && !ut));
|
analysisConfig.mismatched_args_check == Check.skipTests && !ut));
|
||||||
|
|
||||||
if (moduleName.shouldRun!NumberStyleCheck(analysisConfig))
|
|
||||||
checks ~= new NumberStyleCheck(args.setSkipTests(
|
|
||||||
analysisConfig.number_style_check == Check.skipTests && !ut));
|
|
||||||
|
|
||||||
if (moduleName.shouldRun!StyleChecker(analysisConfig))
|
if (moduleName.shouldRun!StyleChecker(analysisConfig))
|
||||||
checks ~= new StyleChecker(args.setSkipTests(
|
checks ~= new StyleChecker(args.setSkipTests(
|
||||||
analysisConfig.style_check == Check.skipTests && !ut));
|
analysisConfig.style_check == Check.skipTests && !ut));
|
||||||
|
|
@ -1345,6 +1341,12 @@ MessageSet analyzeDmd(string fileName, ASTCodegen.Module m, const char[] moduleN
|
||||||
config.redundant_storage_classes == Check.skipTests && !ut
|
config.redundant_storage_classes == Check.skipTests && !ut
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (moduleName.shouldRunDmd!(NumberStyleCheck!ASTCodegen)(config))
|
||||||
|
visitors ~= new NumberStyleCheck!ASTCodegen(
|
||||||
|
fileName,
|
||||||
|
config.number_style_check == Check.skipTests && !ut
|
||||||
|
);
|
||||||
|
|
||||||
foreach (visitor; visitors)
|
foreach (visitor; visitors)
|
||||||
{
|
{
|
||||||
m.accept(visitor);
|
m.accept(visitor);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue