Skip to content

Commit

Permalink
Use DMD in NumberStyleCheck
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladiwostok committed Feb 2, 2024
1 parent 820a5a8 commit f641aec
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 32 deletions.
72 changes: 44 additions & 28 deletions src/dscanner/analysis/numbers.d
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,73 @@

module dscanner.analysis.numbers;

import std.stdio;
import std.regex;
import dparse.ast;
import dparse.lexer;
import dscanner.analysis.base;
import dscanner.analysis.helpers;
import dsymbol.scope_ : Scope;
import dmd.tokens : TOK;
import std.conv;
import std.regex;
import std.stdio;

/**
* Checks for long and hard-to-read number literals
*/
final class NumberStyleCheck : BaseAnalyzer
extern (C++) class NumberStyleCheck(AST) : BaseAnalyzerDmd
{
public:
alias visit = BaseAnalyzer.visit;

alias visit = BaseAnalyzerDmd.visit;
mixin AnalyzerInfo!"number_style_check";

/**
* Constructs the style checker with the given file name.
*/
this(string fileName, const(Scope)* sc, bool skipTests = false)
private enum KEY = "dscanner.style.number_literals";
private enum string MSG = "Use underscores to improve number constant readability.";

private auto badBinaryRegex = ctRegex!(`^0b[01]{9,}`);
private auto badDecimalRegex = ctRegex!(`^\d{5,}`);

extern (D) this(string fileName, bool skipTests = false)
{
super(fileName, sc, skipTests);
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")
&& ((t.text.startsWith("0b") && !t.text.matchFirst(badBinaryRegex)
.empty) || !t.text.matchFirst(badDecimalRegex).empty))
{
addErrorMessage(t.line, t.column, "dscanner.style.number_literals",
"Use underscores to improve number constant readability.");
}
auto bytes = readFile(fileName) ~ '\0';
bytes = bytes[intExpr.loc.fileOffset .. $];

__gshared ErrorSinkNull errorSinkNull;
if (!errorSinkNull)
errorSinkNull = new ErrorSinkNull;

scope lexer = new Lexer(null, cast(char*) bytes, 0, bytes.length, 0, 0,
errorSinkNull, &global.compileEnv);
lexer.nextToken();

auto tokenValue = lexer.token.value;
auto tokenText = to!string(lexer.token.ptr);

if (!isIntegerLiteral(tokenValue))
return;

if (!matchFirst(tokenText, badDecimalRegex).empty || !matchFirst(tokenText, badBinaryRegex).empty)
addErrorMessage(intExpr.loc.linnum, intExpr.loc.charnum, KEY, MSG);
}

private:
auto badBinaryRegex = ctRegex!(`^0b[01]{9,}`);
auto badDecimalRegex = ctRegex!(`^\d{5,}`);
private bool isIntegerLiteral(TOK token)
{
return token >= TOK.int32Literal && token <= TOK.uns128Literal;
}
}

unittest
{
import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
import dscanner.analysis.helpers : assertAnalyzerWarningsDMD;

StaticAnalysisConfig sac = disabledConfig();
sac.number_style_check = Check.enabled;
assertAnalyzerWarnings(q{
assertAnalyzerWarningsDMD(q{
void testNumbers()
{
int a;
Expand Down
10 changes: 6 additions & 4 deletions src/dscanner/analysis/run.d
Original file line number Diff line number Diff line change
Expand Up @@ -492,10 +492,6 @@ MessageSet analyze(string fileName, const Module m, const StaticAnalysisConfig a
checks ~= new MismatchedArgumentCheck(fileName, moduleScope,
analysisConfig.mismatched_args_check == Check.skipTests && !ut);

if (moduleName.shouldRun!NumberStyleCheck(analysisConfig))
checks ~= new NumberStyleCheck(fileName, moduleScope,
analysisConfig.number_style_check == Check.skipTests && !ut);

if (moduleName.shouldRun!StyleChecker(analysisConfig))
checks ~= new StyleChecker(fileName, moduleScope,
analysisConfig.style_check == Check.skipTests && !ut);
Expand Down Expand Up @@ -697,6 +693,12 @@ MessageSet analyzeDmd(string fileName, ASTCodegen.Module m, const char[] moduleN
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)
{
m.accept(visitor);
Expand Down

0 comments on commit f641aec

Please sign in to comment.